In meinem ersten Artikel habe ich Ich habe versucht, TSP mit QAOA zu lösen veröffentlicht. Hierbei wurde jedoch eine sogenannte modularisierte Version von qiskit aqua verwendet, was möglich ist, ohne dass die Schaltung selbst entworfen werden muss. Dieses Mal möchte ich QAOA ohne Qiskit Aqua verwenden. Verwenden Sie zuerst den maximalen Schnitt als ersten Schritt. Um ehrlich zu sein, denke ich, dass andere Probleme nur durch Ändern des Hamilton-Operators gelöst werden können. Ich hoffe, dass dies eine Referenz für diejenigen ist, die Quantenprogrammierung mit Qiskit durchführen. Es gibt mehrere Websites, die die Quantenprogrammierung auf Japanisch erklären, aber da alle unterschiedliche Quantenprogrammiersprachen verwenden, halte ich meinen in qiskit geschriebenen Artikel auch für sinnvoll.
Auch in diesem Artikel möchte ich den Code von Qiskit erläutern, vorausgesetzt, dass die Erklärung von QAOA selbst anderen Personen überlassen bleibt.
Referenz: Quantum Native Dojo
code
Zunächst der gesamte 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:
#Anfangswerteinstellung
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()
#Erstellen einer Kantenliste aus der Gewichtsmatrix
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()
Ich werde nur die Funktionen aufgreifen und erklären, die mich interessieren.
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>
Hier wird das zur Berechnung erforderliche C (Z) erstellt. Zu diesem Zeitpunkt ist es notwendig, das Tensorprodukt zu berechnen, es kann jedoch mit dem Tensorprodukt von qiskit.aqua.utils berechnet werden.
Berechnung des erwarteten Wertes mit qiskit
python
results = execute(qc, backend, shots=NUM_SHOTS, seed_simulator=seed).result()
counts = results.get_counts(qc)
expectation = average_data(counts, self.observable())
Sie können es nach der Methode von tun.
Das Ausführungsergebnis ist wie folgt.
{'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}
Größere Werte, 0101 und 1010, können als Lösungen abgerufen werden.
Recommended Posts