Paddle_QAOA.py 6.5 KB
Newer Older
Q
Quleaf 已提交
1
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
Q
Quleaf 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Paddle_QAOA: To learn more about the functions and properties of this application,
you could check the corresponding Jupyter notebook under the Tutorial folder.
"""

Q
Quleaf 已提交
20 21 22 23 24 25 26
import paddle
from paddle_quantum.circuit import UAnsatz
from paddle_quantum.utils import pauli_str_to_matrix
from paddle_quantum.QAOA.QAOA_Prefunc import Generate_H_D, Generate_default_graph
from paddle_quantum.QAOA.QAOA_Prefunc import Draw_benchmark
from paddle_quantum.QAOA.QAOA_Prefunc import Draw_cut_graph, Draw_original_graph

Q
Quleaf 已提交
27 28 29 30
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx

Q
Quleaf 已提交
31 32

# Random seed for optimizer
Q
Quleaf 已提交
33
SEED = 1024
Q
Quleaf 已提交
34 35 36 37 38 39 40

__all__ = [
    "circuit_QAOA",
    "Net",
    "Paddle_QAOA",
]

Q
Quleaf 已提交
41
def circuit_QAOA(E, V, n, p, gamma, beta):
Q
Quleaf 已提交
42 43
    """
    This function constructs the parameterized QAOA circuit which is composed of P layers of two blocks:
Q
Quleaf 已提交
44 45 46
    one block is based on the problem Hamiltonian H which encodes the classical problem,
    and the other is constructed from the driving Hamiltonian describing the rotation around Pauli X
    acting on each qubit. It outputs the final state of the QAOA circuit.
Q
Quleaf 已提交
47
    Args:
Q
Quleaf 已提交
48 49 50 51 52 53
        E: edges of the graph
        V: vertices of the graph
        n: number of qubits in th QAOA circuit
        p: number of layers of two blocks in the QAOA circuit
        gamma: parameter to be optimized in the QAOA circuit, parameter for the first block
        beta: parameter to be optimized in the QAOA circui, parameter for the second block
Q
Quleaf 已提交
54
    Returns:
Q
Quleaf 已提交
55
        the QAOA circuit
Q
Quleaf 已提交
56
    """
Q
Quleaf 已提交
57
    cir = UAnsatz(n)
Q
Quleaf 已提交
58
    cir.superposition_layer()
Q
Quleaf 已提交
59 60 61 62 63 64 65
    for layer in range(p):
        for (u, v) in E:
            cir.cnot([u, v])
            cir.rz(gamma[layer], v)
            cir.cnot([u, v])
        for v in V:
            cir.rx(beta[layer], v)
Q
Quleaf 已提交
66
    return cir
Q
Quleaf 已提交
67

Q
Quleaf 已提交
68
class Net(paddle.nn.Layer):
Q
Quleaf 已提交
69 70 71 72 73
    """
    It constructs the net for QAOA which combines the  QAOA circuit with the classical optimizer which sets rules
    to update parameters described by theta introduced in the QAOA circuit.
    """
    def __init__(
Q
Quleaf 已提交
74 75 76
        self,
        p,
        dtype="float64",
Q
Quleaf 已提交
77
    ):
Q
Quleaf 已提交
78 79
        super(Net, self).__init__()

Q
Quleaf 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
        self.p = p
        self.gamma = self.create_parameter(shape = [self.p], 
                                           default_initializer = paddle.nn.initializer.Uniform(
                                           low = 0.0, 
                                           high = 2 * np.pi
                                           ),
                                           dtype = dtype, 
                                           is_bias = False)
        self.beta = self.create_parameter(shape = [self.p], 
                                          default_initializer = paddle.nn.initializer.Uniform(
                                          low = 0.0, 
                                          high = 2 * np.pi
                                          ),
                                          dtype = dtype, is_bias = False)


    def forward(self, n, E, V, H_D_list):
        cir = circuit_QAOA(E, V, n, self.p, self.gamma, self.beta)
Q
Quleaf 已提交
98
        cir.run_state_vector()
Q
Quleaf 已提交
99
        loss = -cir.expecval(H_D_list)
Q
Quleaf 已提交
100
        return loss, cir
Q
Quleaf 已提交
101

Q
Quleaf 已提交
102
def Paddle_QAOA(n, p, E, V, H_D_list, ITR, LR):
Q
Quleaf 已提交
103 104 105
    """
    This is the core function to run QAOA.
     Args:
