Dans mon premier article, j'ai posté j'ai essayé de résoudre TSP avec QAOA. Cependant, cela a utilisé une version dite modulaire de qiskit aqua, ce qui est possible sans avoir à concevoir le circuit vous-même. Donc cette fois, j'aimerais utiliser QAOA sans utiliser qiskit aqua. Tout d'abord, utilisez max cut comme première étape. Pour être honnête, je pense que d'autres problèmes peuvent être résolus simplement en changeant le hamiltonien, donc j'espère que ce sera une référence pour ceux qui font de la programmation quantique avec qiskit. Il existe plusieurs sites qui expliquent la programmation quantique en japonais, mais comme ils utilisent tous des langages de programmation quantique différents, je pense que mon article écrit en qiskit est également significatif.
Dans cet article également, je voudrais expliquer le code de qiskit, en supposant que l'explication de QAOA elle-même sera laissée à d'autres personnes.
Référence: Quantum Native Dojo
code
Tout d'abord, tout le code
python
# coding: utf-8
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute
from qiskit.aqua.utils import tensorproduct
from qiskit import BasicAer
from qiskit.quantum_info.analysis import average_data
from scipy.optimize import minimize
import numpy as np
import time
def classical_minimize(cost_func, initial_params, options, method='powell'):
print('classical minimize is starting now... ')
start_time = time.time()
result = minimize(cost_func, initial_params, options=options, method=method)
print('running time: {}'.format(time.time() - start_time))
print('opt_cost: {}'.format(result.fun))
print('opt_params: {}'.format(result.x))
return result.x
class MAXCUT:
#Réglage de la valeur initiale
def __init__(self, n_qubits, weight_matrix, p=1, num_steps=1):
self.n_qubits = n_qubits
self.weight_matrix = weight_matrix
self.P = p
self.num_steps = num_steps
self.edge_list = []
self._make_edge_list()
#Création d'une liste d'arêtes à partir d'une matrice de poids
def _make_edge_list(self):
for i in range(self.weight_matrix.shape[0]):
for j in range(i+1, self.weight_matrix.shape[1]):
if self.weight_matrix[i][j] != 0:
self.edge_list.append([i, j])
'------------------------------------------------------------------------------------------------------------------'
def Zi_Zj(self, q1, q2):
I_mat = np.array([[1, 0], [0, 1]])
Z_mat = np.array([[1, 0], [0, -1]])
if q1 == 0 or q2 == 0:
tensor = Z_mat
else:
tensor = I_mat
for i in range(1, self.n_qubits):
if i == q1 or i == q2:
tensor = tensorproduct(tensor, Z_mat)
else:
tensor = tensorproduct(tensor, I_mat)
return tensor
def observable(self):
obs = np.zeros((2**self.n_qubits, 2**self.n_qubits))
for a_edge in self.edge_list:
q1, q2 = a_edge
obs = obs + 0.5 * self.Zi_Zj(q1, q2)
return obs
'------------------------------------------------------------------------------------------------------------------'
# U_C(gamma)
def add_U_C(self, qc, gamma):
for a_edge in self.edge_list:
q1, q2 = a_edge
qc.cx(q1, q2)
qc.rz(-2**gamma, q2)
qc.cx(q1, q2)
return qc
# U_X(beta)
def add_U_X(self, qc, beta):
for i in range(self.n_qubits):
qc.rx(-2*beta, i)
return qc
def QAOA_output_onelayer(self, params, run=False):
beta, gamma = params
qr = QuantumRegister(self.n_qubits)
cr = ClassicalRegister(self.n_qubits)
qc = QuantumCircuit(qr, cr)
qc.h(range(self.n_qubits))
qc = self.add_U_C(qc, gamma)
qc = self.add_U_X(qc, beta)
qc.measure(range(self.n_qubits), range(self.n_qubits))
NUM_SHOTS = 10000
seed = 1234
backend = BasicAer.get_backend('qasm_simulator')
results = execute(qc, backend, shots=NUM_SHOTS, seed_simulator=seed).result()
counts = results.get_counts(qc)
expectation = average_data(counts, self.observable())
return expectation
'------------------------------------------------------------------------------------------------------------------'
def minimize(self):
initial_params = np.array([0.1, 0.1])
opt_params = classical_minimize(self.QAOA_output_onelayer, initial_params,
options={'maxiter':500}, method='powell')
return opt_params
def run(self):
opt_params = self.minimize()
beta_opt, gamma_opt = opt_params
qr = QuantumRegister(self.n_qubits)
cr = ClassicalRegister(self.n_qubits)
qc = QuantumCircuit(qr, cr)
qc.h(range(self.n_qubits))
qc = self.add_U_C(qc, gamma_opt)
qc = self.add_U_X(qc, beta_opt)
qc.measure(range(self.n_qubits), range(self.n_qubits))
NUM_SHOTS = 10000
seed = 1234
backend = BasicAer.get_backend('qasm_simulator')
results = execute(qc, backend, shots=NUM_SHOTS, seed_simulator=seed).result()
print(results.get_counts())
if __name__ == '__main__':
weight_matrix = np.array([[0, 1, 0, 1],
[1, 0, 1, 0],
[0, 1, 0, 1],
[1, 0, 1, 0]])
cut = MAXCUT(4, weight_matrix, p=1)
cut.run()
Je vais reprendre et expliquer uniquement les fonctions qui m'intéressent.
python
def Zi_Zj(self, q1, q2):
I_mat = np.array([[1, 0], [0, 1]])
Z_mat = np.array([[1, 0], [0, -1]])
if q1 == 0 or q2 == 0:
tensor = Z_mat
else:
tensor = I_mat
for i in range(1, self.n_qubits):
if i == q1 or i == q2:
tensor = tensorproduct(tensor, Z_mat)
else:
tensor = tensorproduct(tensor, I_mat)
return tensor
def observable(self):
obs = np.zeros((2**self.n_qubits, 2**self.n_qubits))
for a_edge in self.edge_list:
q1, q2 = a_edge
obs = obs + 0.5 * self.Zi_Zj(q1, q2)
return obs
python
<\beta,\gamma|C(Z)|\beta,\gamma>
Le C (Z) requis pour calculer est créé ici. À ce stade, il est nécessaire de calculer le produit tensoriel, mais il peut être calculé avec le produit tensoriel de qiskit.aqua.utils.
Pour calculer la valeur attendue avec qiskit
python
results = execute(qc, backend, shots=NUM_SHOTS, seed_simulator=seed).result()
counts = results.get_counts(qc)
expectation = average_data(counts, self.observable())
Vous pouvez le faire par la méthode de.
Le résultat de l'exécution est le suivant.
{'0101': 2578, '1110': 171, '1101': 146, '1001': 793, '1111': 141, '0011': 815, '0111': 122, '0010': 159, '0000': 161, '0100': 170, '0001': 151, '0110': 802, '1000': 160, '1100': 811, '1010': 2682, '1011': 138}
Des valeurs plus élevées, 0101 et 1010, peuvent être récupérées sous forme de solutions.
Recommended Posts