aboutsummaryrefslogtreecommitdiff
path: root/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'main.py')
-rw-r--r--main.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..18d3398
--- /dev/null
+++ b/main.py
@@ -0,0 +1,126 @@
+import pennylane as qml
+from pennylane import numpy as np
+
+n_vertices = 5
+n_wires = 2*n_vertices
+
+graph = [(0,1),(0,2),(0,3),(0,4),(1,2),(1,3),(2,3),(2,4),(3,4)]
+# graph = [(0,2)]
+
+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 bitstring_to_int(bit_string_sample):
+ bit_string = "".join(str(bs) for bs in bit_string_sample)
+ return int(bit_string, base=2)
+
+dev = qml.device("default.qubit", wires=n_wires, shots=1)
+
+@qml.qnode(dev)
+def circuit(gammas, betas, sample=False, n_layers=1):
+ # apply Hadamards to get the n qubit |+> state
+ for wire in range(n_wires):
+ qml.Hadamard(wires=wire)
+ # p instances of unitary operators
+ for i in range(n_layers):
+ U_C(gammas[i])
+ U_B(betas[i])
+ if sample:
+ # measurement phase
+ return qml.sample()
+
+ return qml.expval(cost_hamiltonian)
+
+def qaoa_maxcut(n_layers=1):
+ print("\np={:d}".format(n_layers))
+
+ # initialize the parameters near zero
+ init_gammas = 0.01 * np.random.rand(n_layers, requires_grad=True)
+ init_betas = 0.01 * np.random.rand(n_layers, requires_grad=True)
+
+ # initialize optimizer: Adagrad works well empirically
+ opt = qml.QNSPSAOptimizer()
+
+ # optimize parameters in objective
+ gammas = init_gammas
+ betas = init_betas
+ steps = 200
+ for i in range(steps):
+ params, cost = opt.step_and_cost(circuit, gammas, betas, n_layers=n_layers)
+ gammas = params[0]
+ betas = params[1]
+ if (i + 1) % 5 == 0:
+ print("Objective after step {:5d}: {: .7f}".format(i + 1, cost))
+
+ # sample measured bitstrings 100 times
+ bit_strings = []
+ n_samples = 1000
+ for i in range(0, n_samples):
+ bit_strings.append(bitstring_to_int(circuit(gammas, betas, sample=True, n_layers=n_layers)))
+
+ # print optimal parameters and most frequently sampled bitstring
+ counts = np.bincount(np.array(bit_strings))
+ most_freq_bit_string = np.argmax(counts)
+ print("Optimized (gamma, beta) vectors:\n{} {}".format(gammas, betas))
+ print("Most frequently sampled bit string is: {:010b}".format(most_freq_bit_string))
+
+ return circuit(gammas, betas, n_layers=n_layers), bit_strings
+
+bitstrings1 = qaoa_maxcut(n_layers=2)[1]
+
+# import matplotlib.pyplot as plt
+# matplotlib.use('module://matplotlib-backend-sixel')
+#
+# xticks = range(0, 16)
+# xtick_labels = list(map(lambda x: format(x, "04b"), xticks))
+# bins = np.arange(0, 17) - 0.5
+#
+# fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))
+# plt.subplot(1, 2, 1)
+# plt.title("n_layers=1")
+# plt.xlabel("bitstrings")
+# plt.ylabel("freq.")
+# plt.xticks(xticks, xtick_labels, rotation="vertical")
+# plt.hist(bitstrings1, bins=bins)
+# plt.subplot(1, 2, 2)
+# plt.title("n_layers=2")
+# plt.xlabel("bitstrings")
+# plt.ylabel("freq.")
+# plt.xticks(xticks, xtick_labels, rotation="vertical")
+# plt.hist(bitstrings2, bins=bins)
+# plt.tight_layout()
+# plt.show()