From cbd5da1ba1524e1a50376f50d2867482fed10383 Mon Sep 17 00:00:00 2001 From: ottjk Date: Tue, 5 Dec 2023 23:39:46 -0500 Subject: update --- graphviz.py | 3 +- main.py | 170 +++++++++++++++++++++++++++++++--------------------------- prob_plots.py | 27 ++++++++++ 3 files changed, 119 insertions(+), 81 deletions(-) create mode 100644 prob_plots.py diff --git a/graphviz.py b/graphviz.py index 24ee41b..f435038 100644 --- a/graphviz.py +++ b/graphviz.py @@ -5,8 +5,9 @@ COLORS = ['#1E88E5', '#D81B60', '#FFC107', '#004D40'] USE_EDGE_COLORS = False +graph = [(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)] graph = [(0,1),(0,2),(0,3),(0,4),(1,2),(1,3),(2,3),(2,4),(3,4)] -coloring = '0011011011' +coloring = '0001101101' node_count = len(coloring) // 2 node_colors = [COLORS[int(coloring[i*2:i*2+2], 2)] for i in range(node_count)] diff --git a/main.py b/main.py index 5afd1a6..514a52f 100644 --- a/main.py +++ b/main.py @@ -2,83 +2,93 @@ import pennylane as qml from pennylane import numpy as np from rich.progress import track -n_vertices = 5 -n_wires = 2*n_vertices -n_layers = 3 - -graph = [(0,1),(0,2),(0,3),(0,4),(1,2),(1,3),(2,3),(2,4),(3,4)] - -cost_hamiltonian = sum(qml.Hamiltonian([1,1,1], [ - qml.PauliZ(2*edge[0]) @ qml.PauliZ(2*edge[1]), - qml.PauliZ(2*edge[0]+1) @ qml.PauliZ(2*edge[1]+1), - qml.PauliZ(2*edge[0]) @ qml.PauliZ(2*edge[0]+1) @ qml.PauliZ(2*edge[1]) @ qml.PauliZ(2*edge[1]+1) -]) for edge in graph) - -# unitary operator U_B with parameter beta -def U_B(beta): - for wire in range(n_wires): - qml.RX(2 * beta, wires=wire) - -# unitary operator U_C with parameter gamma -def U_C(gamma): - for edge in graph: - wire1 = 2*edge[0] - wire2 = wire1+1 - wire3 = 2*edge[1] - wire4 = wire3+1 - - qml.CNOT(wires=[wire1, wire3]) - qml.RZ(gamma, wires=wire3) - qml.CNOT(wires=[wire1, wire3]) - - qml.CNOT(wires=[wire2, wire4]) - qml.RZ(gamma, wires=wire4) - qml.CNOT(wires=[wire2, wire4]) - - qml.CNOT(wires=[wire1, wire4]) - qml.CNOT(wires=[wire2, wire4]) - qml.CNOT(wires=[wire3, wire4]) - qml.RZ(gamma, wires=wire4) - qml.CNOT(wires=[wire3, wire4]) - qml.CNOT(wires=[wire2, wire4]) - qml.CNOT(wires=[wire1, wire4]) - -def circuit(gammas, betas): - for wire in range(n_wires): - qml.Hadamard(wires=wire) - - for i in range(n_layers): - U_C(gammas[i]) - U_B(betas[i]) - -dev = qml.device("default.qubit", wires=n_wires) - -@qml.qnode(dev) -def cost_function(params): - circuit(params[0], params[1]) - return qml.expval(cost_hamiltonian) - -@qml.qnode(dev) -def probability_circuit(params): - circuit(params[0], params[1]) - return qml.probs() - -def qaoa_color(): - params = np.random.rand(2, n_layers, requires_grad=True) - print(params) - - opt = qml.QNSPSAOptimizer() - - steps = 200 - for i in track(range(steps)): - params, cost = opt.step_and_cost(cost_function, params) - probs = probability_circuit(params) - print("{: .7f}, {:010b}".format(cost, np.argmax(probs))) - - return params - -@qml.qnode(dev) -def h_exp(): - return qml.expval(cost_hamiltonian) - -params = qaoa_color() +def generate_hamiltonian(graph): + cost_hamiltonian = sum(qml.Hamiltonian([1/4,1/4,1/4], [ + qml.PauliZ(2*edge[0]) @ qml.PauliZ(2*edge[1]), + qml.PauliZ(2*edge[0]+1) @ qml.PauliZ(2*edge[1]+1), + qml.PauliZ(2*edge[0]) @ qml.PauliZ(2*edge[0]+1) @ qml.PauliZ(2*edge[1]) @ qml.PauliZ(2*edge[1]+1) + ]) for edge in graph) + return cost_hamiltonian + +class QC: + def __init__(self, graph, n_vertices, n_layers): + self.graph = graph + self.n_vertices = n_vertices + self.n_wires = 2*n_vertices + self.n_layers = n_layers + self.hamiltonian = generate_hamiltonian(graph) + self.dev = qml.device("default.qubit", wires=self.n_wires) + + # unitary operator U_B with parameter beta + def U_B(self, beta): + for wire in range(self.n_wires): + qml.RX(beta, wires=wire) + + # unitary operator U_C with parameter gamma + def U_C(self, gamma): + for edge in self.graph: + wire1 = 2*edge[0] + wire2 = wire1+1 + wire3 = 2*edge[1] + wire4 = wire3+1 + + qml.CNOT(wires=[wire1, wire3]) + qml.RZ(gamma/4, wires=wire3) + qml.CNOT(wires=[wire1, wire3]) + + qml.CNOT(wires=[wire2, wire4]) + qml.RZ(gamma/4, wires=wire4) + qml.CNOT(wires=[wire2, wire4]) + + qml.CNOT(wires=[wire1, wire4]) + qml.CNOT(wires=[wire2, wire4]) + qml.CNOT(wires=[wire3, wire4]) + qml.RZ(gamma/4, wires=wire4) + qml.CNOT(wires=[wire3, wire4]) + qml.CNOT(wires=[wire2, wire4]) + qml.CNOT(wires=[wire1, wire4]) + + def circuit(self, gammas, betas): + for wire in range(self.n_wires): + qml.PauliX(wire) + qml.Hadamard(wires=wire) + + for i in range(self.n_layers): + self.U_C(gammas[i]) + self.U_B(betas[i]) + + def cost_function(self): + @qml.qnode(self.dev) + def _cost_function(params): + self.circuit(params[0], params[1]) + return qml.expval(self.hamiltonian) + return _cost_function + + def probability_circuit(self, params): + @qml.qnode(self.dev) + def _probability_circuit(params): + self.circuit(params[0], params[1]) + return qml.probs() + return _probability_circuit(params) + + def h_exp(self): + @qml.qnode(self.dev) + def _h_exp(): + return qml.expval(self.hamiltonian) + return _h_exp() + + def qaoa_color(self): + gammas = np.linspace(0, 1, num=self.n_layers) + betas = np.linspace(1, 0, num=self.n_layers) + params = np.array([gammas,betas]) + + opt = qml.QNSPSAOptimizer() + + steps = 10 + for i in track(range(steps)): + params, cost = opt.step_and_cost(self.cost_function(), params) + probs = self.probability_circuit(params) + + print(f"{cost: .7f}, {np.argmax(probs):0{self.n_wires}b}") + + return params diff --git a/prob_plots.py b/prob_plots.py new file mode 100644 index 0000000..741eaec --- /dev/null +++ b/prob_plots.py @@ -0,0 +1,27 @@ +from main import * + +import matplotlib +matplotlib.use('module://matplotlib-backend-sixel') +import matplotlib.pyplot as plt + +n_layers = 4 + +def get_probs(qc): + print(f'Finding probabilities for {qc.n_vertices}-vertex graph') + params = qc.qaoa_color() + probs = qc.probability_circuit(params) + print(f"{len(probs[probs > max(probs) * 3/4])}") + + plot = plt.bar(range(2 ** qc.n_wires), probs) + plt.savefig(f'figures/{qc.n_vertices}-node-probs.pdf') + +n_vertices = 5 +graph = [(0,1),(0,2),(0,3),(0,4),(1,2),(1,3),(2,3),(2,4),(3,4)] +qc_5 = QC(graph, n_vertices, n_layers) + +n_vertices = 6 +graph = [(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)] +qc_6 = QC(graph, n_vertices, n_layers) + +# get_probs(qc_5) +get_probs(qc_6) -- cgit v1.3