Q
Quleaf 已提交
106 107 108 109
         n: number of qubits (default value N=4)
         E: edges of the graph
         V: vertices of the graph
         p: number of layers of blocks in the QAOA circuit (default value p=4)
Q
Quleaf 已提交
110 111 112
         ITR: number of iteration steps for QAOA (default value ITR=120)
         LR: learning rate for the gradient-based optimization method (default value LR=0.1)
     Returns:
Q
Quleaf 已提交
113
         the optimized QAOA circuit
Q
Quleaf 已提交
114 115
         summary_iter
         summary_loss
Q
Quleaf 已提交
116
    """
Q
Quleaf 已提交
117
    net = Net(p)
Q
Quleaf 已提交
118 119 120 121
    opt = paddle.optimizer.Adam(learning_rate=LR, parameters=net.parameters())

    summary_iter, summary_loss = [], []
    for itr in range(1, ITR + 1):
Q
Quleaf 已提交
122
        loss, cir = net(n, E, V, H_D_list)
Q
Quleaf 已提交
123 124 125 126 127 128 129
        loss.backward()
        opt.minimize(loss)
        opt.clear_grad()
        if itr % 10 == 0:
            print("iter:", itr, "  loss:", "%.4f" % loss.numpy())
        summary_loss.append(loss[0][0].numpy())
        summary_iter.append(itr)
Q
Quleaf 已提交
130

Q
Quleaf 已提交
131 132 133 134
    gamma_opt = net.gamma.numpy()
    print("优化后的参数 gamma:\n", gamma_opt)
    beta_opt = net.beta.numpy()
    print("优化后的参数 beta:\n", beta_opt)
Q
Quleaf 已提交
135

Q
Quleaf 已提交
136
    return cir, summary_iter, summary_loss
Q
Quleaf 已提交
137

Q
Quleaf 已提交
138
def main(n = 4, E = None):
Q
Quleaf 已提交
139
    paddle.seed(SEED)
Q
Quleaf 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    
    p = 4 # number of layers in the circuit  
    ITR = 120  #number of iterations
    LR = 0.1    #learning rate
    
    if E is None:
        G, V, E = Generate_default_graph(n)
    else:
        G = nx.Graph()
        V = range(n)
        G.add_nodes_from(V)
        G.add_edges_from(E)
    
    Draw_original_graph(G)
    
    #construct the Hamiltonia
    H_D_list, H_D_matrix = Generate_H_D(E, n)
    H_D_diag = np.diag(H_D_matrix).real
    H_max = np.max(H_D_diag)
    H_min = -H_max

    print(H_D_diag)
    print('H_max:', H_max, '  H_min:', H_min)   

    cir, summary_iter, summary_loss = Paddle_QAOA(n, p, E, V, H_D_list, ITR, LR)
    
    H_min = np.ones([len(summary_iter)]) * H_min
    Draw_benchmark(summary_iter, summary_loss, H_min)
    
    prob_measure = cir.measure(plot=True)
    cut_bitstring = max(prob_measure, key=prob_measure.get)
    print("找到的割的比特串形式:", cut_bitstring)

    Draw_cut_graph(V, E, G, cut_bitstring)
Q
Quleaf 已提交
174 175

if __name__ == "__main__":
Q
Quleaf 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    n = int(input("Please input the number of vertices: "))
    user_input_edge_flag = int(input("Please choose if you want to input edges yourself (0 for yes, 1 for no): "))
    if user_input_edge_flag == 1:
        main(n)
    else:
        E = []
        prompt = "Please input tuples indicating edges (e.g., (0, 1)), input 'z' if finished: "
        while True:
            edge = input(prompt)
            if edge == 'z':
                main(n, E)
                break
            else:
                edge = eval(edge)
                E.append(edge)