diff --git a/src/qututor/bernstein/bernstein_vazirani.qu b/src/quingo/bernstein_vazirani.qu similarity index 78% rename from src/qututor/bernstein/bernstein_vazirani.qu rename to src/quingo/bernstein_vazirani.qu index 2693489abc23b1a93ceba02d1ad0c8a94e8e9ae2..0fd2c5b95fd23f7df2f98d6383c9c63f2f219533 100644 --- a/src/qututor/bernstein/bernstein_vazirani.qu +++ b/src/quingo/bernstein_vazirani.qu @@ -1,5 +1,6 @@ -import std_qcis +import std_ops +import std_utils operation oracle_with_bits(x: qubit[], y: qubit, secret: bool[]) : unit { for (int i = 0; i < x.length; i += 1) { @@ -36,11 +37,17 @@ operation bernstein_vazirani() : bool[] { using (x: qubit[secret_length], y: qubit){ X(y); - apply_all(H, x); H(y); + for (int i = 0; i < x.length; i += 1) { + H(x[i]); + } + + H(y); oracle(x, y); - apply_all(H, x); + for (int i = 0; i < x.length; i += 1) { + H(x[i]); + } for (int i = 0; i < x.length; i += 1) { x_bits[i] = measure(x[i]); diff --git a/src/quingo/ctrl_multiplier.qu b/src/quingo/ctrl_multiplier.qu index e674cfc1baa0a63c2196679931235a9646e4b901..697343430689235d6d519ed9e895d16bae11d925 100644 --- a/src/quingo/ctrl_multiplier.qu +++ b/src/quingo/ctrl_multiplier.qu @@ -55,9 +55,41 @@ operation test_c_mult_N(c: int, x: int, b: int, a: int, N: int, width: int) : bo return res; } -// operation c_Ua(c: qubit, x: qubit[], b: qubit[], a: int[], -// N: int[]) : unit { -// c_mult_N(c, x, b, a, N); -// // TODO: continue from here. -// return; -// } +operation c_Ua(c: qubit, x: qubit[], b: qubit[], anc: qubit, + a: int[], ai: int[], N: int[]) : unit { + c_mult_N(c, x, b, anc, a, N); + for (int i = 0; i < x.length; i += 1) { + swap(x[i], b[i]); + } + c_mult_N(c, x, b, ai, N); + return; +} + +operation test_c_Ua(c: int, x: int, a: int, a_inv: int, N: int, width: int) : bool[] { + + int[] a_bits = get_bin(a, width + 1); + int[] ai_bits = get_bin(a_inv, width + 1); + int[] N_bits = get_bin(N, width + 1); + + // control (1), qs_x (width + 1), qs_b (width + 1), ancilla(1) + int num_qubits = 1 + width + 1 + width + 1 + 1; + bool[num_qubits] res; + + using (c_qubit: qubit, qs_x: qubit[width + 1], qs_b: qubit[width + 1], anc: qubit) { + if (c == 1) { X(c_qubit); } + load_integer(x, qs_x); + + c_Ua(c_qubit, qs_x, qs_b, anc, a_bits, ai_bits, N_bits); + + res[0] = measure(c_qubit); + for (int i = 0; i < width + 1; i += 1) { + res[i + 1] = measure(qs_x[i]); + } + for (int i = 0; i < width + 1; i += 1) { + res[i + width + 2] = measure(qs_b[i]); + } + res[num_qubits - 1] = measure(anc); + } + + return res; +} diff --git a/src/quingo/modular_adder.qu b/src/quingo/modular_adder.qu index 08275a54807d7bda8d6842a01473097c24a80382..eb577800a25f8ef85dd101615177841ee4716ee3 100644 --- a/src/quingo/modular_adder.qu +++ b/src/quingo/modular_adder.qu @@ -5,7 +5,8 @@ import utils /// 2-controlled modular adder: |b> -> | (a + b) mod N> /// - given integer `a`, `N`, and number `b` in state |b>, -/// - return | (a + b) mod N> +/// - return | (a + b) mod N> if both control qubits (c0, c1) are 1, +/// - return | b> otherwise. /// /// parameters: /// - c0, c1: the two control qubits diff --git a/src/qututor/bernstein/std_qcis.qu b/src/quingo/std_utils.qu similarity index 30% rename from src/qututor/bernstein/std_qcis.qu rename to src/quingo/std_utils.qu index b4b81ad19198075bd9ebcc2e9142fb9d11327e0c..fc392b416ad23348ff0abbf22988ffb490242126 100644 --- a/src/qututor/bernstein/std_qcis.qu +++ b/src/quingo/std_utils.qu @@ -1,77 +1,39 @@ -// measurement -opaque MEASURE (qs: qubit[]): bool[]; // measure a list of qubits. -opaque measure (q: qubit): bool; // measure a list of qubits. -// single-qubit gates -opaque X (q:qubit): unit; // Rx( pi ) -opaque X2P (q:qubit): unit; // Rx( pi/2) -opaque X2M (q:qubit): unit; // Rx(-pi/2) - -opaque Y (q:qubit): unit; // Ry( pi ) -opaque Y2P (q:qubit): unit; // Ry( pi/2) -opaque Y2M (q:qubit): unit; // Ry(-pi/2) - -opaque RZ (q:qubit, angle:double): unit; // Rz(angle) -opaque Z (q:qubit): unit; // Rz( pi ) -opaque Z2P (q:qubit): unit; // Rz( pi/2) -opaque Z2M (q:qubit): unit; // Rz(-pi/2) -opaque Z4P (q:qubit): unit; // Rz( pi/4) -opaque Z4M (q:qubit): unit; // Rz(-pi/4) -opaque H (q:qubit): unit; // Hadamard - -opaque CNOT(c: qubit, t: qubit): unit; - -// This operation performs the following rotation on the state: -// - the angle between the positive x-axis and the rotation axis is `azimuth`; -// - the rotation angle is `angle`. -opaque XYARB (q:qubit, azimuth:double, angle:double): unit; - -// two-qubit gates -opaque CZ (control_qubit:qubit, target_qubit:qubit ): unit; // CPhase gate - - - - -// operation CNOT(c: qubit, t: qubit): unit -// { -// H(t); -// CZ(c, t); -// H(t); -// } - -operation init(q: qubit) : unit { - bool a = measure(q); - if (a) { - X(q); - } -} - -operation init_all(target: qubit[]) : unit { - apply_all(init, target); -} - -operation apply_all(gate: qubit -> unit, qubits: qubit[]) : unit { - int i; - i = 0; - int num_qubits; - num_qubits = qubits.length; - while (i < num_qubits) { - gate(qubits[i]); - i = i + 1; - } -} - - -operation meas_all(qubits: qubit[]) : bool[] { - int num_qubits; - num_qubits = qubits.length; - - bool[num_qubits] res; - int i; - i = 0; - while (i < num_qubits) { - res[i] = measure(qubits[i]); - i = i + 1; - } - - return res; -} +import std_ops + +operation init(q: qubit) : unit { + bool a = measure(q); + if (a) { + X(q); + } +} + +operation init_all(target: qubit[]) : unit { + apply_all(init, target); +} + +operation apply_all(gate: qubit -> unit, qubits: qubit[]) : unit { + int i; + i = 0; + int num_qubits; + num_qubits = qubits.length; + while (i < num_qubits) { + gate(qubits[i]); + i = i + 1; + } +} + + +operation meas_all(qubits: qubit[]) : bool[] { + int num_qubits; + num_qubits = qubits.length; + + bool[num_qubits] res; + int i; + i = 0; + while (i < num_qubits) { + res[i] = measure(qubits[i]); + i = i + 1; + } + + return res; +} diff --git a/src/qututor/H2_VQE/host.py b/src/qututor/H2_VQE/host.py index 5726f82fd36935b12bbf3eaae8483cdf49387a25..639d67c6209fb2e54f2b7df17a797535932958a9 100644 --- a/src/qututor/H2_VQE/host.py +++ b/src/qututor/H2_VQE/host.py @@ -1,37 +1,33 @@ import logging -from quingo import quingo_interface as qi +from quingo import * from pathlib import Path import matplotlib.pyplot as plt + # from scipy.optimize import minimize_scalar, minimize from scipy.optimize import minimize_scalar from numpy import * import numpy as np -qi.set_compiler('mlir') -qi.config_execution("state_vector") - -if qi.connect_backend('pyqcisim_quantumsim') is False: - exit(-1) - qu_file = Path(__file__).parent / "kernel.qu" +cfg_file = Path(__file__).parent / "std_qcis.qfg" bond_h_decompose = [ - [0.20, 2.8489, 0.5678, -1.4508, 0.6799, 0.0791, 0.0791], - [0.25, 2.1868, 0.5449, -1.2870, 0.6719, 0.0798, 0.0798], - [0.30, 1.7252, 0.5215, -1.1458, 0.6631, 0.0806, 0.0806], - [0.35, 1.3827, 0.4982, -1.0226, 0.6537, 0.0815, 0.0815], - [0.40, 1.1182, 0.4754, -0.9145, 0.6438, 0.0825, 0.0825], - [0.45, 0.9083, 0.4534, -0.8194, 0.6336, 0.0835, 0.0835], - [0.50, 0.7381, 0.4325, -0.7355, 0.6233, 0.0846, 0.0846], - [0.55, 0.5979, 0.4125, -0.6612, 0.6129, 0.0858, 0.0858], - [0.60, 0.4808, 0.3937, -0.5950, 0.6025, 0.0870, 0.0870], - [0.65, 0.3819, 0.3760, -0.5358, 0.5921, 0.0883, 0.0883], - [0.70, 0.2976, 0.3593, -0.4826, 0.5818, 0.0896, 0.0896], - [0.75, 0.2252, 0.3435, -0.4347, 0.5716, 0.0910, 0.0910], - [0.80, 0.1626, 0.3288, -0.3915, 0.5616, 0.0925, 0.0925], - [0.85, 0.1083, 0.3149, -0.3523, 0.5518, 0.0939, 0.0939], - [0.90, 0.0609, 0.3018, -0.3168, 0.5421, 0.0954, 0.0954], - [0.95, 0.0193, 0.2895, -0.2845, 0.5327, 0.0970, 0.0970], + [0.20, 2.8489, 0.5678, -1.4508, 0.6799, 0.0791, 0.0791], + [0.25, 2.1868, 0.5449, -1.2870, 0.6719, 0.0798, 0.0798], + [0.30, 1.7252, 0.5215, -1.1458, 0.6631, 0.0806, 0.0806], + [0.35, 1.3827, 0.4982, -1.0226, 0.6537, 0.0815, 0.0815], + [0.40, 1.1182, 0.4754, -0.9145, 0.6438, 0.0825, 0.0825], + [0.45, 0.9083, 0.4534, -0.8194, 0.6336, 0.0835, 0.0835], + [0.50, 0.7381, 0.4325, -0.7355, 0.6233, 0.0846, 0.0846], + [0.55, 0.5979, 0.4125, -0.6612, 0.6129, 0.0858, 0.0858], + [0.60, 0.4808, 0.3937, -0.5950, 0.6025, 0.0870, 0.0870], + [0.65, 0.3819, 0.3760, -0.5358, 0.5921, 0.0883, 0.0883], + [0.70, 0.2976, 0.3593, -0.4826, 0.5818, 0.0896, 0.0896], + [0.75, 0.2252, 0.3435, -0.4347, 0.5716, 0.0910, 0.0910], + [0.80, 0.1626, 0.3288, -0.3915, 0.5616, 0.0925, 0.0925], + [0.85, 0.1083, 0.3149, -0.3523, 0.5518, 0.0939, 0.0939], + [0.90, 0.0609, 0.3018, -0.3168, 0.5421, 0.0954, 0.0954], + [0.95, 0.0193, 0.2895, -0.2845, 0.5327, 0.0970, 0.0970], [1.00, -0.0172, 0.2779, -0.2550, 0.5235, 0.0986, 0.0986], [1.05, -0.0493, 0.2669, -0.2282, 0.5146, 0.1002, 0.1002], [1.10, -0.0778, 0.2565, -0.2036, 0.5059, 0.1018, 0.1018], @@ -50,26 +46,27 @@ bond_h_decompose = [ [1.75, -0.2573, 0.1615, -0.0166, 0.4148, 0.1226, 0.1226], [1.80, -0.2632, 0.1565, -0.0088, 0.4094, 0.1241, 0.1241], [1.85, -0.2684, 0.1517, -0.0015, 0.4042, 0.1256, 0.1256], - [1.90, -0.2731, 0.1472, 0.0052, 0.3992, 0.1270, 0.1270], - [1.95, -0.2774, 0.1430, 0.0114, 0.3944, 0.1284, 0.1284], - [2.00, -0.2812, 0.1390, 0.0171, 0.3898, 0.1297, 0.1297], - [2.05, -0.2847, 0.1352, 0.0223, 0.3853, 0.1310, 0.1310], - [2.10, -0.2879, 0.1316, 0.0272, 0.3811, 0.1323, 0.1323], - [2.15, -0.2908, 0.1282, 0.0317, 0.3769, 0.1335, 0.1335], - [2.20, -0.2934, 0.1251, 0.0359, 0.3730, 0.1347, 0.1347], - [2.25, -0.2958, 0.1221, 0.0397, 0.3692, 0.1359, 0.1359], - [2.30, -0.2980, 0.1193, 0.0432, 0.3655, 0.1370, 0.1370], - [2.35, -0.3000, 0.1167, 0.0465, 0.3620, 0.1381, 0.1381], - [2.40, -0.3018, 0.1142, 0.0495, 0.3586, 0.1392, 0.1392], - [2.45, -0.3035, 0.1119, 0.0523, 0.3553, 0.1402, 0.1402], - [2.50, -0.3051, 0.1098, 0.0549, 0.3521, 0.1412, 0.1412], - [2.55, -0.3066, 0.1078, 0.0572, 0.3491, 0.1422, 0.1422], - [2.60, -0.3079, 0.1059, 0.0594, 0.3461, 0.1432, 0.1432], - [2.65, -0.3092, 0.1042, 0.0614, 0.3433, 0.1441, 0.1441], - [2.70, -0.3104, 0.1026, 0.0632, 0.3406, 0.1450, 0.1450], - [2.75, -0.3115, 0.1011, 0.0649, 0.3379, 0.1458, 0.1458], - [2.80, -0.3125, 0.0997, 0.0665, 0.3354, 0.1467, 0.1467], - [2.85, -0.3135, 0.0984, 0.0679, 0.3329, 0.1475, 0.1475]] + [1.90, -0.2731, 0.1472, 0.0052, 0.3992, 0.1270, 0.1270], + [1.95, -0.2774, 0.1430, 0.0114, 0.3944, 0.1284, 0.1284], + [2.00, -0.2812, 0.1390, 0.0171, 0.3898, 0.1297, 0.1297], + [2.05, -0.2847, 0.1352, 0.0223, 0.3853, 0.1310, 0.1310], + [2.10, -0.2879, 0.1316, 0.0272, 0.3811, 0.1323, 0.1323], + [2.15, -0.2908, 0.1282, 0.0317, 0.3769, 0.1335, 0.1335], + [2.20, -0.2934, 0.1251, 0.0359, 0.3730, 0.1347, 0.1347], + [2.25, -0.2958, 0.1221, 0.0397, 0.3692, 0.1359, 0.1359], + [2.30, -0.2980, 0.1193, 0.0432, 0.3655, 0.1370, 0.1370], + [2.35, -0.3000, 0.1167, 0.0465, 0.3620, 0.1381, 0.1381], + [2.40, -0.3018, 0.1142, 0.0495, 0.3586, 0.1392, 0.1392], + [2.45, -0.3035, 0.1119, 0.0523, 0.3553, 0.1402, 0.1402], + [2.50, -0.3051, 0.1098, 0.0549, 0.3521, 0.1412, 0.1412], + [2.55, -0.3066, 0.1078, 0.0572, 0.3491, 0.1422, 0.1422], + [2.60, -0.3079, 0.1059, 0.0594, 0.3461, 0.1432, 0.1432], + [2.65, -0.3092, 0.1042, 0.0614, 0.3433, 0.1441, 0.1441], + [2.70, -0.3104, 0.1026, 0.0632, 0.3406, 0.1450, 0.1450], + [2.75, -0.3115, 0.1011, 0.0649, 0.3379, 0.1458, 0.1458], + [2.80, -0.3125, 0.0997, 0.0665, 0.3354, 0.1467, 0.1467], + [2.85, -0.3135, 0.0984, 0.0679, 0.3329, 0.1475, 0.1475], +] def gate(i): @@ -85,7 +82,7 @@ def gate(i): def expand_1q_gate(gate, target_qubit): - '''Expand a single-qubit gate applied on the `target_qubit` to a 4 x 4 matrix. + """Expand a single-qubit gate applied on the `target_qubit` to a 4 x 4 matrix. Qubits in the basis is organized as: |qubit_1, qubit_0> The basis of this matrix is shown as following: |00> |01> |10> |11> @@ -93,31 +90,34 @@ def expand_1q_gate(gate, target_qubit): |01> xx xx xx xx |10> xx xx xx xx |11> xx xx xx xx - ''' + """ if target_qubit == 1: return np.kron(gate, eye(2)) elif target_qubit == 0: return np.kron(eye(2), gate) else: raise ValueError( - "Given target_qubit ({}) is neither 0 or 1.".format(target_qubit)) + "Given target_qubit ({}) is neither 0 or 1.".format(target_qubit) + ) def hamiltonian(g): - '''Generate the hamiltonian for the H2 molecule, which is: - H = g0*I + g1*Z0 + g2*Z1 + g3*Z0Z1 + g4*Y0Y1 + g5*X0X1 - ''' + """Generate the hamiltonian for the H2 molecule, which is: + H = g0*I + g1*Z0 + g2*Z1 + g3*Z0Z1 + g4*Y0Y1 + g5*X0X1 + """ X = gate(1) Y = gate(2) Z = gate(3) - assert(len(g) == 6) - sigmas = [eye(4), - expand_1q_gate(Z, 0), - expand_1q_gate(Z, 1), - expand_1q_gate(Z, 0) * expand_1q_gate(Z, 1), - expand_1q_gate(X, 0) * expand_1q_gate(X, 1), - expand_1q_gate(Y, 0) * expand_1q_gate(Y, 1)] + assert len(g) == 6 + sigmas = [ + eye(4), + expand_1q_gate(Z, 0), + expand_1q_gate(Z, 1), + expand_1q_gate(Z, 0) * expand_1q_gate(Z, 1), + expand_1q_gate(X, 0) * expand_1q_gate(X, 1), + expand_1q_gate(Y, 0) * expand_1q_gate(Y, 1), + ] h = zeros((4, 4)) for i in range(6): h = h + np.dot(g[i], sigmas[i]) @@ -126,10 +126,10 @@ def hamiltonian(g): def get_ansatz(circ_name, theta): - if not qi.call_quingo(qu_file, circ_name, theta): - print("Failed to call {}".format(circ_name)) - res = qi.read_result() - return res + task = Quingo_task(qu_file, circ_name) + qasm_file = compile(task, (theta,), config_file=cfg_file) + res = execute(qasm_file, BackendType.QUANTUM_SIM, ExeConfig(ExeMode.SimStateVector)) + return [i for i in res["quantum"][1]] def get_real(c): @@ -137,16 +137,14 @@ def get_real(c): def expectation(h, state): - ''' Return the expectation value of the given state under the given hamiltonian. - ''' + """Return the expectation value of the given state under the given hamiltonian.""" state_matrix = np.mat(state).T t_conj_state = state_matrix.T.conjugate() return get_real(np.dot(t_conj_state, np.dot(h, state_matrix))) def energy_theta(theta: np.double, g): - '''Return the calculated energy for the given parameter theta. - ''' + """Return the calculated energy for the given parameter theta.""" ansatz_state = get_ansatz("ansatz", theta) h = hamiltonian(g) energy = expectation(h, ansatz_state) @@ -161,8 +159,7 @@ def eval_all(): g = b[1:] # --------------- optimization based on searching --------------- - minimum = minimize_scalar( - lambda theta: (energy_theta(theta, g)).A[0][0]) + minimum = minimize_scalar(lambda theta: (energy_theta(theta, g)).A[0][0]) lowest_energies.append(minimum.fun) plt.plot(bond_length, lowest_energies, "b.-") @@ -172,4 +169,5 @@ def eval_all(): plt.show() -eval_all() +# eval_all() +# get_ansatz("ansatz", 0.0) diff --git a/src/qututor/H2_VQE/std_qcis.qfg b/src/qututor/H2_VQE/std_qcis.qfg new file mode 100644 index 0000000000000000000000000000000000000000..befaab2261d6ee49f82c74c3c800e41027ae4623 --- /dev/null +++ b/src/qututor/H2_VQE/std_qcis.qfg @@ -0,0 +1,319 @@ +{ + "op_list": [ + { + "op_name": "X", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [1, 0, 0], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "Y", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [0, 1, 0], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "Z", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [0,0,1], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "RX", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "params": [ + { + "name": "angle", + "type": "double" + } + ], + "semantics": { + "type": "rotation", + "rot_axis": [ + 1, + 0, + 0 + ], + "rot_angle": "angle" + } + } + }, + { + "op_name": "arbRot", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0.6, + 0.8, + 0 + ], + "rot_angle": 1.5707963267948966 + } + } + }, + { + "op_name": "RY", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "params": [ + { + "name": "angle", + "type": "double" + } + ], + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 1, + 0 + ], + "rot_angle": "angle" + } + } + }, + { + "op_name": "RZ", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "params": [ + { + "name": "angle", + "type": "double" + } + ], + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 0, + 1 + ], + "rot_angle": "angle" + } + } + }, + { + "op_name": "H", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0.7071067811865476, + 0, + 0.7071067811865476 + ], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "CNOT", + "op_def": { + "num_target_qubits": 2, + "semantics": { + "type": "matrix", + "matrix": + [ + [[1,0], [0,0], [0,0], [0,0]], + [[0,0], [1,0], [0,0], [0,0]], + [[0,0], [0,0], [0,0], [1,0]], + [[0,0], [0,0], [1,0], [0,0]] + ] + } + } + }, + { + "op_name": "CZ", + "op_def": { + "num_target_qubits": 2, + "semantics": { + "type": "matrix", + "matrix": + [ + [[1,0], [0,0], [0,0], [0,0]], + [[0,0], [1,0], [0,0], [0,0]], + [[0,0], [0,0], [1,0], [0,0]], + [[0,0], [0,0], [0,0], [-1,0]] + ] + } + } + }, + { + "op_name":"measure", + "op_def": { + "duration": 600e-9, + "num_target_qubits": 1, + "semantics": { + "type": "measure", + "return": "bool" + } + } + }, + { + "op_name": "SingleQubitGate", + "op_def": { + "num_target_qubits": 1, + "semantics": { + "type": "matrix", + "matrix": + [ + [[1,0], [0,0]], + [[0,0], [1,0]] + ] + } + } + }, + { + "op_name": "X2P", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 1, + 0, + 0 + ], + "rot_angle":1.5707963267948966, + "global_phase":0 + } + } + }, + { + "op_name": "X2M", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 1, + 0, + 0 + ], + "rot_angle":-1.5707963267948966, + "global_phase":0 + } + } + }, + { + "op_name": "Y2P", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 1, + 0 + ], + "rot_angle":1.5707963267948966, + "global_phase":0 + } + } + }, + { + "op_name": "Y2M", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 1, + 0 + ], + "rot_angle":-1.5707963267948966, + "global_phase":0 + } + } + }, + { + "op_name": "S", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [0,0,1], + "rot_angle": 1.5707963267948966, + "global_phase": -0.7853981633974483 + } + } + }, + { + "op_name": "SD", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [0,0,1], + "rot_angle": -1.5707963267948966, + "global_phase": 0.7853981633974483 + } + } + }, + { + "op_name": "T", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [0,0,1], + "rot_angle": 0.7853981633974483, + "global_phase": -0.3926990816987241 + } + } + }, + { + "op_name": "TD", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [0,0,1], + "rot_angle": -0.7853981633974483, + "global_phase": 0.3926990816987241 + } + } + } + ] +} diff --git a/src/qututor/adder/test_adder.py b/src/qututor/adder/test_adder.py index 8ed89efb70c86767b3ca3f7ef08c903d976162d7..3de9fab98e56a51b824a3ace0fcfb652d8a7196b 100644 --- a/src/qututor/adder/test_adder.py +++ b/src/qututor/adder/test_adder.py @@ -4,23 +4,15 @@ from pathlib import Path import qututor.runtime.result_format as rf from qututor.adder.classical_behavior import adder_behavior, subtracter_behavior from qututor.tools import * + import termcolor as tc -import threading logger = get_logger("adder_test") -logger.setLevel(logging.INFO) +logger.setLevel(logging.DEBUG) +logger.disabled = True dir_path = Path(__file__).parent.resolve() kernel_file = (dir_path.parent.parent) / "quingo" / "draper_test.qu" -print("kernel_file: ", kernel_file.resolve()) - - -def trigger_task(func, args, multi_threading): - if multi_threading: - t = threading.Thread(target=func, args=args) - t.start() - else: - func(*args) class Test_Draper_adder: @@ -50,14 +42,14 @@ class Test_Draper_adder: num_qubits = 2 for i in range(1 << num_qubits): for j in range(1 << num_qubits): - trigger_task(Test_Draper_adder.add_or_sub, (i, j, num_qubits), False) + trigger_task(Test_Draper_adder.add_or_sub, (i, j, num_qubits), True) def test_subtracter(self): num_qubits = 2 for i in range(1 << num_qubits): for j in range(1 << num_qubits): trigger_task( - Test_Draper_adder.add_or_sub, (i, j, num_qubits, True), False + Test_Draper_adder.add_or_sub, (i, j, num_qubits, True), True ) diff --git a/src/qututor/bell/test_bell.py b/src/qututor/bell/test_bell.py index 852882822d78be42d7a948a2ad24cbda0a0651a2..162533eb2cd4b9a0c9ba3513745aa9abddc7a1c2 100644 --- a/src/qututor/bell/test_bell.py +++ b/src/qututor/bell/test_bell.py @@ -4,28 +4,20 @@ import qututor.global_config as gc qu_file = gc.quingo_dir / "bell.qu" - -# def test_bell(): circ_name = "bell_state" -task = Quingo_task(qu_file, circ_name, qisa=Qisa.QUIET, debug_mode=True) -num_shots = 10 -cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) - -# method 1 -# qasm_fn = compile(task, params=()) -# res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) -# method 2 -<<<<<<< HEAD -res = call(task, (), BackendType.DQCSIM_QUANTUMSIM, cfg) -======= -res = call(task, (), BackendType.DQCSIM_QUANTUMSIM cfg) ->>>>>>> tmp-br -print("res: ", res) -# assert len(res[0]) == 2 -# assert len(res[1]) == num_shots +class Test_Bell: + def test_bell(self): + task = Quingo_task(qu_file, circ_name) + num_shots = 10 + cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + res = call(task, (), BackendType.QUANTUM_SIM, cfg) + assert len(res[0]) == 2 + assert len(res[1]) == num_shots + for vars in res[1]: + assert vars[0] == vars[1] -# if __name__ == "__main__": -# test_bell() +if __name__ == "__main__": + Test_Bell().test_bell() diff --git a/src/qututor/bernstein/host.py b/src/qututor/bernstein/host.py deleted file mode 100644 index f277e68365ed3cc932f59c58821e9d2fcfaed249..0000000000000000000000000000000000000000 --- a/src/qututor/bernstein/host.py +++ /dev/null @@ -1,44 +0,0 @@ -import logging -from quingo import quingo_interface as qi -from pathlib import Path - -def dump_res(qcis_result): - if qcis_result is None: - print("No one-shot results found") - qubit_list, msmt_count = qcis_result - qubit_list.reverse() - # print(qubit_list) - if msmt_count is None: - print("no measurements performed on qubits") - for k, v in msmt_count.items(): - if v > 0: - return k - - -qi.set_compiler("mlir") -if qi.connect_backend("pyqcisim_quantumsim") is False: - exit(-1) - -qu_file = Path(__file__).parent / "bernstein_vazirani.qu" - - - -# circ_name = "single_bit" -# res = [] -# for bit in range(8): -# if not qi.call_quingo(qu_file, circ_name, bit): -# print("Failed to call {}. Abort".format(circ_name)) -# res.append(dump_res(qi.read_result())) -# print(res) - - -circ_name = "bernstein_vazirani" -if not qi.call_quingo(qu_file, circ_name): - print("Failed to call {}. Abort".format(circ_name)) -print("The result of {} is:".format(circ_name)) -result = dump_res(qi.read_result()) - -l = len(result) -for i in range(l): - print("{}".format(result[l-i-1]), end=" ") -print("") \ No newline at end of file diff --git a/src/qututor/bernstein/test_bernstein.py b/src/qututor/bernstein/test_bernstein.py new file mode 100644 index 0000000000000000000000000000000000000000..afa36f8692331b2bfe033a2761908e7f690288f0 --- /dev/null +++ b/src/qututor/bernstein/test_bernstein.py @@ -0,0 +1,26 @@ +import logging +from quingo import * +from pathlib import Path +import qututor.runtime.result_format as rf + +import qututor.global_config as gc + +qu_file = gc.quingo_dir / "bernstein_vazirani.qu" + +circ_name = "bernstein_vazirani" +# task = Quingo_task(qu_file, circ_name) +# sim_result = call(task, params=()) +# res = rf.get_first_non_zero_res(sim_result) +# print(res) + + +class Test_Bernstein_Vazirani: + def test_bernstein_vazirani(self): + task = Quingo_task(qu_file, circ_name) + sim_result = call(task, params=()) + res = rf.get_first_non_zero_res(sim_result) + assert res == 178 + + +if __name__ == "__main__": + Test_Bernstein_Vazirani().test_bernstein_vazirani() diff --git a/src/qututor/classical_tools/test_utils.py b/src/qututor/classical_tools/test_utils.py index 4454499ba6b7887dc580ab1caef8164e56900a3f..932794aa23489acbe93c5f3f8b298575a29a9253 100644 --- a/src/qututor/classical_tools/test_utils.py +++ b/src/qututor/classical_tools/test_utils.py @@ -1,21 +1,28 @@ -from quingo import quingo_interface as qi +from quingo import * from pathlib import Path import qututor.runtime.result_format as rf -qi.set_compiler("mlir") + dir_path = Path(__file__).parent kernel_file = dir_path / "utils.qu" -qi.set_num_shots(1) class Test_Utils: def test_individual(self): - qi.connect_backend("pyqcisim_quantumsim") + circ_name = "get_bin" + task = Quingo_task(kernel_file, circ_name, qisa=Qisa.QCIS) + cfg = ExeConfig(ExeMode.SimFinalResult, 1) for i in range(7): - assert qi.call_quingo(kernel_file, "get_bin", i, 4) - - res = rf.get_first_non_zero_res(qi.read_result()) - assert i == res + res = call( + task, + ( + i, + 4, + ), + BackendType.QUANTUM_SIM, + cfg, + ) + assert i == rf.get_first_non_zero_res(res) if __name__ == "__main__": diff --git a/src/qututor/ctrl-adder/ctrl_adder.py b/src/qututor/ctrl-adder/test_ctrl_adder.py similarity index 87% rename from src/qututor/ctrl-adder/ctrl_adder.py rename to src/qututor/ctrl-adder/test_ctrl_adder.py index 483e922cd87b1929ea54c3d24025f9c34cf5710d..85ff0f51269684a4b7916e1fc2bbf8795ed5b618 100644 --- a/src/qututor/ctrl-adder/ctrl_adder.py +++ b/src/qututor/ctrl-adder/test_ctrl_adder.py @@ -4,10 +4,10 @@ import qututor.runtime.result_format as rf import qututor.global_config as gc from qututor.tools import * import termcolor as tc -import threading logger = get_logger("ctrl_adder") logger.setLevel(logging.DEBUG) +logger.disabled = True mod_adder_module = gc.quingo_dir / "test_ctrl_adder.qu" DEBUG_MODE = False @@ -45,10 +45,7 @@ class Test_CtrlAdd: if DEBUG_MODE: Test_CtrlAdd.ctrl_adder(params, DEBUG_MODE) else: - t = threading.Thread( - target=Test_CtrlAdd.ctrl_adder, args=(params, DEBUG_MODE) - ) - t.start() + trigger_task(Test_CtrlAdd.ctrl_adder, (params, DEBUG_MODE), True) single_test((1, 1, 2, 3, 3)) single_test((1, 1, 1, 5, 3)) diff --git a/src/qututor/ctrl-mult/test_ctrl_mult.py b/src/qututor/ctrl-mult/test_ctrl_mult.py index de428e4f32a832c3e414e31f72fff50aceeb79d4..746abca6157b26aaf8be0b5341413c2ed3fed945 100644 --- a/src/qututor/ctrl-mult/test_ctrl_mult.py +++ b/src/qututor/ctrl-mult/test_ctrl_mult.py @@ -3,11 +3,12 @@ from quingo import * import qututor.runtime.result_format as rf import qututor.global_config as gc from qututor.tools import * + import termcolor as tc -import threading logger = get_logger("ctrl-mult") logger.setLevel(logging.DEBUG) +logger.disabled = True mod_adder_module = gc.quingo_dir / "ctrl_multiplier.qu" DEBUG_MODE = False @@ -29,7 +30,9 @@ class Test_CtrlMult: exp_res = ((a * x + b) % N) if (c == 1) else b sim_result = call(task, params=(c, x, b, a, N, w)) - res = rf.get_first_non_zero_res(sim_result) + qs_b = sim_result[1][0][w + 2 : 2 * w + 3][::-1] + res = int("".join(list(map(str, qs_b))), 2) + logger.info( "ctrl_mult " + ( @@ -48,10 +51,7 @@ class Test_CtrlMult: if DEBUG_MODE: Test_CtrlMult.ctrl_mult(params, DEBUG_MODE) else: - t = threading.Thread( - target=Test_CtrlMult.ctrl_mult, args=(params, DEBUG_MODE) - ) - t.start() + trigger_task(Test_CtrlMult.ctrl_mult, (params, DEBUG_MODE), True) # c: 1, x: 2, b: 2, a: 3, N: 7, w: 3 # (a * x + b) % N -> (2*3+2) % 7 = 1 diff --git a/src/qututor/ctrl-mult/test_ctrl_ua.py b/src/qututor/ctrl-mult/test_ctrl_ua.py new file mode 100644 index 0000000000000000000000000000000000000000..5b2b2cbf8a33f88e21f183a0f6069f1eb7537d90 --- /dev/null +++ b/src/qututor/ctrl-mult/test_ctrl_ua.py @@ -0,0 +1,97 @@ +import logging +from quingo import * +import qututor.runtime.result_format as rf +import qututor.global_config as gc +from qututor.tools import * +from random import randint +import math + +import termcolor as tc + +logger = get_logger("ctrl-ua") +logger.setLevel(logging.DEBUG) +logger.disabled = False + +mod_adder_module = gc.quingo_dir / "ctrl_multiplier.qu" +DEBUG_MODE = False + + +# a^-1 mod n +# gcd(a,n) = 1 (necessary condition) +class Test_Mod_Inverse: + def mod_inv(self, a, n): + res = pow(a, -1, n) + mult_mod = (a * res) % n + logger.debug(f"{a} * {res} mod {n} = {mult_mod}") + assert mult_mod == (1 % n) + return res + + def test_mod_inv(self): + def get_rand_coprimes(): + while True: + a = randint(1, 100) + n = randint(1, 100) + if math.gcd(a, n) == 1: + return a, n + + test_times = 5 + for i in range(test_times): + a, n = get_rand_coprimes() + res = self.mod_inv(a, n) + logger.info(f"All {test_times} tests of modular inverse passed.") + + +# class Test_CtrlUa: +# def ctrl_ua(params, debug): +# task = Quingo_task(mod_adder_module, "test_c_mult_N", debug_mode=debug) + +# c, x, b, a, N, w = params + +# logger.debug( +# "test_c_mult_N: c: {}, x: {}, b: {}, a: {}, N: {}, w: {}".format( +# c, x, b, a, N, w +# ) +# ) + +# # 1-controlled multipler: |x>|b> -> |x> | (ax + b) mod N> +# exp_res = ((a * x + b) % N) if (c == 1) else b + +# sim_result = call(task, params=(c, x, b, a, N, w)) +# qs_b = sim_result[1][0][w + 2 : 2 * w + 3][::-1] +# res = int("".join(list(map(str, qs_b))), 2) + +# logger.info( +# "ctrl_ua " +# + ( +# tc.colored("passed:", "green") +# if res == exp_res +# else tc.colored("failed:", "red") +# ) +# + "c: {}, x: {}, b: {}, a: {}, N: {}, w: {}, acutal: {}, expect: {}".format( +# c, x, b, a, N, w, res, exp_res +# ) +# ) +# assert res == exp_res + +# def test_ctrl_ua(self): +# def single_test(params): +# if DEBUG_MODE: +# Test_CtrlUa.ctrl_ua(params, DEBUG_MODE) +# else: +# trigger_task(Test_CtrlUa.ctrl_ua, (params, DEBUG_MODE), True) + +# # c: 1, x: 2, b: 2, a: 3, N: 7, w: 3 +# # (a * x + b) % N -> (2*3+2) % 7 = 1 +# # qubits: +# # control: 1 | 1 +# # qs_x : 2 | 0 1 0 0 +# # qs_b : 1 | 1 0 0 0 +# # anc : 0 | 0 +# # expect result: [1, 0, 1, 0, 0, 1, 0, 0, 0, 0] +# # actual result: [1, 0, 1, 0, 0, 1, 0, 0, 0, 0] +# single_test((1, 2, 2, 3, 7, 3)) + + +if __name__ == "__main__": + test = Test_Mod_Inverse() + test.test_mod_inv() diff --git a/src/qututor/ghz/ghz.py b/src/qututor/ghz/ghz.py deleted file mode 100644 index f94f9467f1d686e6cc0180b967faeff8674ff199..0000000000000000000000000000000000000000 --- a/src/qututor/ghz/ghz.py +++ /dev/null @@ -1,22 +0,0 @@ -from quingo import * -import qututor.global_config as gc - -qu_file = gc.quingo_dir / "ghz.qu" - - -circ_name = "GHZ_state" -num_shots = 10 -task = Quingo_task(qu_file, circ_name) -cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) - -# method 1 -# qasm_fn = compile(task, params=()) -# res = execute(qasm_fn, BackendType.QUANTUM_SIM, cfg) - -# method 2 -num_qubits = 3 -res = call(task, (num_qubits,), BackendType.TEUQILA, cfg) -print("res: ", res) - -assert len(res[0]) == num_qubits -assert len(res[1]) == num_shots diff --git a/src/qututor/ghz/test_ghz.py b/src/qututor/ghz/test_ghz.py new file mode 100644 index 0000000000000000000000000000000000000000..3c4acb90761e6c4d9e9286a316193b4b363e86b6 --- /dev/null +++ b/src/qututor/ghz/test_ghz.py @@ -0,0 +1,22 @@ +from quingo import * +import qututor.global_config as gc + +qu_file = gc.quingo_dir / "ghz.qu" +circ_name = "GHZ_state" + + +class Test_GHZ: + def test_ghz(self): + num_qubits = 3 + num_shots = 10 + task = Quingo_task(qu_file, circ_name) + cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + res = call(task, (num_qubits,), BackendType.TEQUILA, cfg) + assert len(res[0]) == num_qubits + assert len(res[1]) == num_shots + for vars in res[1]: + assert vars[0] == vars[1] == vars[2] + + +if __name__ == "__main__": + Test_GHZ().test_ghz() diff --git a/src/qututor/grover/main.py b/src/qututor/grover/main.py deleted file mode 100644 index 241b84dfe3f061cb46ad0c934e50d8906e588d90..0000000000000000000000000000000000000000 --- a/src/qututor/grover/main.py +++ /dev/null @@ -1,14 +0,0 @@ -from quingo import * -import qututor.global_config as gc - -qu_file = gc.quingo_dir / "grover2.qu" - - -circ_name = "grover_2q" -num_shots = 1 -task = Quingo_task(qu_file, circ_name) -cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) - -# method 2 -res = call(task, (), BackendType.QUANTUM_SIM, cfg) -print("res: ", res) diff --git a/src/qututor/grover/test_grover.py b/src/qututor/grover/test_grover.py new file mode 100644 index 0000000000000000000000000000000000000000..27d4a57c3ba3585c5ec2cfef4d72b6248c61e79e --- /dev/null +++ b/src/qututor/grover/test_grover.py @@ -0,0 +1,22 @@ +from quingo import * +import qututor.global_config as gc + +qu_file = gc.quingo_dir / "grover.qu" + + +circ_name = "grover_2q" + + +class Test_Grover: + def test_grover(self): + task = Quingo_task(qu_file, circ_name) + num_shots = 1 + cfg = ExeConfig(ExeMode.SimFinalResult, num_shots) + res = call(task, (), BackendType.QUANTUM_SIM, cfg) + assert len(res[0]) == 2 + assert len(res[1]) == num_shots + assert res[1][0] == [0, 1] + + +if __name__ == "__main__": + Test_Grover().test_grover() diff --git a/src/qututor/qft/test_qft_bb.py b/src/qututor/qft/test_qft_bb.py index 8c1004476628ac6e68a6dd0ac32b75391291898b..eeea3eca24b5f7bfa520fd06c43b8c3e54ec9530 100644 --- a/src/qututor/qft/test_qft_bb.py +++ b/src/qututor/qft/test_qft_bb.py @@ -1,13 +1,10 @@ import logging -from quingo import quingo_interface as qi +from quingo import * from pathlib import Path +import qututor.global_config as gc -qi.set_compiler("mlir") -# qi.connect_backend("pyqcisim_tequila") -# qi.set_verbose(True) -# qi.set_log_level(logging.DEBUG) -dir_path = Path(__file__).parent -kernel_file = dir_path / "qft2.qu" + +qu_file = gc.quingo_dir / "test_qft.qu" def is_number(s): @@ -25,29 +22,39 @@ def get_bin(x, n): return "{0:{fill}{width}b}".format((int(x) + 2**n) % 2**n, fill="0", width=n) +def to_int(x): + a = 0 + for i in range(len(x)): + if x[i] == 1: + a += 2**i + return a + + def get_first_non_zero_res(qcis_result): if qcis_result is None: print("No measure results found") qubit_list, msmt_count = qcis_result - for k, v in msmt_count.items(): - if v > 0: - return int(k, 2) + return to_int(msmt_count[0]) -qi.set_num_shots(1) +cfg = ExeConfig(ExeMode.SimFinalResult, 1) class Test_QFT_BB: def test_qft_bb(self): - qi.connect_backend("pyqcisim_quantumsim") num_qubits = 2 for i in range(1 << num_qubits): str_bin = get_bin(i, num_qubits) blist = [int(b) for b in str_bin] print("input :", str_bin) blist.reverse() - assert qi.call_quingo(kernel_file, "test_qft_bb", blist) - res = qi.read_result() + task = Quingo_task(qu_file, "test_qft_bb", qisa=Qisa.QCIS) + res = call( + task, + (blist,), + BackendType.QUANTUM_SIM, + cfg, + ) k = get_first_non_zero_res(res) assert k == i diff --git a/src/qututor/qft/test_qft_mat.py b/src/qututor/qft/test_qft_mat.py index c920c82ec3db7746b8e553f7c671e7c9d24c3a36..21ea2e6e9feaba930dbfd72d3f48e198c632ef7d 100644 --- a/src/qututor/qft/test_qft_mat.py +++ b/src/qututor/qft/test_qft_mat.py @@ -1,38 +1,120 @@ import logging -from quingo import quingo_interface as qi +from quingo import * from pathlib import Path import numpy as np import sympy as sp -from matrix_equal import matrix_equal, sp_mat_equal + +# from matrix_equal import matrix_equal, sp_mat_equal from cl_ft import qft from symqc import circuit_mat, circuit_mat_from_file +import qututor.global_config as gc np.set_printoptions(precision=3, suppress=True) +qu_file = gc.quingo_dir / "test_qft.qu" + +import numpy as np + +ATOL_DEFAULT = 1e-5 +RTOL_DEFAULT = 1e-5 + + +def extract_global_phase(mat): + phases = np.angle(mat[abs(mat) > 1e-6].ravel(order="F")) + + if len(phases) > 0: + # Get phase of first non-zero entry of matrix + # and multiply all entries by the conjugate + mat = np.exp(-1j * phases[0]) * mat + + return mat, phases[0] + + +def matrix_equal(mat1, mat2, ignore_phase=True, rtol=RTOL_DEFAULT, atol=ATOL_DEFAULT): + """Test if two arrays are equal. + + The final comparison is implemented using Numpy.allclose. See its + documentation for additional information on tolerance parameters. + + If ignore_phase is True both matrices will be multiplied by + exp(-1j * theta) where `theta` is the first nphase for a + first non-zero matrix element `|a| * exp(1j * theta)`. + + Args: + mat1 (matrix_like): a matrix + mat2 (matrix_like): a matrix + ignore_phase (bool): ignore complex-phase differences between + matrices [Default: False] + rtol (double): the relative tolerance parameter [Default {}]. + atol (double): the absolute tolerance parameter [Default {}]. + + Returns: + bool: True if the matrices are equal or False otherwise. + """.format( + RTOL_DEFAULT, ATOL_DEFAULT + ) + + if atol is None: + atol = ATOL_DEFAULT + if rtol is None: + rtol = RTOL_DEFAULT + mat1 = np.array(mat1) + mat2 = np.array(mat2) + if mat1.shape != mat2.shape: + return False + if ignore_phase: + mat1, phase1 = extract_global_phase(mat1) + mat2, phase2 = extract_global_phase(mat2) + + for i in range(mat1.shape[0]): + for j in range(mat1.shape[1]): + v1 = mat1[i][j] + v2 = mat2[i][j] + if np.abs(v1 - v2) > 1e-6: + print("mat[{}, {}] has diff elements: {} v.s. {}".format(i, j, v1, v2)) + return False + return True + + +def sp_mat_equal(sp_mat1, sp_mat2): + np_mat1 = np.array(sp_mat1).astype(np.complex64) + np_mat2 = np.array(sp_mat2).astype(np.complex64) + return matrix_equal(np_mat1, np_mat2) + + +import sympy as sp + + +def dft_element(N, i, j): + return sp.exp((2 * sp.pi * sp.I / N) * i * j) -dir_path = Path(__file__).parent -qu_file = dir_path / "qft2.qu" -qi.set_compiler("mlir") +def qft(num_qubits): + N = 2**num_qubits + rows = [] + for i in range(N): + row = [] + for j in range(N): + row.append(dft_element(N, i, j)) + rows.append(row) + return sp.MatMul(1 / sp.sqrt(N), sp.Matrix(rows), evaluate=False) class Test_QFT_IQFT: def test_qft(self): - assert qi.connect_backend("pyqcisim_quantumsim") circ_name = "call_qft" - qcis_file = dir_path / "build" / (circ_name + ".qcis") - for num_qubits in range(1, 6): - assert qi.call_quingo(qu_file, circ_name, num_qubits) + task = Quingo_task(qu_file, circ_name, qisa=Qisa.QCIS) + for num_qubits in range(1, 2): + qcis_file = compile(task, params=(num_qubits,), config_file="") qu_sy_mat = circuit_mat_from_file(qcis_file) cl_sp_mat = qft(num_qubits) assert sp_mat_equal(qu_sy_mat, cl_sp_mat) def test_iqft(self): - assert qi.connect_backend("pyqcisim_quantumsim") circ_name = "call_iqft" - qcis_file = dir_path / "build" / (circ_name + ".qcis") - for num_qubits in range(1, 6): - assert qi.call_quingo(qu_file, circ_name, num_qubits) + task = Quingo_task(qu_file, circ_name, qisa=Qisa.QCIS) + for num_qubits in range(1, 2): + qcis_file = compile(task, params=(num_qubits,), config_file="") qu_sy_mat = circuit_mat_from_file(qcis_file) cl_sp_mat = qft(num_qubits).adjoint() assert sp_mat_equal(qu_sy_mat, cl_sp_mat) diff --git a/src/qututor/recursion_test/test_scalarize_alloc/alloc.qu b/src/qututor/recursion_test/test_scalarize_alloc/alloc.qu new file mode 100644 index 0000000000000000000000000000000000000000..e5e7d891d54b32ae22fbec77d8905c23bc56576d --- /dev/null +++ b/src/qututor/recursion_test/test_scalarize_alloc/alloc.qu @@ -0,0 +1,18 @@ +import std_ops + +operation alloc_qubits_measure(a: int[], b: int[]) : bool[] { + int num_qubits = b.length; + bool[num_qubits] result; + using (qa: qubit[num_qubits]) { + for (int i = 0; i < num_qubits; i += 1) { + result[i] = measure(qa[i]); + } + } + return result; +} + +operation test_entry() : bool[] { + int[] a = {0, 0}; + int[] b = {0, 0}; + return alloc_qubits_measure(a, b); +} \ No newline at end of file diff --git a/src/qututor/recursion_test/test_scalarize_alloc/test_alloc.py b/src/qututor/recursion_test/test_scalarize_alloc/test_alloc.py new file mode 100644 index 0000000000000000000000000000000000000000..a3d4092bdaa8b234bd1784cc5fd4638b09efac13 --- /dev/null +++ b/src/qututor/recursion_test/test_scalarize_alloc/test_alloc.py @@ -0,0 +1,21 @@ +from quingo import * +from quingo.backend.qisa import Qisa +from pathlib import Path + +qu_file = Path(__file__).parent / "alloc.qu" + + +def test_alloc_with_qcis(): + circ_name = "test_entry" + task = Quingo_task(qu_file, circ_name, qisa=Qisa.QCIS) + qasm_fn = compile(task, params=()) + print(qasm_fn) + with qasm_fn.open() as f: + lines = f.readlines() + + assert "M Q0" == lines[0].strip() + assert "M Q1" == lines[1].strip() + + +if __name__ == "__main__": + test_alloc_with_qcis() diff --git a/src/qututor/shor/modular_adder_test.py b/src/qututor/shor/test_modular_adder.py similarity index 80% rename from src/qututor/shor/modular_adder_test.py rename to src/qututor/shor/test_modular_adder.py index 58fd00ca8901e2b997f6619a72f92a287d963d62..f7353729bbc032539b5473ffae2cc06b37b66bc9 100644 --- a/src/qututor/shor/modular_adder_test.py +++ b/src/qututor/shor/test_modular_adder.py @@ -4,10 +4,10 @@ import qututor.runtime.result_format as rf import qututor.global_config as gc from qututor.tools import * import termcolor as tc -import threading logger = get_logger("add_N_back") logger.setLevel(logging.DEBUG) +logger.disabled = True mod_adder_module = gc.quingo_dir / "modular_adder.qu" @@ -19,7 +19,9 @@ class Test_Addback: logger.debug("add_back: a: {}, b: {}, N: {}, w: {}".format(a, b, N, w)) exp_res = a + b sim_result = call(task, params=(a, b, N, w)) - res = rf.get_first_non_zero_res(sim_result) + res = sim_result[1][0][::-1][1:] + res = int("".join(list(map(str, res))), 2) + logger.info( "add_back " + ( @@ -39,6 +41,7 @@ class Test_Addback: logger.debug("add_back_nc: a: {}, b: {}, N: {}, w: {}".format(a, b, N, w)) exp_res = (a + b) % N sim_result = call(task, params=(a, b, N, w)) + # print("sim_result: ", sim_result) res = rf.get_first_non_zero_res(sim_result) logger.info( "mod_adder_nc " @@ -55,17 +58,15 @@ class Test_Addback: def test_add_backs(self): def single_test(params): - t1 = threading.Thread(target=Test_Addback.add_back, args=(params,)) - t2 = threading.Thread(target=Test_Addback.mod_adder_nc, args=(params,)) - t1.start() - t2.start() + trigger_task(Test_Addback.add_back, (params,), True) + trigger_task(Test_Addback.mod_adder_nc, (params,), True) # a, b, N, width + # N > a,b single_test((2, 2, 3, 2)) single_test((1, 1, 3, 2)) single_test((0, 1, 3, 2)) single_test((0, 0, 5, 3)) - single_test((5, 7, 5, 3)) single_test((2, 3, 8, 3)) single_test((7, 3, 8, 3)) @@ -80,9 +81,9 @@ class Test_Addback: ) sim_result = call(task, params) - print("sim_result: ", sim_result) + # print("sim_result: ", sim_result) res = rf.get_first_non_zero_res(sim_result) - print("res: ", res) + # print("res: ", res) logger.info( "mod_adder_nc " + ( @@ -98,16 +99,14 @@ class Test_Addback: def test_mod_adder(self): def single_test(params): - t = threading.Thread(target=Test_Addback.mod_adder, args=(params,)) - t.start() # `start()` should be called in another line to enable printing + trigger_task(Test_Addback.mod_adder, (params,), True) - # c0, c1, a, b, N, w single_test((1, 1, 2, 3, 8, 3)) single_test((1, 0, 2, 3, 8, 3)) if __name__ == "__main__": test = Test_Addback() - # test.test_add_backs() + test.test_add_backs() test.test_mod_adder() - # print("All tests passed") + print("All tests passed") diff --git a/src/qututor/tools.py b/src/qututor/tools.py index f50309ebadbe913c249b48e1c75ff7d65ee8344b..a9da87bce940c23c4f85178e03ce08fa2c91b99d 100644 --- a/src/qututor/tools.py +++ b/src/qututor/tools.py @@ -1,3 +1,6 @@ +import threading + + def is_number(s): try: float(s) @@ -31,7 +34,6 @@ def test_int2bits(): assert int2bit_list(1089, 15) == [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0] - import logging from logging.handlers import TimedRotatingFileHandler import sys @@ -98,6 +100,13 @@ def ensure_path(fn) -> Path: return fn +def trigger_task(func, args, multi_threading): + if multi_threading: + t = threading.Thread(target=func, args=args) + t.start() + else: + func(*args) + if __name__ == "__main__": test_int2bits() diff --git a/src/qututor/vqe/Hamiltonian.py b/src/qututor/vqe/Hamiltonian.py new file mode 100644 index 0000000000000000000000000000000000000000..441fee45192568eb17650b0f91530e49b1754c78 --- /dev/null +++ b/src/qututor/vqe/Hamiltonian.py @@ -0,0 +1,199 @@ +import numpy as np +from numpy import * +from expand_gate import expand_gate + + +class Hamiltonian: + def __init__(self, paulis, coeffs): + self.paulis = paulis + self.coeffs = coeffs + assert len(paulis) == len(coeffs) + self.num_qubits = len(paulis[0]) + self.num_paulis = len(paulis) + + def __str__(self): + s = "" + for i in range(self.num_paulis): + s += str(self.coeffs[i]) + "*" + str(self.paulis[i]) + " + " + return s[:-3] + + def __repr__(self): + return self.__str__() + + def __len__(self): + return self.num_paulis + + def __getitem__(self, i): + return self.paulis[i], self.coeffs[i] + + def __iter__(self): + return iter(zip(self.paulis, self.coeffs)) + + def to_matrix(self): + """ + paulis: list of Pauli matrices, + e.g. ["X", "Y", "Z", ...] for 1-qubit Paulis + e.g. ["XI", "IZ", "ZZ", ...] for 2-qubit Paulis + e.g. ["XIZI", "IZZI", "ZZZZ", ...] for 4-qubit Paulis + coeffs: list of coefficients, + e.g. [1.0, -0.5, 0.3, ...] and len(coeffs) == len(paulis) + for example, + the Hamiltonian H = g0*I + g1*Z0 + g2*Z1 + g3*Z0Z1 + g4*Y0Y1 + g5*X0X1 + can be represented as + paulis = ["II", "IZ", "ZI", "ZZ", "YY", "XX"] + coeffs = [g0, g1, g2, g3, g4, g5] + """ + X = pauli_gate(1) + Y = pauli_gate(2) + Z = pauli_gate(3) + I = pauli_gate(4) + + sigmas = [] + for i in range(self.num_paulis): + assert len(self.paulis[i]) == self.num_qubits + s = eye(2**self.num_qubits) + for j in range(self.num_qubits): + if str(self.paulis[i][j]) == "I": + s = s * expand_gate(self.num_qubits, I, [j]) + elif str(self.paulis[i][j]) == "X": + s = s * expand_gate(self.num_qubits, X, [j]) + elif str(self.paulis[i][j]) == "Y": + s = s * expand_gate(self.num_qubits, Y, [j]) + elif str(self.paulis[i][j]) == "Z": + s = s * expand_gate(self.num_qubits, Z, [j]) + else: + raise ValueError("Invalid Pauli string") + sigmas.append(s) + assert len(sigmas) == self.num_paulis + h = np.zeros(sigmas[0].shape) + for i in range(len(sigmas)): + h = h + self.coeffs[i] * sigmas[i] + return h + + +def pauli_gate(i): + if i == 1: + m = np.matrix([[0, 1], [1, 0]]) + elif i == 2: + m = np.matrix([[0, -1j], [1j, 0]]) + elif i == 3: + m = np.matrix([[1, 0], [0, -1]]) + elif i == 4: + m = np.matrix([[1, 0], [0, 1]]) + else: + raise IndexError("Invalid Pauli index") + return m + + +def hamiltonian(paulis, coeffs): + """ + paulis: list of Pauli matrices, + e.g. ["X", "Y", "Z", ...] for 1-qubit Paulis + e.g. ["XI", "IZ", "ZZ", ...] for 2-qubit Paulis + e.g. ["XIZI", "IZZI", "ZZZZ", ...] for 4-qubit Paulis + coeffs: list of coefficients, + e.g. [1.0, -0.5, 0.3, ...] and len(coeffs) == len(paulis) + for example, + the Hamiltonian H = g0*I + g1*Z0 + g2*Z1 + g3*Z0Z1 + g4*Y0Y1 + g5*X0X1 + can be represented as + paulis = ["II", "IZ", "ZI", "ZZ", "YY", "XX"] + coeffs = [g0, g1, g2, g3, g4, g5] + """ + X = pauli_gate(1) + Y = pauli_gate(2) + Z = pauli_gate(3) + I = pauli_gate(4) + + assert len(coeffs) == len(paulis) + sigmas = [] + for i in range(len(paulis)): + assert len(paulis[i]) == len(paulis[0]) + s = eye(2 ** len(paulis[i])) + for j in range(len(paulis[i])): + if str(paulis[i][j]) == "I": + s = s * expand_gate(len(paulis[i]), I, [j]) + elif str(paulis[i][j]) == "X": + s = s * expand_gate(len(paulis[i]), X, [j]) + elif str(paulis[i][j]) == "Y": + s = s * expand_gate(len(paulis[i]), Y, [j]) + elif str(paulis[i][j]) == "Z": + s = s * expand_gate(len(paulis[i]), Z, [j]) + else: + raise ValueError("Invalid Pauli string") + sigmas.append(s) + assert len(sigmas) == len(paulis) + h = np.zeros(sigmas[0].shape) + for i in range(len(sigmas)): + h = h + coeffs[i] * sigmas[i] + return h + + +# def expand_1q_gate(gate, target_qubit): +# """Expand a single-qubit gate applied on the `target_qubit` to a 4 x 4 matrix. +# Qubits in the basis is organized as: |qubit_1, qubit_0> +# The basis of this matrix is shown as following: +# |00> |01> |10> |11> +# |00> xx xx xx xx +# |01> xx xx xx xx +# |10> xx xx xx xx +# |11> xx xx xx xx +# """ +# if target_qubit == 1: +# return np.kron(gate, eye(2)) +# elif target_qubit == 0: +# return np.kron(eye(2), gate) +# else: +# raise ValueError( +# "Given target_qubit ({}) is neither 0 or 1.".format(target_qubit) +# ) + + +# def gate(i): +# if i == 1: +# m = np.matrix([[0, 1], [1, 0]]) +# elif i == 2: +# m = np.matrix([[0, -1j], [1j, 0]]) +# elif i == 3: +# m = np.matrix([[1, 0], [0, -1]]) +# elif i == 4: +# m = np.matrix([[1, 0], [0, 1]]) +# else: +# raise IndexError("Invalid Pauli index") +# return m + + +# def hamiltonian2(g): +# """Generate the hamiltonian for the H2 molecule, which is: +# H = g0*I + g1*Z0 + g2*Z1 + g3*Z0Z1 + g4*Y0Y1 + g5*X0X1 +# """ +# X = gate(1) +# Y = gate(2) +# Z = gate(3) + +# assert len(g) == 6 +# sigmas = [ +# eye(4), +# expand_1q_gate(Z, 0), +# expand_1q_gate(Z, 1), +# expand_1q_gate(Z, 0) * expand_1q_gate(Z, 1), +# expand_1q_gate(X, 0) * expand_1q_gate(X, 1), +# expand_1q_gate(Y, 0) * expand_1q_gate(Y, 1), +# ] +# h = zeros((4, 4)) +# for i in range(6): +# h = h + np.dot(g[i], sigmas[i]) + +# return h + +# from qiskit.quantum_info import SparsePauliOp + +# H2_op = SparsePauliOp.from_list( +# [ +# ("II", -1.052373245772859), +# ("IZ", 0.39793742484318045), +# ("ZI", -0.39793742484318045), +# ("ZZ", -0.01128010425623538), +# ("XX", 0.18093119978423156), +# ] +# ) +# print(hamiltonian(H2_op.paulis, H2_op.coeffs)) diff --git a/src/qututor/vqe/VQE.py b/src/qututor/vqe/VQE.py new file mode 100644 index 0000000000000000000000000000000000000000..bc0b1864c091087987cf05d8a64ef21a588f380b --- /dev/null +++ b/src/qututor/vqe/VQE.py @@ -0,0 +1,93 @@ +# 1. 构造哈密顿量 +from qututor.vqe.Hamiltonian import hamiltonian, Hamiltonian +from qututor.vqe.ansatz import Ansatz_circuit + +# 验证 hamiltonian 的正确性 +""" +from qiskit_nature.units import DistanceUnit +from qiskit_nature.second_q.drivers import PySCFDriver +from qiskit_nature.second_q.mappers import JordanWignerMapper +import qiskit_nature.settings + +qiskit_nature.settings.use_pauli_sum_op = False + +driver = PySCFDriver( + atom="H 0 0 0; H 0 0 0.735", + basis="sto3g", + charge=0, + spin=0, + unit=DistanceUnit.ANGSTROM, +) +problem = driver.run() +mapper = JordanWignerMapper() +H2_op = mapper.map(problem.hamiltonian.second_q_op()) + +H1 = H2_op.to_matrix() +# print(H1) +H2 = hamiltonian(H2_op.paulis, H2_op.coeffs) +assert (H1 == H2).all() +""" +"./std_qcis.qfg" +# 2. 生成 ansatz 电路 +""" +from pathlib import Path +from quingo import * +qu_file = Path(__file__).parent / "kernel.qu" +# input circuit name. +circ_name = "ansatz" +cfg = ExeConfig(ExeMode.SimStateVector) +params = (0.1,) +get_ansatz(qu_file, circ_name, params, config_file="./std_qcis.qfg") +""" + +# 3. 优化 +# from scipy.optimize import minimize_scalar, minimize +from scipy.optimize import minimize_scalar, minimize +import matplotlib.pyplot as plt +import numpy as np +from quingo import * +from pathlib import Path +from typing import List +import random + + +def expectation(h, state): + """Return the expectation value of the given state under the given hamiltonian.""" + state_matrix = np.mat(state).T + t_conj_state = state_matrix.T.conjugate() + return np.real(np.dot(t_conj_state, np.dot(h, state_matrix))) + + +def energy_theta( + circ: Ansatz_circuit, + params: np.array, + hamiltonian: Hamiltonian, + backend=BackendType.QUANTUM_SIM, + config_file="", +): + """Return the calculated energy for the given parameter theta.""" + circ.params = params + circ.with_backend(backend) + circ.with_config_file(config_file) + ansatz_state = circ.get_ansatz() + h = hamiltonian.to_matrix() + energy = expectation(h, ansatz_state) + return energy + + +def vqe( + circ: Ansatz_circuit, + hamiltonian: Hamiltonian, + backend=BackendType.QUANTUM_SIM, + method="Nelder-Mead", + circ_cfg_file="", +): + """Return the calculated energy for the given parameter theta.""" + + def loss_func(params): + return energy_theta(circ, params, hamiltonian, backend, circ_cfg_file).A[0][0] + + theta = random.uniform(0, 2 * np.pi) + x1 = np.array([theta] * circ.num_params) + minimum = minimize(fun=loss_func, x0=x1, method=method) + return minimum diff --git a/src/qututor/vqe/ansatz.py b/src/qututor/vqe/ansatz.py new file mode 100644 index 0000000000000000000000000000000000000000..f4278a687f224b8cb14e11f44d60d65d321aa47f --- /dev/null +++ b/src/qututor/vqe/ansatz.py @@ -0,0 +1,50 @@ +from pathlib import Path +from quingo import * + + +class Ansatz_circuit: + def __init__(self, qu_file: Path, circ_name: str, num_params: int): + self.qu_file = qu_file + self.circ_name = circ_name + self.num_params = num_params + self._params = None + self.backend = BackendType.QUANTUM_SIM + self.exe_config = ExeConfig(ExeMode.SimStateVector) + self.config_file = "" + + @property + def params(self): + return self._params + + @params.setter + def params(self, params): + if len(params) != self.num_params: + raise ValueError( + "The number of parameters ({}) does not match the number of parameters in the circuit ({})".format( + len(params), self.num_params + ) + ) + self._params = params + + def with_params(self, params): + self.params = params + + def with_backend(self, backend): + self.backend = backend + + def with_config_file(self, config_file): + self.config_file = config_file + + def get_ansatz(self): + task = Quingo_task(self.qu_file, self.circ_name, debug_mode=False) + qasm_fn = compile(task, params=self.params, config_file=self.config_file) + res = execute(qasm_fn, self.backend, ExeConfig(ExeMode.SimStateVector)) + return res["quantum"][1] + + +# # get ansatz. +# def get_ansatz(circ: Ansatz_circuit, backend, config_file=""): +# task = Quingo_task(circ.qu_file, circ.circ_name, debug_mode=False) +# qasm_fn = compile(task, params=circ.params, config_file=config_file) +# res = execute(qasm_fn, backend, ExeConfig(ExeMode.SimStateVector)) +# return res["quantum"][1] diff --git a/src/qututor/vqe/expand_gate.py b/src/qututor/vqe/expand_gate.py new file mode 100644 index 0000000000000000000000000000000000000000..9a582cf3aec96197c16879fe973a301f9e85dfeb --- /dev/null +++ b/src/qututor/vqe/expand_gate.py @@ -0,0 +1,100 @@ +from typing import List +from math import log2 + +# from utils import remap_bits, gamma +import numpy as np + + +def get_bit(val, n): + """Get the n-th bit of val. + + No check is performed. + """ + return val >> n & 1 + + +def remap_bits(val, bit_pos_list): + """Remap the bits of val according to bit_pos_list, i.e., + $$ + \sum_{i=0}^{l - 1}{val\langle i\rangle \times 2^{bit_pos_list[i]}} + $$ + where, $val\langle i\rangle$ is the i-th bit of val. + """ + sum = 0 + for i in range(len(bit_pos_list)): + sum += get_bit(val, i) << bit_pos_list[i] + return sum + + +def gamma(t_val, t_qubits, o_val, o_qubits, c_val=0, c_qubits=[]): + """This function calculates the following value: + $$ + \Gamma(k,x)|_{\{o_0, o_1, \cdots, o_{l-1}\}, \{t_0, t_1, \cdots, t_{n-1}\}} = \sum_{i=0}^{l -1}{k\langle i\rangle \times 2^{o_i}} + \sum_{i=0}^{n-1}{x\langle i\rangle \times 2^{t_i}} + $$ + i.e., $\overline{o_{l-1}\cdots b_{n-1}o_{l-2}\cdots b_{n-2}\cdots b_{0}o_{0}}$. + This value is used in expanding a matrix when applying a gate on qubits. + + Parameters + ---------- + t_qubits : list of integers + a list of target qubits + o_qubits : list of integers + a list of other qubits + t_val : an integer value + it should have the same length as t_qubits + o_val : an integer value + it should have the same length as o_qubits + + Returns + ------- + integer + the value of $\Gamma(k,x)$ + """ + if c_qubits == []: + return remap_bits(o_val, o_qubits) + remap_bits(t_val, t_qubits) + else: + return ( + remap_bits(o_val, o_qubits) + + remap_bits(t_val, t_qubits) + + remap_bits(c_val, c_qubits) + ) + + +def expand_gate(num_qubits, core_mat: np.matrix, t_qubits: List[int]): + """ + Expand a gate to a matrix of the entire circuit. + The size of the matrix is determined by the total number of qubits in the circuit. + + Args: + num_qubits: The number of qubits in the circuit. + core_mat: The matrix of the gate to be expanded. + t_qubits: The target qubits of the gate. + """ + if log2(core_mat.shape[0]) != len(t_qubits): + raise ValueError("The number of qubits is not correct") + + o_qubits = [] + used_qubits = t_qubits + for i in range(num_qubits): + if i not in used_qubits: + o_qubits.append(i) + + num_target_qubits = len(t_qubits) + num_other_qubits = len(o_qubits) + + assert num_qubits == num_target_qubits + num_other_qubits + + new_mat_size = 2**num_qubits + new_mat = np.zeros((new_mat_size, new_mat_size), dtype=complex) + + for o_val in range(2**num_other_qubits): + for tgt_idx in range(2**num_target_qubits): + iden_idx = remap_bits(o_val, o_qubits) + remap_bits(tgt_idx, t_qubits) + new_mat[iden_idx, iden_idx] = 1 + + for t_val in range(2**num_target_qubits): + for i in range(2**num_target_qubits): + row_idx = gamma(t_val, t_qubits, o_val, o_qubits) + col_idx = gamma(i, t_qubits, o_val, o_qubits) + new_mat[row_idx, col_idx] = core_mat[t_val, i] + return np.matrix(new_mat) diff --git a/src/qututor/vqe/host.py b/src/qututor/vqe/host.py new file mode 100644 index 0000000000000000000000000000000000000000..5e1c4d0523b72963cd5e3e0699f1ad1f81015c2b --- /dev/null +++ b/src/qututor/vqe/host.py @@ -0,0 +1,99 @@ +from pathlib import Path +import matplotlib.pyplot as plt +from VQE import vqe +from ansatz import Ansatz_circuit +from Hamiltonian import Hamiltonian +from quingo import * + +bond_h_decompose = [ + [0.20, 2.8489, 0.5678, -1.4508, 0.6799, 0.0791, 0.0791], + [0.25, 2.1868, 0.5449, -1.2870, 0.6719, 0.0798, 0.0798], + [0.30, 1.7252, 0.5215, -1.1458, 0.6631, 0.0806, 0.0806], + [0.35, 1.3827, 0.4982, -1.0226, 0.6537, 0.0815, 0.0815], + [0.40, 1.1182, 0.4754, -0.9145, 0.6438, 0.0825, 0.0825], + [0.45, 0.9083, 0.4534, -0.8194, 0.6336, 0.0835, 0.0835], + [0.50, 0.7381, 0.4325, -0.7355, 0.6233, 0.0846, 0.0846], + [0.55, 0.5979, 0.4125, -0.6612, 0.6129, 0.0858, 0.0858], + [0.60, 0.4808, 0.3937, -0.5950, 0.6025, 0.0870, 0.0870], + [0.65, 0.3819, 0.3760, -0.5358, 0.5921, 0.0883, 0.0883], + [0.70, 0.2976, 0.3593, -0.4826, 0.5818, 0.0896, 0.0896], + [0.75, 0.2252, 0.3435, -0.4347, 0.5716, 0.0910, 0.0910], + [0.80, 0.1626, 0.3288, -0.3915, 0.5616, 0.0925, 0.0925], + [0.85, 0.1083, 0.3149, -0.3523, 0.5518, 0.0939, 0.0939], + [0.90, 0.0609, 0.3018, -0.3168, 0.5421, 0.0954, 0.0954], + [0.95, 0.0193, 0.2895, -0.2845, 0.5327, 0.0970, 0.0970], + [1.00, -0.0172, 0.2779, -0.2550, 0.5235, 0.0986, 0.0986], + [1.05, -0.0493, 0.2669, -0.2282, 0.5146, 0.1002, 0.1002], + [1.10, -0.0778, 0.2565, -0.2036, 0.5059, 0.1018, 0.1018], + [1.15, -0.1029, 0.2467, -0.1810, 0.4974, 0.1034, 0.1034], + [1.20, -0.1253, 0.2374, -0.1603, 0.4892, 0.1050, 0.1050], + [1.25, -0.1452, 0.2286, -0.1413, 0.4812, 0.1067, 0.1067], + [1.30, -0.1629, 0.2203, -0.1238, 0.4735, 0.1083, 0.1083], + [1.35, -0.1786, 0.2123, -0.1077, 0.4660, 0.1100, 0.1100], + [1.40, -0.1927, 0.2048, -0.0929, 0.4588, 0.1116, 0.1116], + [1.45, -0.2053, 0.1976, -0.0792, 0.4518, 0.1133, 0.1133], + [1.50, -0.2165, 0.1908, -0.0666, 0.4451, 0.1149, 0.1149], + [1.55, -0.2265, 0.1843, -0.0549, 0.4386, 0.1165, 0.1165], + [1.60, -0.2355, 0.1782, -0.0442, 0.4323, 0.1181, 0.1181], + [1.65, -0.2436, 0.1723, -0.0342, 0.4262, 0.1196, 0.1196], + [1.70, -0.2508, 0.1667, -0.0251, 0.4204, 0.1211, 0.1211], + [1.75, -0.2573, 0.1615, -0.0166, 0.4148, 0.1226, 0.1226], + [1.80, -0.2632, 0.1565, -0.0088, 0.4094, 0.1241, 0.1241], + [1.85, -0.2684, 0.1517, -0.0015, 0.4042, 0.1256, 0.1256], + [1.90, -0.2731, 0.1472, 0.0052, 0.3992, 0.1270, 0.1270], + [1.95, -0.2774, 0.1430, 0.0114, 0.3944, 0.1284, 0.1284], + [2.00, -0.2812, 0.1390, 0.0171, 0.3898, 0.1297, 0.1297], + [2.05, -0.2847, 0.1352, 0.0223, 0.3853, 0.1310, 0.1310], + [2.10, -0.2879, 0.1316, 0.0272, 0.3811, 0.1323, 0.1323], + [2.15, -0.2908, 0.1282, 0.0317, 0.3769, 0.1335, 0.1335], + [2.20, -0.2934, 0.1251, 0.0359, 0.3730, 0.1347, 0.1347], + [2.25, -0.2958, 0.1221, 0.0397, 0.3692, 0.1359, 0.1359], + [2.30, -0.2980, 0.1193, 0.0432, 0.3655, 0.1370, 0.1370], + [2.35, -0.3000, 0.1167, 0.0465, 0.3620, 0.1381, 0.1381], + [2.40, -0.3018, 0.1142, 0.0495, 0.3586, 0.1392, 0.1392], + [2.45, -0.3035, 0.1119, 0.0523, 0.3553, 0.1402, 0.1402], + [2.50, -0.3051, 0.1098, 0.0549, 0.3521, 0.1412, 0.1412], + [2.55, -0.3066, 0.1078, 0.0572, 0.3491, 0.1422, 0.1422], + [2.60, -0.3079, 0.1059, 0.0594, 0.3461, 0.1432, 0.1432], + [2.65, -0.3092, 0.1042, 0.0614, 0.3433, 0.1441, 0.1441], + [2.70, -0.3104, 0.1026, 0.0632, 0.3406, 0.1450, 0.1450], + [2.75, -0.3115, 0.1011, 0.0649, 0.3379, 0.1458, 0.1458], + [2.80, -0.3125, 0.0997, 0.0665, 0.3354, 0.1467, 0.1467], + [2.85, -0.3135, 0.0984, 0.0679, 0.3329, 0.1475, 0.1475], +] + + +def eval_all_vqe(): + bond_length = [] + lowest_energies = [] + paulis = ["II", "ZI", "IZ", "ZZ", "XX", "YY"] + qu_file = Path(__file__).parent / "kernel.qu" + circ_name = "ansatz" + num_theta = 2 + circ = Ansatz_circuit(qu_file, circ_name, num_theta) + for b in bond_h_decompose: + print("bond_length: {:1.3f}".format(b[0]), end=" ") + bond_length.append(b[0]) + coeffs = b[1:] + h = Hamiltonian(paulis, coeffs) + + # --------------- optimization based on searching --------------- + minimum = vqe( + circ, + h, + backend=BackendType.QUANTUM_SIM, + method="Nelder-Mead", + circ_cfg_file="./std_qcis.qfg", + ) + ground_state_energy = minimum.fun + print("energy: ", ground_state_energy) + lowest_energies.append(ground_state_energy) + + plt.plot(bond_length, lowest_energies, "b.-") + plt.xlabel("Bond Length") + plt.title("Variational Quantum Eigensolver") + plt.ylabel("Energy") + plt.show() + + +# eval_all_vqe() diff --git a/src/qututor/vqe/kernel.qu b/src/qututor/vqe/kernel.qu new file mode 100644 index 0000000000000000000000000000000000000000..08d664e70be46e6d1c2e1fbfdadae49a598015ca --- /dev/null +++ b/src/qututor/vqe/kernel.qu @@ -0,0 +1,37 @@ +opaque X(q: qubit) : unit; +opaque X2P(q: qubit) : unit; +opaque X2M(q: qubit) : unit; +opaque Y2P(q: qubit) : unit; +opaque Y2M(q: qubit) : unit; +opaque RZ(q: qubit, angle: double) : unit; + +opaque CZ(q1: qubit, q2: qubit) : unit; +opaque measure(q: qubit): bool; + +operation CNOT(a: qubit, b: qubit) : unit { + Y2M(b); + CZ(a, b); + Y2P(b); +} + +operation init(q: qubit): unit{ + X(q); +} + +operation ansatz(angle: double,angle2: double): unit { + using(q0: qubit, q1: qubit) { + init(q0); + + X2M(q0); + Y2P(q1); + CNOT(q1, q0); + RZ(q0, angle); + RZ(q1, angle2); + CNOT(q1, q0); + X2P(q0); + Y2M(q1); + } + +} + + diff --git a/src/qututor/vqe/std_qcis.qfg b/src/qututor/vqe/std_qcis.qfg new file mode 100644 index 0000000000000000000000000000000000000000..e7a3c21d2f4ca48df23cb5bf3f9fde1041a78436 --- /dev/null +++ b/src/qututor/vqe/std_qcis.qfg @@ -0,0 +1,498 @@ +{ + "op_list": [ + { + "op_name": "X", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 1, + 0, + 0 + ], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "Y", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 1, + 0 + ], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "Z", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 0, + 1 + ], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "RX", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "params": [ + { + "name": "angle", + "type": "double" + } + ], + "semantics": { + "type": "rotation", + "rot_axis": [ + 1, + 0, + 0 + ], + "rot_angle": "angle" + } + } + }, + { + "op_name": "arbRot", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0.6, + 0.8, + 0 + ], + "rot_angle": 1.5707963267948966 + } + } + }, + { + "op_name": "RY", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "params": [ + { + "name": "angle", + "type": "double" + } + ], + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 1, + 0 + ], + "rot_angle": "angle" + } + } + }, + { + "op_name": "RZ", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "params": [ + { + "name": "angle", + "type": "double" + } + ], + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 0, + 1 + ], + "rot_angle": "angle" + } + } + }, + { + "op_name": "H", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0.7071067811865476, + 0, + 0.7071067811865476 + ], + "rot_angle": 3.141592653589793, + "global_phase": 1.5707963267948966 + } + } + }, + { + "op_name": "CNOT", + "op_def": { + "num_target_qubits": 2, + "semantics": { + "type": "matrix", + "matrix": [ + [ + [ + 1, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + [ + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 1, + 0 + ] + ], + [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 0, + 0 + ] + ] + ] + } + } + }, + { + "op_name": "CZ", + "op_def": { + "num_target_qubits": 2, + "semantics": { + "type": "matrix", + "matrix": [ + [ + [ + 1, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + [ + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 0, + 0 + ] + ], + [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -1, + 0 + ] + ] + ] + } + } + }, + { + "op_name": "measure", + "op_def": { + "duration": 600e-9, + "num_target_qubits": 1, + "semantics": { + "type": "measure", + "return": "bool" + } + } + }, + { + "op_name": "SingleQubitGate", + "op_def": { + "num_target_qubits": 1, + "semantics": { + "type": "matrix", + "matrix": [ + [ + [ + 1, + 0 + ], + [ + 0, + 0 + ] + ], + [ + [ + 0, + 0 + ], + [ + 1, + 0 + ] + ] + ] + } + } + }, + { + "op_name": "X2P", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 1, + 0, + 0 + ], + "rot_angle": 1.5707963267948966, + "global_phase": 0 + } + } + }, + { + "op_name": "X2M", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 1, + 0, + 0 + ], + "rot_angle": -1.5707963267948966, + "global_phase": 0 + } + } + }, + { + "op_name": "Y2P", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 1, + 0 + ], + "rot_angle": 1.5707963267948966, + "global_phase": 0 + } + } + }, + { + "op_name": "Y2M", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 1, + 0 + ], + "rot_angle": -1.5707963267948966, + "global_phase": 0 + } + } + }, + { + "op_name": "S", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 0, + 1 + ], + "rot_angle": 1.5707963267948966, + "global_phase": -0.7853981633974483 + } + } + }, + { + "op_name": "SD", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 0, + 1 + ], + "rot_angle": -1.5707963267948966, + "global_phase": 0.7853981633974483 + } + } + }, + { + "op_name": "T", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 0, + 1 + ], + "rot_angle": 0.7853981633974483, + "global_phase": -0.3926990816987241 + } + } + }, + { + "op_name": "TD", + "op_def": { + "duration": 20e-9, + "num_target_qubits": 1, + "semantics": { + "type": "rotation", + "rot_axis": [ + 0, + 0, + 1 + ], + "rot_angle": -0.7853981633974483, + "global_phase": 0.3926990816987241 + } + } + } + ] +} \ No newline at end of file diff --git a/src/qututor/vqe/test.py b/src/qututor/vqe/test.py new file mode 100644 index 0000000000000000000000000000000000000000..1ba6ed4e7bb5de93ed673106f12aa1209d37f448 --- /dev/null +++ b/src/qututor/vqe/test.py @@ -0,0 +1,24 @@ +from pathlib import Path +from quingo import * + + + +# # get ansatz. + +qu_file = Path(__file__).parent / "test.qu" + +circ_name = "TwoLocal" + +qubit_number = 3 +rotation_blocks = [9,10] +entanglement_blocks = [2,10] +entanglement = 1 +reps = 2 +theta = [0.0]*20 +skip_final_rotation_layer = False + +params = (qubit_number, rotation_blocks, entanglement_blocks, entanglement, reps, theta, skip_final_rotation_layer) + +task = Quingo_task(qu_file, circ_name, debug_mode=True) +qasm_fn = compile(task, params) +res = execute(qasm_fn, backend, ExeConfig(ExeMode.SimStateVector)) diff --git a/src/qututor/vqe/test.qu b/src/qututor/vqe/test.qu new file mode 100644 index 0000000000000000000000000000000000000000..bf778124b76051c1f8a39ba71b3361aa98359f2e --- /dev/null +++ b/src/qututor/vqe/test.qu @@ -0,0 +1,115 @@ +import std_ops + +operation entanglement_layer_linear(q: qubit[], entanglement_blocks: int[], theta: double[], theta_count: int): int{ + int qubit_number = q.length; + for (int i = 0; i < qubit_number - 1; i += 1){ + for (int j = 0; j < entanglement_blocks.length; j += 1){ + if (entanglement_blocks[j] == 1){ + continue; + } + if (entanglement_blocks[j] == 2) { + ctrlX(q[i+1]); + } + if (entanglement_blocks[j] == 3) { + ctrlY(q[i+1]); + } + if (entanglement_blocks[j] == 4) { + ctrlZ(q[i+1]); + } + if (entanglement_blocks[j] == 5) { + ctrlS(q[i+1]); + } + if (entanglement_blocks[j] == 6) { + ctrlSdag(q[i+1]); + } + if (entanglement_blocks[j] == 7) { + ctrlT(q[i+1]); + } + if (entanglement_blocks[j] == 8) { + ctrlTdag(q[i+1]); + } + if (entanglement_blocks[j] == 9) { + ctrlH(q[i+1]); + } + if (entanglement_blocks[j] == 10) { + ctrlRx(q[i+1], theta[theta_count]); + theta_count += 1; + } + if (entanglement_blocks[j] == 11) { + ctrlRy(q[i+1], theta[theta_count]); + theta_count += 1; + } + if (entanglement_blocks[j] == 12) { + ctrlRz(q[i+1], theta[theta_count]); + theta_count += 1; + } + + + } + } + return theta_count; +} + +operation roration_layer(q: qubit[], rotation_blocks: int[], theta: double[], theta_count: int): int{ + int qubit_number = q.length; + for (int i = 0; i < qubit_number; i += 1){ + for (int j = 0; j < rotation_blocks.length; j += 1){ + if (rotation_blocks[j] == 1){ + continue; + } + if (rotation_blocks[j] == 2) { + X(q[i]); + } + if (rotation_blocks[j] == 3) { + Y(q[i]); + } + if (rotation_blocks[j] == 4) { + Z(q[i]); + } + if (rotation_blocks[j] == 5) { + S(q[i]); + } + if (rotation_blocks[j] == 6) { + Sdag(q[i]); + } + if (rotation_blocks[j] == 7) { + T(q[i]); + } + if (rotation_blocks[j] == 8) { + Tdag(q[i]); + } + if (rotation_blocks[j] == 9) { + H(q[i]); + } + if (rotation_blocks[j] == 10) { + Rx(q[i], theta[theta_count]); + theta_count += 1; + } + if (rotation_blocks[j] == 11) { + Ry(q[i], theta[theta_count]); + theta_count += 1; + } + if (rotation_blocks[j] == 12) { + Rz(q[i], theta[theta_count]); + theta_count += 1; + } + } + } + return theta_count; +} + +operation TwoLocal(qubit_number: int, rotation_blocks: int[], entanglement_blocks: int[], entanglement: int, reps: int, theta: double[], skip_final_rotation_layer: bool): unit { + using(q: qubit[qubit_number]) { + int theta_count = 0; + for (int i = 0; i < reps; i += 1) { + theta_count = roration_layer(q, rotation_blocks, theta, theta_count); + if (entanglement == 1){ + theta_count = entanglement_layer_linear(q, entanglement_blocks, theta, theta_count); + } + //todo + } + //if (skip_final_rotation_layer == false){ + theta_count = roration_layer(q, rotation_blocks, theta, theta_count); + //} + } +} \ No newline at end of file diff --git a/src/qututor/vqe/test_VQE.ipynb b/src/qututor/vqe/test_VQE.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..62ca9bd5480a39e75b360dbca029569d5ff384e8 --- /dev/null +++ b/src/qututor/vqe/test_VQE.ipynb @@ -0,0 +1,99 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from qututor.vqe.host import eval_all_vqe" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bond_length: 0.200 energy: 0.14421033394938315\n", + "bond_length: 0.250 energy: -0.3239392441860759\n", + "bond_length: 0.300 energy: 1.7640000006242817\n", + "bond_length: 0.350 energy: -0.800510260420718\n", + "bond_length: 0.400 energy: -0.925259604296447\n", + "bond_length: 0.450 energy: -1.0090090165899186\n", + "bond_length: 0.500 energy: 1.0584000001110159\n", + "bond_length: 0.550 energy: -1.1023261921031906\n", + "bond_length: 0.600 energy: -1.1255942617878536\n", + "bond_length: 0.650 energy: -1.1389447428202601\n", + "bond_length: 0.700 energy: -1.1449602739137452\n", + "bond_length: 0.750 energy: -1.1455991239275123\n", + "bond_length: 0.800 energy: -1.1426780816941224\n", + "bond_length: 0.850 energy: -1.1366267410185193\n", + "bond_length: 0.900 energy: -1.1285566246765792\n", + "bond_length: 0.950 energy: -1.1192976807017359\n", + "bond_length: 1.000 energy: -1.1089167276207026\n", + "bond_length: 1.050 " + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43meval_all_vqe\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/quingo-tutorials/src/qututor/vqe/host.py:81\u001b[0m, in \u001b[0;36meval_all_vqe\u001b[0;34m()\u001b[0m\n\u001b[1;32m 78\u001b[0m h \u001b[38;5;241m=\u001b[39m Hamiltonian(paulis, coeffs)\n\u001b[1;32m 80\u001b[0m \u001b[38;5;66;03m# --------------- optimization based on searching ---------------\u001b[39;00m\n\u001b[0;32m---> 81\u001b[0m minimum \u001b[38;5;241m=\u001b[39m \u001b[43mvqe\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 82\u001b[0m \u001b[43m \u001b[49m\u001b[43mcirc\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 83\u001b[0m \u001b[43m \u001b[49m\u001b[43mh\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 84\u001b[0m \u001b[43m \u001b[49m\u001b[43mbackend\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mBackendType\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mQUANTUM_SIM\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 85\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mNelder-Mead\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 86\u001b[0m \u001b[43m \u001b[49m\u001b[43mcirc_cfg_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m./std_qcis.qfg\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 87\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 88\u001b[0m ground_state_energy \u001b[38;5;241m=\u001b[39m minimum\u001b[38;5;241m.\u001b[39mfun\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124menergy: \u001b[39m\u001b[38;5;124m\"\u001b[39m, ground_state_energy)\n", + "File \u001b[0;32m~/quingo-tutorials/src/qututor/vqe/VQE.py:92\u001b[0m, in \u001b[0;36mvqe\u001b[0;34m(circ, hamiltonian, backend, method, circ_cfg_file)\u001b[0m\n\u001b[1;32m 90\u001b[0m theta \u001b[38;5;241m=\u001b[39m random\u001b[38;5;241m.\u001b[39muniform(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m np\u001b[38;5;241m.\u001b[39mpi)\n\u001b[1;32m 91\u001b[0m x1 \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39marray([theta] \u001b[38;5;241m*\u001b[39m circ\u001b[38;5;241m.\u001b[39mnum_params)\n\u001b[0;32m---> 92\u001b[0m minimum \u001b[38;5;241m=\u001b[39m \u001b[43mminimize\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfun\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mloss_func\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mx0\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mx1\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 93\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m minimum\n", + "File \u001b[0;32m~/anaconda3/envs/quingo/lib/python3.8/site-packages/scipy/optimize/_minimize.py:684\u001b[0m, in \u001b[0;36mminimize\u001b[0;34m(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)\u001b[0m\n\u001b[1;32m 681\u001b[0m bounds \u001b[38;5;241m=\u001b[39m standardize_bounds(bounds, x0, meth)\n\u001b[1;32m 683\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m meth \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnelder-mead\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[0;32m--> 684\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43m_minimize_neldermead\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfun\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mx0\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallback\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbounds\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbounds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 685\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 686\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m meth \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpowell\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 687\u001b[0m res \u001b[38;5;241m=\u001b[39m _minimize_powell(fun, x0, args, callback, bounds, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39moptions)\n", + "File \u001b[0;32m~/anaconda3/envs/quingo/lib/python3.8/site-packages/scipy/optimize/_optimize.py:907\u001b[0m, in \u001b[0;36m_minimize_neldermead\u001b[0;34m(func, x0, args, callback, maxiter, maxfev, disp, return_all, initial_simplex, xatol, fatol, adaptive, bounds, **unknown_options)\u001b[0m\n\u001b[1;32m 905\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m bounds \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 906\u001b[0m xcc \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mclip(xcc, lower_bound, upper_bound)\n\u001b[0;32m--> 907\u001b[0m fxcc \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mxcc\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 909\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m fxcc \u001b[38;5;241m<\u001b[39m fsim[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]:\n\u001b[1;32m 910\u001b[0m sim[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m] \u001b[38;5;241m=\u001b[39m xcc\n", + "File \u001b[0;32m~/anaconda3/envs/quingo/lib/python3.8/site-packages/scipy/optimize/_optimize.py:569\u001b[0m, in \u001b[0;36m_wrap_scalar_function_maxfun_validation..function_wrapper\u001b[0;34m(x, *wrapper_args)\u001b[0m\n\u001b[1;32m 567\u001b[0m ncalls[\u001b[38;5;241m0\u001b[39m] \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 568\u001b[0m \u001b[38;5;66;03m# A copy of x is sent to the user function (gh13740)\u001b[39;00m\n\u001b[0;32m--> 569\u001b[0m fx \u001b[38;5;241m=\u001b[39m \u001b[43mfunction\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcopy\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mwrapper_args\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 570\u001b[0m \u001b[38;5;66;03m# Ideally, we'd like to a have a true scalar returned from f(x). For\u001b[39;00m\n\u001b[1;32m 571\u001b[0m \u001b[38;5;66;03m# backwards-compatibility, also allow np.array([1.3]),\u001b[39;00m\n\u001b[1;32m 572\u001b[0m \u001b[38;5;66;03m# np.array([[1.3]]) etc.\u001b[39;00m\n\u001b[1;32m 573\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m np\u001b[38;5;241m.\u001b[39misscalar(fx):\n", + "File \u001b[0;32m~/quingo-tutorials/src/qututor/vqe/VQE.py:88\u001b[0m, in \u001b[0;36mvqe..loss_func\u001b[0;34m(params)\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mloss_func\u001b[39m(params):\n\u001b[0;32m---> 88\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43menergy_theta\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcirc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mhamiltonian\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbackend\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcirc_cfg_file\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mA[\u001b[38;5;241m0\u001b[39m][\u001b[38;5;241m0\u001b[39m]\n", + "File \u001b[0;32m~/quingo-tutorials/src/qututor/vqe/VQE.py:72\u001b[0m, in \u001b[0;36menergy_theta\u001b[0;34m(circ, params, hamiltonian, backend, config_file)\u001b[0m\n\u001b[1;32m 70\u001b[0m circ\u001b[38;5;241m.\u001b[39mwith_backend(backend)\n\u001b[1;32m 71\u001b[0m circ\u001b[38;5;241m.\u001b[39mwith_config_file(config_file)\n\u001b[0;32m---> 72\u001b[0m ansatz_state \u001b[38;5;241m=\u001b[39m \u001b[43mcirc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_ansatz\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 73\u001b[0m h \u001b[38;5;241m=\u001b[39m hamiltonian\u001b[38;5;241m.\u001b[39mto_matrix()\n\u001b[1;32m 74\u001b[0m energy \u001b[38;5;241m=\u001b[39m expectation(h, ansatz_state)\n", + "File \u001b[0;32m~/quingo-tutorials/src/qututor/vqe/ansatz.py:40\u001b[0m, in \u001b[0;36mAnsatz_circuit.get_ansatz\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_ansatz\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[1;32m 39\u001b[0m task \u001b[38;5;241m=\u001b[39m Quingo_task(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mqu_file, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcirc_name, debug_mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[0;32m---> 40\u001b[0m qasm_fn \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mcompile\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mtask\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig_file\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfig_file\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 41\u001b[0m res \u001b[38;5;241m=\u001b[39m execute(qasm_fn, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbackend, ExeConfig(ExeMode\u001b[38;5;241m.\u001b[39mSimStateVector))\n\u001b[1;32m 42\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m res[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquantum\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;241m1\u001b[39m]\n", + "File \u001b[0;32m~/quingo-runtime/src/quingo/core/compile.py:31\u001b[0m, in \u001b[0;36mcompile\u001b[0;34m(task, params, qasm_fn, config_file)\u001b[0m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m task\u001b[38;5;241m.\u001b[39mdebug_mode:\n\u001b[1;32m 30\u001b[0m logger\u001b[38;5;241m.\u001b[39minfo(compile_cmd)\n\u001b[0;32m---> 31\u001b[0m ret_value \u001b[38;5;241m=\u001b[39m \u001b[43msubprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 32\u001b[0m \u001b[43m \u001b[49m\u001b[43mcompile_cmd\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 33\u001b[0m \u001b[43m \u001b[49m\u001b[43mstdout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msubprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 34\u001b[0m \u001b[43m \u001b[49m\u001b[43mstderr\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msubprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mPIPE\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 35\u001b[0m \u001b[43m \u001b[49m\u001b[43mtext\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 36\u001b[0m \u001b[43m \u001b[49m\u001b[43mshell\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 37\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m ret_value\u001b[38;5;241m.\u001b[39mstdout \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 39\u001b[0m logger\u001b[38;5;241m.\u001b[39minfo(ret_value\u001b[38;5;241m.\u001b[39mstdout\u001b[38;5;241m.\u001b[39mstrip())\n", + "File \u001b[0;32m~/anaconda3/envs/quingo/lib/python3.8/subprocess.py:495\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(input, capture_output, timeout, check, *popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 493\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m Popen(\u001b[38;5;241m*\u001b[39mpopenargs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs) \u001b[38;5;28;01mas\u001b[39;00m process:\n\u001b[1;32m 494\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 495\u001b[0m stdout, stderr \u001b[38;5;241m=\u001b[39m \u001b[43mprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcommunicate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 496\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m TimeoutExpired \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[1;32m 497\u001b[0m process\u001b[38;5;241m.\u001b[39mkill()\n", + "File \u001b[0;32m~/anaconda3/envs/quingo/lib/python3.8/subprocess.py:1028\u001b[0m, in \u001b[0;36mPopen.communicate\u001b[0;34m(self, input, timeout)\u001b[0m\n\u001b[1;32m 1025\u001b[0m endtime \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1027\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 1028\u001b[0m stdout, stderr \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_communicate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mendtime\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1029\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[1;32m 1030\u001b[0m \u001b[38;5;66;03m# https://bugs.python.org/issue25942\u001b[39;00m\n\u001b[1;32m 1031\u001b[0m \u001b[38;5;66;03m# See the detailed comment in .wait().\u001b[39;00m\n\u001b[1;32m 1032\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m timeout \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", + "File \u001b[0;32m~/anaconda3/envs/quingo/lib/python3.8/subprocess.py:1884\u001b[0m, in \u001b[0;36mPopen._communicate\u001b[0;34m(self, input, endtime, orig_timeout)\u001b[0m\n\u001b[1;32m 1877\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_timeout(endtime, orig_timeout,\n\u001b[1;32m 1878\u001b[0m stdout, stderr,\n\u001b[1;32m 1879\u001b[0m skip_check_and_raise\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n\u001b[1;32m 1880\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m( \u001b[38;5;66;03m# Impossible :)\u001b[39;00m\n\u001b[1;32m 1881\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m_check_timeout(..., skip_check_and_raise=True) \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 1882\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mfailed to raise TimeoutExpired.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m-> 1884\u001b[0m ready \u001b[38;5;241m=\u001b[39m \u001b[43mselector\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mselect\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1885\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_timeout(endtime, orig_timeout, stdout, stderr)\n\u001b[1;32m 1887\u001b[0m \u001b[38;5;66;03m# XXX Rewrite these to use non-blocking I/O on the file\u001b[39;00m\n\u001b[1;32m 1888\u001b[0m \u001b[38;5;66;03m# objects; they are no longer using C stdio!\u001b[39;00m\n", + "File \u001b[0;32m~/anaconda3/envs/quingo/lib/python3.8/selectors.py:415\u001b[0m, in \u001b[0;36m_PollLikeSelector.select\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 413\u001b[0m ready \u001b[38;5;241m=\u001b[39m []\n\u001b[1;32m 414\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 415\u001b[0m fd_event_list \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_selector\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpoll\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 416\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mInterruptedError\u001b[39;00m:\n\u001b[1;32m 417\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m ready\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "eval_all_vqe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "quingo", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.17" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}