From 1492e61972d8a7fc1ccf3c155bc79033e3be332f Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Tue, 19 Jul 2022 15:34:19 +0800 Subject: [PATCH 01/39] Adding the first version of qibo's qasm tested with Quimb backend --- src/qibotn/test_qasm_quimb_backend.py | 275 ++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 src/qibotn/test_qasm_quimb_backend.py diff --git a/src/qibotn/test_qasm_quimb_backend.py b/src/qibotn/test_qasm_quimb_backend.py new file mode 100644 index 0000000..2e7e0a2 --- /dev/null +++ b/src/qibotn/test_qasm_quimb_backend.py @@ -0,0 +1,275 @@ +import random +from turtle import delay +import quimb as qu +import quimb.tensor as qtn +import numpy as np +import re + +from timeit import default_timer as timer +import cirq + +nqubits = 18 + +# define dictionary +gate_dict_cirq = { + #'i': I, + 'h': cirq.H, + 't': cirq.T, + #'z': Z, + 'cz': cirq.CZ, + #'cX': cX, + #'rz': ZPhase, + #'rX': XPhase, + #'x': X, + #'y': Y, + 'x_1_2': cirq.rx(0.5*np.pi), + 'y_1_2': cirq.ry(0.5*np.pi) + #'hz_1_2': W_1_2, + #'fs': fSim +} + +# search 'GATE_FUNCTIONS' in Source code for quimb.tensor.circuit for pre-defined gates in quimb +gate_dict = { + #'i': I, + 'h': 'H', + 't': 'T', + #'z': Z, + 'cz': 'cZ', + #'cX': cX, + #'rz': ZPhase, + #'rX': XPhase, + #'x': X, + #'y': Y, + 'x_1_2': 'X_1_2', + 'y_1_2': 'Y_1_2' +} + + +def QI_QFT(nqubits: int, with_swaps: bool = True, psi0 = None): + ## constructs qft circuit + #from qibo import gates + #circuit = Circuit(nqubits) + circ = qtn.Circuit(nqubits, psi0 = psi0) + + for i1 in range(nqubits): + #circuit.add(gates.H(i1)) + circ.apply_gate('H', i1) + for i2 in range(i1 + 1, nqubits): + theta = np.pi / 2 ** (i2 - i1) + #circuit.add(gates.CU1(i2, i1, theta)) + circ.apply_gate('CU1', theta, i2, i1) + + if with_swaps: + for i in range(nqubits // 2): + #circuit.add(gates.SWAP(i, nqubits - i - 1)) + circ.apply_gate('SWAP', i, nqubits - i - 1) + + return circ + +def get_gate_params(operation): + if "h" in operation: + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no.insert(0, "H") + elif "x" in operation: + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no.insert(0, "X") + elif "y" in operation: + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no.insert(0, "Y") + elif "z" in operation: + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no.insert(0, "Z") + elif "s" in operation: + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no.insert(0, "S") + elif "t" in operation: + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no.insert(0, "T") + elif "cu1" in operation: + lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', + operation.split(" ")[0]))) + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["CU1", lamda] + elif "cu2" in operation: + angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) + phi = float('.'.join(angles[0:2])) + lamba = float('.'.join(angles[2:])) + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["CU2", phi, lamda] + elif "cu3" in operation: + angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) + theta = float('.'.join(angles[0:2])) + phi = float('.'.join(angles[2:4])) + lamba = float('.'.join(angles[4:])) + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["CU3", theta, phi, lamda] + elif "cx" in operation: + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CX") + elif "cy" in operation: + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CY") + elif "cz" in operation: + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CZ") + elif "rx" in operation: + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', + operation.split(" ")[0]))) + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no[0:0] = ["RX", theta] + elif "ry" in operation: + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', + operation.split(" ")[0]))) + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no[0:0] = ["RY", theta] + elif "rz" in operation: + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', + operation.split(" ")[0]))) + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no[0:0] = ["RZ", theta] + elif "rzz" in operation: + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', + operation.split(" ")[0]))) + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["RZZ", theta] + elif "u1" in operation: + lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', + operation.split(" ")[0]))) + qbit_no = [int(re.findall(r'\d+', operation)[0])] + qbit_no[0:0] = ["U1", lamda] + elif "u2" in operation: + angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) + phi = float('.'.join(angles[0:2])) + lamba = float('.'.join(angles[2:])) + qbit_no = int(re.findall(r'\d+', operation)[0]) + qbit_no[0:0] = ["U2", phi, lamda] + elif "u3" in operation: + angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) + theta = float('.'.join(angles[0:2])) + phi = float('.'.join(angles[2:4])) + lamba = float('.'.join(angles[4:])) + qbit_no = int(re.findall(r'\d+', operation)[0]) + qbit_no[0:0] = ["U3", theta, phi, lamda] + else: + assert("Unsupported gate") + + return qbit_no + + +def get_gate_functions(qasm_str, start_idx): + # func_list = [] + # param_list = {} + # for line in qasm_str[start_idx:]: + # if "gate" in line: + # line = line.split(" ") + # for i in line[3:]: + # if ',' in i: + # params = i.split(",") + # param_list.append([int(j) for j in params]) + # elif "(" in i: + # params = re.findall(r'\w+', i) + # param_list.append([int(j) for j in params]) + # elif "{" in i: + # break + # elif "}" in line: + # return func_list + # else: + # func_list.append(line) + pass + +def qasm_QFT(nqubits:int, qasm_str:str, with_swaps: bool = True, psi0 = None): + circ = qtn.Circuit(nqubits, psi0 = psi0) + # circ = qtn.Circuit.qasm(nqubits, psi0 = psi0) + gate_functions = {} + qasm_str = qasm_str.split('\n') + for idx, line in enumerate(qasm_str): + command = line.split(" ")[0] + if re.search("include|//|OPENQASM", command): + continue + elif "qreg" in command: + nbits = int(re.findall(r'\d+', line)[0]) + assert(nbits == nqubits) + elif "swap" in command: + break + elif "gate" in command: # TODO: Complete gate handling + gate_name = line.split(" ")[1] + # gate_func = get_gate_functions(qasm_str, idx) + # gate_funtions[gate_name] = gate_func + pass + elif "barrier" in command: # TODO: Complete barrier handling + pass + elif "measure" in command: # TODO: Complete measure handling + pass + else: + params = get_gate_params(line) + circ.apply_gate(*params) + + if with_swaps: + for i in range(nqubits // 2): # TODO: Ignore the barrier indices? + circ.apply_gate('SWAP', i, nqubits - i - 1) + + return circ + + +def eval_QI_qft(nqubits, bond_dim=0, backend='numpy', qibo_backend='numpy', + with_swaps=True, compare_qibo=False): + # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. + # qibo_backend: qibojit, qibotf, tensorflow, numpy + + # generate random statevector as initial state + init_state = np.random.random(2 ** nqubits) + 1j + * np.random.random(2 ** nqubits) + init_state = init_state / np.sqrt((np.abs(init_state)**2).sum()) + + # Qibo part + if compare_qibo==True: + import qibo + qibo.set_backend(qibo_backend) + # qibo.set_backend(backend="qibojit", platform="numba") + from qibo.models import QFT as qibo_qft + start = timer() + circ_qibo = qibo_qft(nqubits, with_swaps) + amplitudes_reference = np.array(circ_qibo(init_state)) + end = timer() + print("qibo time is " + str(end-start)) + qasm_circ = circ_qibo.to_qasm() + + + ##################################################################### + + # Quimb part + qtn.tensor_core.set_contract_backend(backend) + ## convert vector to MPS + dims = tuple(2*np.ones(nqubits, dtype=int)) + start = timer() + init_state_MPS = + qtn.tensor_1d.MatrixProductState.from_dense(init_state, dims) + end = timer() + MPS_time = end-start + # print('MPS conversion time: ', MPS_time) + + # construct quimb qft circuit + start = timer() + if compare_qibo == True: + circ_quimb = + qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) + else: + circ_quimb = QI_QFT(nqubits, with_swaps, psi0=init_state_MPS) + + result = circ_quimb.to_dense(backend=backend) + amplitudes = result.flatten() + end = timer() + quimb_qft_time = end-start + print("quimb time is " + str(quimb_qft_time)) + assert(np.allclose(amplitudes,amplitudes_reference)) + +if __name__ == '__main__': + print("Testing for %d nqubits" % (nqubits)) + result = eval_QI_qft(nqubits, compare_qibo=True) \ No newline at end of file From 2fb08c51edd66d891d957fc9c36753bd772d31a2 Mon Sep 17 00:00:00 2001 From: yangliwei Date: Thu, 21 Jul 2022 14:15:49 +0800 Subject: [PATCH 02/39] Add the circuit comparison notebook. --- src/qibotn/qibo2quimb.ipynb | 301 ++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 src/qibotn/qibo2quimb.ipynb diff --git a/src/qibotn/qibo2quimb.ipynb b/src/qibotn/qibo2quimb.ipynb new file mode 100644 index 0000000..1a18866 --- /dev/null +++ b/src/qibotn/qibo2quimb.ipynb @@ -0,0 +1,301 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "quimb version: 1.4.0\n" + ] + } + ], + "source": [ + "import argparse\n", + "from timeit import default_timer as timer\n", + "\n", + "import quimb as qu\n", + "from qiskit import QuantumCircuit\n", + "\n", + "from qibo import __version__, gates, tests\n", + "from qibo.models import Circuit, QFT\n", + "from qibo.tests.utils import random_state\n", + "\n", + "print('quimb version:', qu.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Testing for 8 qubits\n", + "qibo QFT circuit:\n", + "q0: ─H─U1─U1─U1─U1─U1─U1─U1─────────────────────────────────────────────── ...\n", + "q1: ───o──|──|──|──|──|──|──H─U1─U1─U1─U1─U1─U1─────────────────────────── ...\n", + "q2: ──────o──|──|──|──|──|────o──|──|──|──|──|──H─U1─U1─U1─U1─U1────────── ...\n", + "q3: ─────────o──|──|──|──|───────o──|──|──|──|────o──|──|──|──|──H─U1─U1─U ...\n", + "q4: ────────────o──|──|──|──────────o──|──|──|───────o──|──|──|────o──|──| ...\n", + "q5: ───────────────o──|──|─────────────o──|──|──────────o──|──|───────o──| ...\n", + "q6: ──────────────────o──|────────────────o──|─────────────o──|──────────o ...\n", + "q7: ─────────────────────o───────────────────o────────────────o─────────── ...\n", + "\n", + "q0: ... ───────────────────────────────x───────\n", + "q1: ... ───────────────────────────────|─x─────\n", + "q2: ... ───────────────────────────────|─|─x───\n", + "q3: ... 1─U1───────────────────────────|─|─|─x─\n", + "q4: ... ──|──H─U1─U1─U1────────────────|─|─|─x─\n", + "q5: ... ──|────o──|──|──H─U1─U1────────|─|─x───\n", + "q6: ... ──|───────o──|────o──|──H─U1───|─x─────\n", + "q7: ... ──o──────────o───────o────o──H─x───────\n", + "\n", + "qiskit QFT circuit:\n" + ] + }, + { + "data": { + "text/html": [ + "
     ┌───┐                                                            »\n",
+       "q_0: ┤ H ├─■──────────────■───────────────────■───────────────────────»\n",
+       "     └───┘ │U1(π/2) ┌───┐ │                   │                       »\n",
+       "q_1: ──────■────────┤ H ├─┼─────────■─────────┼──────────────■────────»\n",
+       "                    └───┘ │U1(π/4)  │U1(π/2)  │        ┌───┐ │        »\n",
+       "q_2: ─────────────────────■─────────■─────────┼────────┤ H ├─┼────────»\n",
+       "                                              │U1(π/8) └───┘ │U1(π/4) »\n",
+       "q_3: ─────────────────────────────────────────■──────────────■────────»\n",
+       "                                                                      »\n",
+       "q_4: ─────────────────────────────────────────────────────────────────»\n",
+       "                                                                      »\n",
+       "q_5: ─────────────────────────────────────────────────────────────────»\n",
+       "                                                                      »\n",
+       "q_6: ─────────────────────────────────────────────────────────────────»\n",
+       "                                                                      »\n",
+       "q_7: ─────────────────────────────────────────────────────────────────»\n",
+       "                                                                      »\n",
+       "«                                                                         »\n",
+       "«q_0: ─■──────────────────────────────■───────────────────────────────────»\n",
+       "«      │                              │                                   »\n",
+       "«q_1: ─┼────────────────────■─────────┼─────────────────────────■─────────»\n",
+       "«      │                    │         │                         │         »\n",
+       "«q_2: ─┼──────────■─────────┼─────────┼───────────────■─────────┼─────────»\n",
+       "«      │          │U1(π/2)  │         │         ┌───┐ │         │         »\n",
+       "«q_3: ─┼──────────■─────────┼─────────┼─────────┤ H ├─┼─────────┼─────────»\n",
+       "«      │U1(π/16)            │U1(π/8)  │         └───┘ │U1(π/4)  │         »\n",
+       "«q_4: ─■────────────────────■─────────┼───────────────■─────────┼─────────»\n",
+       "«                                     │U1(π/32)                 │U1(π/16) »\n",
+       "«q_5: ────────────────────────────────■─────────────────────────■─────────»\n",
+       "«                                                                         »\n",
+       "«q_6: ────────────────────────────────────────────────────────────────────»\n",
+       "«                                                                         »\n",
+       "«q_7: ────────────────────────────────────────────────────────────────────»\n",
+       "«                                                                         »\n",
+       "«                                                                          »\n",
+       "«q_0: ─■─────────────────────────────────────────■─────────────────────────»\n",
+       "«      │                                         │                         »\n",
+       "«q_1: ─┼──────────────────────────────■──────────┼─────────────────────────»\n",
+       "«      │                              │          │                         »\n",
+       "«q_2: ─┼────────────────────■─────────┼──────────┼─────────────────────────»\n",
+       "«      │                    │         │          │                         »\n",
+       "«q_3: ─┼──────────■─────────┼─────────┼──────────┼────────────────■────────»\n",
+       "«      │          │U1(π/2)  │         │          │          ┌───┐ │        »\n",
+       "«q_4: ─┼──────────■─────────┼─────────┼──────────┼──────────┤ H ├─┼────────»\n",
+       "«      │                    │U1(π/8)  │          │          └───┘ │U1(π/4) »\n",
+       "«q_5: ─┼────────────────────■─────────┼──────────┼────────────────■────────»\n",
+       "«      │U1(π/64)                      │U1(π/32)  │                         »\n",
+       "«q_6: ─■──────────────────────────────■──────────┼─────────────────────────»\n",
+       "«                                                │U1(π/128)                »\n",
+       "«q_7: ───────────────────────────────────────────■─────────────────────────»\n",
+       "«                                                                          »\n",
+       "«                                                                         »\n",
+       "«q_0: ────────────────────────────────────────────────────────────────────»\n",
+       "«                                                                         »\n",
+       "«q_1: ────────────■───────────────────────────────────────────────────────»\n",
+       "«                 │                                                       »\n",
+       "«q_2: ─■──────────┼──────────────────────────────■────────────────────────»\n",
+       "«      │          │                              │                        »\n",
+       "«q_3: ─┼──────────┼────────────────────■─────────┼────────────────────────»\n",
+       "«      │          │                    │         │                        »\n",
+       "«q_4: ─┼──────────┼──────────■─────────┼─────────┼───────────────■────────»\n",
+       "«      │          │          │U1(π/2)  │         │         ┌───┐ │        »\n",
+       "«q_5: ─┼──────────┼──────────■─────────┼─────────┼─────────┤ H ├─┼────────»\n",
+       "«      │U1(π/16)  │                    │U1(π/8)  │         └───┘ │U1(π/4) »\n",
+       "«q_6: ─■──────────┼────────────────────■─────────┼───────────────■────────»\n",
+       "«                 │U1(π/64)                      │U1(π/32)                »\n",
+       "«q_7: ────────────■──────────────────────────────■────────────────────────»\n",
+       "«                                                                         »\n",
+       "«                                                                     \n",
+       "«q_0: ──────────────────────────────────────────────────────────────X─\n",
+       "«                                                                   │ \n",
+       "«q_1: ──────────────────────────────────────────────────────────X───┼─\n",
+       "«                                                               │   │ \n",
+       "«q_2: ──────────────────────────────────────────────────X───────┼───┼─\n",
+       "«                                                       │       │   │ \n",
+       "«q_3: ─■───────────────────────────────X────────────────┼───────┼───┼─\n",
+       "«      │                               │                │       │   │ \n",
+       "«q_4: ─┼────────────────────■──────────X────────────────┼───────┼───┼─\n",
+       "«      │                    │                           │       │   │ \n",
+       "«q_5: ─┼──────────■─────────┼──────────────■────────────X───────┼───┼─\n",
+       "«      │          │U1(π/2)  │        ┌───┐ │                    │   │ \n",
+       "«q_6: ─┼──────────■─────────┼────────┤ H ├─┼─────────■──────────X───┼─\n",
+       "«      │U1(π/16)            │U1(π/8) └───┘ │U1(π/4)  │U1(π/2) ┌───┐ │ \n",
+       "«q_7: ─■────────────────────■──────────────■─────────■────────┤ H ├─X─\n",
+       "«                                                             └───┘   
" + ], + "text/plain": [ + " ┌───┐ »\n", + "q_0: ┤ H ├─■──────────────■───────────────────■───────────────────────»\n", + " └───┘ │U1(π/2) ┌───┐ │ │ »\n", + "q_1: ──────■────────┤ H ├─┼─────────■─────────┼──────────────■────────»\n", + " └───┘ │U1(π/4) │U1(π/2) │ ┌───┐ │ »\n", + "q_2: ─────────────────────■─────────■─────────┼────────┤ H ├─┼────────»\n", + " │U1(π/8) └───┘ │U1(π/4) »\n", + "q_3: ─────────────────────────────────────────■──────────────■────────»\n", + " »\n", + "q_4: ─────────────────────────────────────────────────────────────────»\n", + " »\n", + "q_5: ─────────────────────────────────────────────────────────────────»\n", + " »\n", + "q_6: ─────────────────────────────────────────────────────────────────»\n", + " »\n", + "q_7: ─────────────────────────────────────────────────────────────────»\n", + " »\n", + "« »\n", + "«q_0: ─■──────────────────────────────■───────────────────────────────────»\n", + "« │ │ »\n", + "«q_1: ─┼────────────────────■─────────┼─────────────────────────■─────────»\n", + "« │ │ │ │ »\n", + "«q_2: ─┼──────────■─────────┼─────────┼───────────────■─────────┼─────────»\n", + "« │ │U1(π/2) │ │ ┌───┐ │ │ »\n", + "«q_3: ─┼──────────■─────────┼─────────┼─────────┤ H ├─┼─────────┼─────────»\n", + "« │U1(π/16) │U1(π/8) │ └───┘ │U1(π/4) │ »\n", + "«q_4: ─■────────────────────■─────────┼───────────────■─────────┼─────────»\n", + "« │U1(π/32) │U1(π/16) »\n", + "«q_5: ────────────────────────────────■─────────────────────────■─────────»\n", + "« »\n", + "«q_6: ────────────────────────────────────────────────────────────────────»\n", + "« »\n", + "«q_7: ────────────────────────────────────────────────────────────────────»\n", + "« »\n", + "« »\n", + "«q_0: ─■─────────────────────────────────────────■─────────────────────────»\n", + "« │ │ »\n", + "«q_1: ─┼──────────────────────────────■──────────┼─────────────────────────»\n", + "« │ │ │ »\n", + "«q_2: ─┼────────────────────■─────────┼──────────┼─────────────────────────»\n", + "« │ │ │ │ »\n", + "«q_3: ─┼──────────■─────────┼─────────┼──────────┼────────────────■────────»\n", + "« │ │U1(π/2) │ │ │ ┌───┐ │ »\n", + "«q_4: ─┼──────────■─────────┼─────────┼──────────┼──────────┤ H ├─┼────────»\n", + "« │ │U1(π/8) │ │ └───┘ │U1(π/4) »\n", + "«q_5: ─┼────────────────────■─────────┼──────────┼────────────────■────────»\n", + "« │U1(π/64) │U1(π/32) │ »\n", + "«q_6: ─■──────────────────────────────■──────────┼─────────────────────────»\n", + "« │U1(π/128) »\n", + "«q_7: ───────────────────────────────────────────■─────────────────────────»\n", + "« »\n", + "« »\n", + "«q_0: ────────────────────────────────────────────────────────────────────»\n", + "« »\n", + "«q_1: ────────────■───────────────────────────────────────────────────────»\n", + "« │ »\n", + "«q_2: ─■──────────┼──────────────────────────────■────────────────────────»\n", + "« │ │ │ »\n", + "«q_3: ─┼──────────┼────────────────────■─────────┼────────────────────────»\n", + "« │ │ │ │ »\n", + "«q_4: ─┼──────────┼──────────■─────────┼─────────┼───────────────■────────»\n", + "« │ │ │U1(π/2) │ │ ┌───┐ │ »\n", + "«q_5: ─┼──────────┼──────────■─────────┼─────────┼─────────┤ H ├─┼────────»\n", + "« │U1(π/16) │ │U1(π/8) │ └───┘ │U1(π/4) »\n", + "«q_6: ─■──────────┼────────────────────■─────────┼───────────────■────────»\n", + "« │U1(π/64) │U1(π/32) »\n", + "«q_7: ────────────■──────────────────────────────■────────────────────────»\n", + "« »\n", + "« \n", + "«q_0: ──────────────────────────────────────────────────────────────X─\n", + "« │ \n", + "«q_1: ──────────────────────────────────────────────────────────X───┼─\n", + "« │ │ \n", + "«q_2: ──────────────────────────────────────────────────X───────┼───┼─\n", + "« │ │ │ \n", + "«q_3: ─■───────────────────────────────X────────────────┼───────┼───┼─\n", + "« │ │ │ │ │ \n", + "«q_4: ─┼────────────────────■──────────X────────────────┼───────┼───┼─\n", + "« │ │ │ │ │ \n", + "«q_5: ─┼──────────■─────────┼──────────────■────────────X───────┼───┼─\n", + "« │ │U1(π/2) │ ┌───┐ │ │ │ \n", + "«q_6: ─┼──────────■─────────┼────────┤ H ├─┼─────────■──────────X───┼─\n", + "« │U1(π/16) │U1(π/8) └───┘ │U1(π/4) │U1(π/2) ┌───┐ │ \n", + "«q_7: ─■────────────────────■──────────────■─────────■────────┤ H ├─X─\n", + "« └───┘ " + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "num_qubits = 6\n", + "\n", + "print('Testing for {} qubits'.format(num_qubits))\n", + "\n", + "# generate the initial state\n", + "initial_state = random_state(num_qubits)\n", + "\n", + "# get the qibo circuit, convert it to a qasm circuit\n", + "start = timer()\n", + "qibo_qft_circuit = QFT(num_qubits)\n", + "final_state = qibo_qft_circuit(initial_state)\n", + "end = timer()\n", + "\n", + "# print(qibo_qft_circuit.summary())\n", + "print('qibo QFT circuit:')\n", + "print(qibo_qft_circuit.draw())\n", + "# print(final_state.state())\n", + "# print(\"qibo execution time is \" + str(end - start))\n", + "\n", + "# convert the circuit format from qibo to qasm\n", + "qasm_qft_circuit = qibo_qft_circuit.to_qasm()\n", + "\n", + "# convert the circuit format from qasm to qiskit\n", + "qiskit_qft_circuit = QuantumCircuit.from_qasm_str(qasm_qft_circuit)\n", + "print('\\nqiskit QFT circuit:')\n", + "qiskit_qft_circuit.draw()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.13 64-bit ('3.8.13')", + "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.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "ad6a7ef27ab1ef63a56400052d1dab463d164a7bc59eb0569183e19f112dd87c" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 7554086d6efbd3ecd07c0a65073561df803f3aa1 Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Fri, 3 Feb 2023 13:50:53 +0800 Subject: [PATCH 03/39] Add argparse for parsing args, do clean-up. --- src/qibotn/test_qasm_quimb_backend.py | 140 ++++++++++++++------------ 1 file changed, 77 insertions(+), 63 deletions(-) diff --git a/src/qibotn/test_qasm_quimb_backend.py b/src/qibotn/test_qasm_quimb_backend.py index 2e7e0a2..55447c9 100644 --- a/src/qibotn/test_qasm_quimb_backend.py +++ b/src/qibotn/test_qasm_quimb_backend.py @@ -1,15 +1,15 @@ -import random -from turtle import delay +import argparse import quimb as qu import quimb.tensor as qtn import numpy as np -import re +import re, copy + +import qibo +from qibo.models import QFT as qibo_qft from timeit import default_timer as timer import cirq -nqubits = 18 - # define dictionary gate_dict_cirq = { #'i': I, @@ -67,22 +67,22 @@ def QI_QFT(nqubits: int, with_swaps: bool = True, psi0 = None): return circ def get_gate_params(operation): - if "h" in operation: + if "h " in operation: qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no.insert(0, "H") - elif "x" in operation: + elif "x " in operation: qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no.insert(0, "X") - elif "y" in operation: + elif "y " in operation: qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no.insert(0, "Y") - elif "z" in operation: + elif "z " in operation: qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no.insert(0, "Z") - elif "s" in operation: + elif "s " in operation: qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no.insert(0, "S") - elif "t" in operation: + elif "t " in operation: qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no.insert(0, "T") elif "cu1" in operation: @@ -106,51 +106,63 @@ def get_gate_params(operation): qbit_no = re.findall(r'\d+', operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no[0:0] = ["CU3", theta, phi, lamda] - elif "cx" in operation: + elif " cx " in operation: qbit_no = re.findall(r'\d+', operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no.insert(0, "CX") - elif "cy" in operation: + elif " cy " in operation: qbit_no = re.findall(r'\d+', operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no.insert(0, "CY") - elif "cz" in operation: + elif " cz " in operation: qbit_no = re.findall(r'\d+', operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no.insert(0, "CZ") - elif "rx" in operation: + elif " ccx " in operation: + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CCX") + elif " ccy " in operation: + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CCY") + elif " ccz " in operation: + qbit_no = re.findall(r'\d+', operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CCZ") + elif " rx " in operation: theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["RX", theta] - elif "ry" in operation: + elif "^ry " in operation: theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["RY", theta] - elif "rz" in operation: + elif "^rz " in operation: theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["RZ", theta] - elif "rzz" in operation: + elif "^rzz " in operation: theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', operation.split(" ")[0]))) qbit_no = re.findall(r'\d+', operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no[0:0] = ["RZZ", theta] - elif "u1" in operation: + elif "^u1 " in operation: lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["U1", lamda] - elif "u2" in operation: + elif "^u2 " in operation: angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) phi = float('.'.join(angles[0:2])) lamba = float('.'.join(angles[2:])) qbit_no = int(re.findall(r'\d+', operation)[0]) qbit_no[0:0] = ["U2", phi, lamda] - elif "u3" in operation: + elif "^u3 " in operation: angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) theta = float('.'.join(angles[0:2])) phi = float('.'.join(angles[2:4])) @@ -164,28 +176,26 @@ def get_gate_params(operation): def get_gate_functions(qasm_str, start_idx): - # func_list = [] - # param_list = {} - # for line in qasm_str[start_idx:]: - # if "gate" in line: - # line = line.split(" ") - # for i in line[3:]: - # if ',' in i: - # params = i.split(",") - # param_list.append([int(j) for j in params]) - # elif "(" in i: - # params = re.findall(r'\w+', i) - # param_list.append([int(j) for j in params]) - # elif "{" in i: - # break - # elif "}" in line: - # return func_list - # else: - # func_list.append(line) - pass + func_list = [] + param_list = {} + result = [] + idx_inc = 0 + for line in qasm_str[start_idx:]: + if "gate " in line: + result = re.findall("[^,\s()]+", line) + elif result and "{" not in line and "}" not in line: + params = get_gate_params(line) + func_list.append(*params) + elif "}" in line: + print("Returning the list") + print(func_list) + return func_list, idx_incsss + idx_inc += 1 def qasm_QFT(nqubits:int, qasm_str:str, with_swaps: bool = True, psi0 = None): circ = qtn.Circuit(nqubits, psi0 = psi0) + + # circ.psi.draw(color=['PSI0','CU1', 'H', 'SWAP'], show_inds=None, show_tags=False,font_size=40, font_size_inner=20) # circ = qtn.Circuit.qasm(nqubits, psi0 = psi0) gate_functions = {} qasm_str = qasm_str.split('\n') @@ -199,9 +209,7 @@ def qasm_QFT(nqubits:int, qasm_str:str, with_swaps: bool = True, psi0 = None): elif "swap" in command: break elif "gate" in command: # TODO: Complete gate handling - gate_name = line.split(" ")[1] - # gate_func = get_gate_functions(qasm_str, idx) - # gate_funtions[gate_name] = gate_func + gate_func, increment = get_gate_functions(qasm_str, idx) pass elif "barrier" in command: # TODO: Complete barrier handling pass @@ -218,22 +226,22 @@ def qasm_QFT(nqubits:int, qasm_str:str, with_swaps: bool = True, psi0 = None): return circ -def eval_QI_qft(nqubits, bond_dim=0, backend='numpy', qibo_backend='numpy', +def eval_QI_qft(nqubits, bond_dim=0, backend='numpy', qibo_backend='qibojit', with_swaps=True, compare_qibo=False): # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. # qibo_backend: qibojit, qibotf, tensorflow, numpy # generate random statevector as initial state - init_state = np.random.random(2 ** nqubits) + 1j - * np.random.random(2 ** nqubits) + init_state = np.random.random(2 ** nqubits) + 1j * np.random.random(2 ** nqubits) init_state = init_state / np.sqrt((np.abs(init_state)**2).sum()) + init_state_quimb = copy.deepcopy(init_state) # Qibo part if compare_qibo==True: - import qibo - qibo.set_backend(qibo_backend) - # qibo.set_backend(backend="qibojit", platform="numba") - from qibo.models import QFT as qibo_qft + # qibo.set_backend(qibo_backend) + # qibo.set_backend(backend=qibo_backend, platform="numba") + qibo.set_backend(backend=qibo_backend, platform="numpy") + start = timer() circ_qibo = qibo_qft(nqubits, with_swaps) amplitudes_reference = np.array(circ_qibo(init_state)) @@ -243,33 +251,39 @@ def eval_QI_qft(nqubits, bond_dim=0, backend='numpy', qibo_backend='numpy', ##################################################################### - # Quimb part - qtn.tensor_core.set_contract_backend(backend) + qu.core.pnjit() ## convert vector to MPS dims = tuple(2*np.ones(nqubits, dtype=int)) start = timer() - init_state_MPS = - qtn.tensor_1d.MatrixProductState.from_dense(init_state, dims) + init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense(init_state_quimb, dims) end = timer() MPS_time = end-start - # print('MPS conversion time: ', MPS_time) + # construct quimb qft circuit start = timer() - if compare_qibo == True: - circ_quimb = - qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) - else: + if compare_qibo == False: circ_quimb = QI_QFT(nqubits, with_swaps, psi0=init_state_MPS) + else: + circ_quimb = qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) + + interim = circ_quimb.psi.full_simplify(seq="DRC") + + result = interim.to_dense(backend=backend) - result = circ_quimb.to_dense(backend=backend) amplitudes = result.flatten() end = timer() quimb_qft_time = end-start print("quimb time is " + str(quimb_qft_time)) - assert(np.allclose(amplitudes,amplitudes_reference)) + assert(np.allclose(amplitudes,amplitudes_reference,atol=1e-06)) if __name__ == '__main__': - print("Testing for %d nqubits" % (nqubits)) - result = eval_QI_qft(nqubits, compare_qibo=True) \ No newline at end of file + parser = argparse.ArgumentParser() + parser.add_argument("--nqubits", default=10, type=int, + help="Number of quibits in the circuits.") + + args = parser.parse_args() + + print("Testing for %d nqubits" % (args.nqubits)) + result = eval_QI_qft(args.nqubits, compare_qibo=True) From a148fab2f22945efeec0a4b6b56c70077ddc5e05 Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Mon, 6 Feb 2023 18:06:05 +0800 Subject: [PATCH 04/39] Code clean up --- src/qibotn/test_qasm_quimb_backend.py | 122 ++++++-------------------- 1 file changed, 28 insertions(+), 94 deletions(-) diff --git a/src/qibotn/test_qasm_quimb_backend.py b/src/qibotn/test_qasm_quimb_backend.py index 55447c9..08dab01 100644 --- a/src/qibotn/test_qasm_quimb_backend.py +++ b/src/qibotn/test_qasm_quimb_backend.py @@ -8,63 +8,6 @@ import qibo from qibo.models import QFT as qibo_qft from timeit import default_timer as timer -import cirq - -# define dictionary -gate_dict_cirq = { - #'i': I, - 'h': cirq.H, - 't': cirq.T, - #'z': Z, - 'cz': cirq.CZ, - #'cX': cX, - #'rz': ZPhase, - #'rX': XPhase, - #'x': X, - #'y': Y, - 'x_1_2': cirq.rx(0.5*np.pi), - 'y_1_2': cirq.ry(0.5*np.pi) - #'hz_1_2': W_1_2, - #'fs': fSim -} - -# search 'GATE_FUNCTIONS' in Source code for quimb.tensor.circuit for pre-defined gates in quimb -gate_dict = { - #'i': I, - 'h': 'H', - 't': 'T', - #'z': Z, - 'cz': 'cZ', - #'cX': cX, - #'rz': ZPhase, - #'rX': XPhase, - #'x': X, - #'y': Y, - 'x_1_2': 'X_1_2', - 'y_1_2': 'Y_1_2' -} - - -def QI_QFT(nqubits: int, with_swaps: bool = True, psi0 = None): - ## constructs qft circuit - #from qibo import gates - #circuit = Circuit(nqubits) - circ = qtn.Circuit(nqubits, psi0 = psi0) - - for i1 in range(nqubits): - #circuit.add(gates.H(i1)) - circ.apply_gate('H', i1) - for i2 in range(i1 + 1, nqubits): - theta = np.pi / 2 ** (i2 - i1) - #circuit.add(gates.CU1(i2, i1, theta)) - circ.apply_gate('CU1', theta, i2, i1) - - if with_swaps: - for i in range(nqubits // 2): - #circuit.add(gates.SWAP(i, nqubits - i - 1)) - circ.apply_gate('SWAP', i, nqubits - i - 1) - - return circ def get_gate_params(operation): if "h " in operation: @@ -86,8 +29,8 @@ def get_gate_params(operation): qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no.insert(0, "T") elif "cu1" in operation: - lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', - operation.split(" ")[0]))) + lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ + operation.split(" ")[0]))) qbit_no = re.findall(r'\d+', operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no[0:0] = ["CU1", lamda] @@ -131,29 +74,29 @@ def get_gate_params(operation): qbit_no = [int(x) for x in qbit_no] qbit_no.insert(0, "CCZ") elif " rx " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', - operation.split(" ")[0]))) + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ + operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["RX", theta] elif "^ry " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', - operation.split(" ")[0]))) + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ + operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["RY", theta] elif "^rz " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', - operation.split(" ")[0]))) + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ + operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["RZ", theta] elif "^rzz " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', - operation.split(" ")[0]))) + theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ + operation.split(" ")[0]))) qbit_no = re.findall(r'\d+', operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no[0:0] = ["RZZ", theta] elif "^u1 " in operation: - lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', - operation.split(" ")[0]))) + lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ + operation.split(" ")[0]))) qbit_no = [int(re.findall(r'\d+', operation)[0])] qbit_no[0:0] = ["U1", lamda] elif "^u2 " in operation: @@ -177,7 +120,6 @@ def get_gate_params(operation): def get_gate_functions(qasm_str, start_idx): func_list = [] - param_list = {} result = [] idx_inc = 0 for line in qasm_str[start_idx:]: @@ -195,9 +137,6 @@ def get_gate_functions(qasm_str, start_idx): def qasm_QFT(nqubits:int, qasm_str:str, with_swaps: bool = True, psi0 = None): circ = qtn.Circuit(nqubits, psi0 = psi0) - # circ.psi.draw(color=['PSI0','CU1', 'H', 'SWAP'], show_inds=None, show_tags=False,font_size=40, font_size_inner=20) - # circ = qtn.Circuit.qasm(nqubits, psi0 = psi0) - gate_functions = {} qasm_str = qasm_str.split('\n') for idx, line in enumerate(qasm_str): command = line.split(" ")[0] @@ -226,32 +165,31 @@ def qasm_QFT(nqubits:int, qasm_str:str, with_swaps: bool = True, psi0 = None): return circ -def eval_QI_qft(nqubits, bond_dim=0, backend='numpy', qibo_backend='qibojit', - with_swaps=True, compare_qibo=False): +def eval_QI_qft(nqubits, backend='numpy', qibo_backend='qibojit', \ + with_swaps=True): # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. # qibo_backend: qibojit, qibotf, tensorflow, numpy # generate random statevector as initial state - init_state = np.random.random(2 ** nqubits) + 1j * np.random.random(2 ** nqubits) + init_state = np.random.random(2 ** nqubits) + 1j * \ + np.random.random(2 ** nqubits) init_state = init_state / np.sqrt((np.abs(init_state)**2).sum()) init_state_quimb = copy.deepcopy(init_state) - # Qibo part - if compare_qibo==True: - # qibo.set_backend(qibo_backend) - # qibo.set_backend(backend=qibo_backend, platform="numba") - qibo.set_backend(backend=qibo_backend, platform="numpy") + # Qibo circuit + # qibo.set_backend(backend=qibo_backend, platform="numba") + qibo.set_backend(backend=qibo_backend, platform="numpy") - start = timer() - circ_qibo = qibo_qft(nqubits, with_swaps) - amplitudes_reference = np.array(circ_qibo(init_state)) - end = timer() - print("qibo time is " + str(end-start)) - qasm_circ = circ_qibo.to_qasm() + start = timer() + circ_qibo = qibo_qft(nqubits, with_swaps) + amplitudes_reference = np.array(circ_qibo(init_state)) + end = timer() + print("qibo time is " + str(end-start)) + qasm_circ = circ_qibo.to_qasm() ##################################################################### - # Quimb part + # Quimb circuit qu.core.pnjit() ## convert vector to MPS dims = tuple(2*np.ones(nqubits, dtype=int)) @@ -263,15 +201,11 @@ def eval_QI_qft(nqubits, bond_dim=0, backend='numpy', qibo_backend='qibojit', # construct quimb qft circuit start = timer() - if compare_qibo == False: - circ_quimb = QI_QFT(nqubits, with_swaps, psi0=init_state_MPS) - else: - circ_quimb = qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) + circ_quimb = qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) interim = circ_quimb.psi.full_simplify(seq="DRC") result = interim.to_dense(backend=backend) - amplitudes = result.flatten() end = timer() quimb_qft_time = end-start @@ -286,4 +220,4 @@ if __name__ == '__main__': args = parser.parse_args() print("Testing for %d nqubits" % (args.nqubits)) - result = eval_QI_qft(args.nqubits, compare_qibo=True) + result = eval_QI_qft(args.nqubits) From 2fbdfecb3463164aac87336fe1139937e2f3f1c2 Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Mon, 6 Feb 2023 20:05:18 +0800 Subject: [PATCH 05/39] Fix maximum line length --- src/qibotn/test_qasm_quimb_backend.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/qibotn/test_qasm_quimb_backend.py b/src/qibotn/test_qasm_quimb_backend.py index 08dab01..548b95d 100644 --- a/src/qibotn/test_qasm_quimb_backend.py +++ b/src/qibotn/test_qasm_quimb_backend.py @@ -193,10 +193,8 @@ def eval_QI_qft(nqubits, backend='numpy', qibo_backend='qibojit', \ qu.core.pnjit() ## convert vector to MPS dims = tuple(2*np.ones(nqubits, dtype=int)) - start = timer() - init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense(init_state_quimb, dims) - end = timer() - MPS_time = end-start + init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense \ + (init_state_quimb, dims) # construct quimb qft circuit From 9dc59cf14dc9b4d7da095873ecc3f6d4f2f5635e Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Tue, 7 Feb 2023 11:54:05 +0800 Subject: [PATCH 06/39] Remove the circuit comparison notebook from the quimb support PR --- src/qibotn/qibo2quimb.ipynb | 301 ------------------------------------ 1 file changed, 301 deletions(-) delete mode 100644 src/qibotn/qibo2quimb.ipynb diff --git a/src/qibotn/qibo2quimb.ipynb b/src/qibotn/qibo2quimb.ipynb deleted file mode 100644 index 1a18866..0000000 --- a/src/qibotn/qibo2quimb.ipynb +++ /dev/null @@ -1,301 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "quimb version: 1.4.0\n" - ] - } - ], - "source": [ - "import argparse\n", - "from timeit import default_timer as timer\n", - "\n", - "import quimb as qu\n", - "from qiskit import QuantumCircuit\n", - "\n", - "from qibo import __version__, gates, tests\n", - "from qibo.models import Circuit, QFT\n", - "from qibo.tests.utils import random_state\n", - "\n", - "print('quimb version:', qu.__version__)" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Testing for 8 qubits\n", - "qibo QFT circuit:\n", - "q0: ─H─U1─U1─U1─U1─U1─U1─U1─────────────────────────────────────────────── ...\n", - "q1: ───o──|──|──|──|──|──|──H─U1─U1─U1─U1─U1─U1─────────────────────────── ...\n", - "q2: ──────o──|──|──|──|──|────o──|──|──|──|──|──H─U1─U1─U1─U1─U1────────── ...\n", - "q3: ─────────o──|──|──|──|───────o──|──|──|──|────o──|──|──|──|──H─U1─U1─U ...\n", - "q4: ────────────o──|──|──|──────────o──|──|──|───────o──|──|──|────o──|──| ...\n", - "q5: ───────────────o──|──|─────────────o──|──|──────────o──|──|───────o──| ...\n", - "q6: ──────────────────o──|────────────────o──|─────────────o──|──────────o ...\n", - "q7: ─────────────────────o───────────────────o────────────────o─────────── ...\n", - "\n", - "q0: ... ───────────────────────────────x───────\n", - "q1: ... ───────────────────────────────|─x─────\n", - "q2: ... ───────────────────────────────|─|─x───\n", - "q3: ... 1─U1───────────────────────────|─|─|─x─\n", - "q4: ... ──|──H─U1─U1─U1────────────────|─|─|─x─\n", - "q5: ... ──|────o──|──|──H─U1─U1────────|─|─x───\n", - "q6: ... ──|───────o──|────o──|──H─U1───|─x─────\n", - "q7: ... ──o──────────o───────o────o──H─x───────\n", - "\n", - "qiskit QFT circuit:\n" - ] - }, - { - "data": { - "text/html": [ - "
     ┌───┐                                                            »\n",
-       "q_0: ┤ H ├─■──────────────■───────────────────■───────────────────────»\n",
-       "     └───┘ │U1(π/2) ┌───┐ │                   │                       »\n",
-       "q_1: ──────■────────┤ H ├─┼─────────■─────────┼──────────────■────────»\n",
-       "                    └───┘ │U1(π/4)  │U1(π/2)  │        ┌───┐ │        »\n",
-       "q_2: ─────────────────────■─────────■─────────┼────────┤ H ├─┼────────»\n",
-       "                                              │U1(π/8) └───┘ │U1(π/4) »\n",
-       "q_3: ─────────────────────────────────────────■──────────────■────────»\n",
-       "                                                                      »\n",
-       "q_4: ─────────────────────────────────────────────────────────────────»\n",
-       "                                                                      »\n",
-       "q_5: ─────────────────────────────────────────────────────────────────»\n",
-       "                                                                      »\n",
-       "q_6: ─────────────────────────────────────────────────────────────────»\n",
-       "                                                                      »\n",
-       "q_7: ─────────────────────────────────────────────────────────────────»\n",
-       "                                                                      »\n",
-       "«                                                                         »\n",
-       "«q_0: ─■──────────────────────────────■───────────────────────────────────»\n",
-       "«      │                              │                                   »\n",
-       "«q_1: ─┼────────────────────■─────────┼─────────────────────────■─────────»\n",
-       "«      │                    │         │                         │         »\n",
-       "«q_2: ─┼──────────■─────────┼─────────┼───────────────■─────────┼─────────»\n",
-       "«      │          │U1(π/2)  │         │         ┌───┐ │         │         »\n",
-       "«q_3: ─┼──────────■─────────┼─────────┼─────────┤ H ├─┼─────────┼─────────»\n",
-       "«      │U1(π/16)            │U1(π/8)  │         └───┘ │U1(π/4)  │         »\n",
-       "«q_4: ─■────────────────────■─────────┼───────────────■─────────┼─────────»\n",
-       "«                                     │U1(π/32)                 │U1(π/16) »\n",
-       "«q_5: ────────────────────────────────■─────────────────────────■─────────»\n",
-       "«                                                                         »\n",
-       "«q_6: ────────────────────────────────────────────────────────────────────»\n",
-       "«                                                                         »\n",
-       "«q_7: ────────────────────────────────────────────────────────────────────»\n",
-       "«                                                                         »\n",
-       "«                                                                          »\n",
-       "«q_0: ─■─────────────────────────────────────────■─────────────────────────»\n",
-       "«      │                                         │                         »\n",
-       "«q_1: ─┼──────────────────────────────■──────────┼─────────────────────────»\n",
-       "«      │                              │          │                         »\n",
-       "«q_2: ─┼────────────────────■─────────┼──────────┼─────────────────────────»\n",
-       "«      │                    │         │          │                         »\n",
-       "«q_3: ─┼──────────■─────────┼─────────┼──────────┼────────────────■────────»\n",
-       "«      │          │U1(π/2)  │         │          │          ┌───┐ │        »\n",
-       "«q_4: ─┼──────────■─────────┼─────────┼──────────┼──────────┤ H ├─┼────────»\n",
-       "«      │                    │U1(π/8)  │          │          └───┘ │U1(π/4) »\n",
-       "«q_5: ─┼────────────────────■─────────┼──────────┼────────────────■────────»\n",
-       "«      │U1(π/64)                      │U1(π/32)  │                         »\n",
-       "«q_6: ─■──────────────────────────────■──────────┼─────────────────────────»\n",
-       "«                                                │U1(π/128)                »\n",
-       "«q_7: ───────────────────────────────────────────■─────────────────────────»\n",
-       "«                                                                          »\n",
-       "«                                                                         »\n",
-       "«q_0: ────────────────────────────────────────────────────────────────────»\n",
-       "«                                                                         »\n",
-       "«q_1: ────────────■───────────────────────────────────────────────────────»\n",
-       "«                 │                                                       »\n",
-       "«q_2: ─■──────────┼──────────────────────────────■────────────────────────»\n",
-       "«      │          │                              │                        »\n",
-       "«q_3: ─┼──────────┼────────────────────■─────────┼────────────────────────»\n",
-       "«      │          │                    │         │                        »\n",
-       "«q_4: ─┼──────────┼──────────■─────────┼─────────┼───────────────■────────»\n",
-       "«      │          │          │U1(π/2)  │         │         ┌───┐ │        »\n",
-       "«q_5: ─┼──────────┼──────────■─────────┼─────────┼─────────┤ H ├─┼────────»\n",
-       "«      │U1(π/16)  │                    │U1(π/8)  │         └───┘ │U1(π/4) »\n",
-       "«q_6: ─■──────────┼────────────────────■─────────┼───────────────■────────»\n",
-       "«                 │U1(π/64)                      │U1(π/32)                »\n",
-       "«q_7: ────────────■──────────────────────────────■────────────────────────»\n",
-       "«                                                                         »\n",
-       "«                                                                     \n",
-       "«q_0: ──────────────────────────────────────────────────────────────X─\n",
-       "«                                                                   │ \n",
-       "«q_1: ──────────────────────────────────────────────────────────X───┼─\n",
-       "«                                                               │   │ \n",
-       "«q_2: ──────────────────────────────────────────────────X───────┼───┼─\n",
-       "«                                                       │       │   │ \n",
-       "«q_3: ─■───────────────────────────────X────────────────┼───────┼───┼─\n",
-       "«      │                               │                │       │   │ \n",
-       "«q_4: ─┼────────────────────■──────────X────────────────┼───────┼───┼─\n",
-       "«      │                    │                           │       │   │ \n",
-       "«q_5: ─┼──────────■─────────┼──────────────■────────────X───────┼───┼─\n",
-       "«      │          │U1(π/2)  │        ┌───┐ │                    │   │ \n",
-       "«q_6: ─┼──────────■─────────┼────────┤ H ├─┼─────────■──────────X───┼─\n",
-       "«      │U1(π/16)            │U1(π/8) └───┘ │U1(π/4)  │U1(π/2) ┌───┐ │ \n",
-       "«q_7: ─■────────────────────■──────────────■─────────■────────┤ H ├─X─\n",
-       "«                                                             └───┘   
" - ], - "text/plain": [ - " ┌───┐ »\n", - "q_0: ┤ H ├─■──────────────■───────────────────■───────────────────────»\n", - " └───┘ │U1(π/2) ┌───┐ │ │ »\n", - "q_1: ──────■────────┤ H ├─┼─────────■─────────┼──────────────■────────»\n", - " └───┘ │U1(π/4) │U1(π/2) │ ┌───┐ │ »\n", - "q_2: ─────────────────────■─────────■─────────┼────────┤ H ├─┼────────»\n", - " │U1(π/8) └───┘ │U1(π/4) »\n", - "q_3: ─────────────────────────────────────────■──────────────■────────»\n", - " »\n", - "q_4: ─────────────────────────────────────────────────────────────────»\n", - " »\n", - "q_5: ─────────────────────────────────────────────────────────────────»\n", - " »\n", - "q_6: ─────────────────────────────────────────────────────────────────»\n", - " »\n", - "q_7: ─────────────────────────────────────────────────────────────────»\n", - " »\n", - "« »\n", - "«q_0: ─■──────────────────────────────■───────────────────────────────────»\n", - "« │ │ »\n", - "«q_1: ─┼────────────────────■─────────┼─────────────────────────■─────────»\n", - "« │ │ │ │ »\n", - "«q_2: ─┼──────────■─────────┼─────────┼───────────────■─────────┼─────────»\n", - "« │ │U1(π/2) │ │ ┌───┐ │ │ »\n", - "«q_3: ─┼──────────■─────────┼─────────┼─────────┤ H ├─┼─────────┼─────────»\n", - "« │U1(π/16) │U1(π/8) │ └───┘ │U1(π/4) │ »\n", - "«q_4: ─■────────────────────■─────────┼───────────────■─────────┼─────────»\n", - "« │U1(π/32) │U1(π/16) »\n", - "«q_5: ────────────────────────────────■─────────────────────────■─────────»\n", - "« »\n", - "«q_6: ────────────────────────────────────────────────────────────────────»\n", - "« »\n", - "«q_7: ────────────────────────────────────────────────────────────────────»\n", - "« »\n", - "« »\n", - "«q_0: ─■─────────────────────────────────────────■─────────────────────────»\n", - "« │ │ »\n", - "«q_1: ─┼──────────────────────────────■──────────┼─────────────────────────»\n", - "« │ │ │ »\n", - "«q_2: ─┼────────────────────■─────────┼──────────┼─────────────────────────»\n", - "« │ │ │ │ »\n", - "«q_3: ─┼──────────■─────────┼─────────┼──────────┼────────────────■────────»\n", - "« │ │U1(π/2) │ │ │ ┌───┐ │ »\n", - "«q_4: ─┼──────────■─────────┼─────────┼──────────┼──────────┤ H ├─┼────────»\n", - "« │ │U1(π/8) │ │ └───┘ │U1(π/4) »\n", - "«q_5: ─┼────────────────────■─────────┼──────────┼────────────────■────────»\n", - "« │U1(π/64) │U1(π/32) │ »\n", - "«q_6: ─■──────────────────────────────■──────────┼─────────────────────────»\n", - "« │U1(π/128) »\n", - "«q_7: ───────────────────────────────────────────■─────────────────────────»\n", - "« »\n", - "« »\n", - "«q_0: ────────────────────────────────────────────────────────────────────»\n", - "« »\n", - "«q_1: ────────────■───────────────────────────────────────────────────────»\n", - "« │ »\n", - "«q_2: ─■──────────┼──────────────────────────────■────────────────────────»\n", - "« │ │ │ »\n", - "«q_3: ─┼──────────┼────────────────────■─────────┼────────────────────────»\n", - "« │ │ │ │ »\n", - "«q_4: ─┼──────────┼──────────■─────────┼─────────┼───────────────■────────»\n", - "« │ │ │U1(π/2) │ │ ┌───┐ │ »\n", - "«q_5: ─┼──────────┼──────────■─────────┼─────────┼─────────┤ H ├─┼────────»\n", - "« │U1(π/16) │ │U1(π/8) │ └───┘ │U1(π/4) »\n", - "«q_6: ─■──────────┼────────────────────■─────────┼───────────────■────────»\n", - "« │U1(π/64) │U1(π/32) »\n", - "«q_7: ────────────■──────────────────────────────■────────────────────────»\n", - "« »\n", - "« \n", - "«q_0: ──────────────────────────────────────────────────────────────X─\n", - "« │ \n", - "«q_1: ──────────────────────────────────────────────────────────X───┼─\n", - "« │ │ \n", - "«q_2: ──────────────────────────────────────────────────X───────┼───┼─\n", - "« │ │ │ \n", - "«q_3: ─■───────────────────────────────X────────────────┼───────┼───┼─\n", - "« │ │ │ │ │ \n", - "«q_4: ─┼────────────────────■──────────X────────────────┼───────┼───┼─\n", - "« │ │ │ │ │ \n", - "«q_5: ─┼──────────■─────────┼──────────────■────────────X───────┼───┼─\n", - "« │ │U1(π/2) │ ┌───┐ │ │ │ \n", - "«q_6: ─┼──────────■─────────┼────────┤ H ├─┼─────────■──────────X───┼─\n", - "« │U1(π/16) │U1(π/8) └───┘ │U1(π/4) │U1(π/2) ┌───┐ │ \n", - "«q_7: ─■────────────────────■──────────────■─────────■────────┤ H ├─X─\n", - "« └───┘ " - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "num_qubits = 6\n", - "\n", - "print('Testing for {} qubits'.format(num_qubits))\n", - "\n", - "# generate the initial state\n", - "initial_state = random_state(num_qubits)\n", - "\n", - "# get the qibo circuit, convert it to a qasm circuit\n", - "start = timer()\n", - "qibo_qft_circuit = QFT(num_qubits)\n", - "final_state = qibo_qft_circuit(initial_state)\n", - "end = timer()\n", - "\n", - "# print(qibo_qft_circuit.summary())\n", - "print('qibo QFT circuit:')\n", - "print(qibo_qft_circuit.draw())\n", - "# print(final_state.state())\n", - "# print(\"qibo execution time is \" + str(end - start))\n", - "\n", - "# convert the circuit format from qibo to qasm\n", - "qasm_qft_circuit = qibo_qft_circuit.to_qasm()\n", - "\n", - "# convert the circuit format from qasm to qiskit\n", - "qiskit_qft_circuit = QuantumCircuit.from_qasm_str(qasm_qft_circuit)\n", - "print('\\nqiskit QFT circuit:')\n", - "qiskit_qft_circuit.draw()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 64-bit ('3.8.13')", - "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.13" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "ad6a7ef27ab1ef63a56400052d1dab463d164a7bc59eb0569183e19f112dd87c" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 64747045eb6e2d6fe8881820fe61fc8aa02577d9 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 09:10:09 +0100 Subject: [PATCH 07/39] Add testing workflow --- .github/workflows/rules.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/rules.yml diff --git a/.github/workflows/rules.yml b/.github/workflows/rules.yml new file mode 100644 index 0000000..e087400 --- /dev/null +++ b/.github/workflows/rules.yml @@ -0,0 +1,21 @@ +# A single CI script with github workflow +name: Tests + +on: + push: + pull_request: + types: [labeled] + +jobs: + build: + if: contains(github.event.pull_request.labels.*.name, 'run-workflow') || github.event_name == 'push' + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: [3.7, 3.8, 3.9, "3.10"] + uses: qiboteam/workflows/.github/workflows/rules.yml@main + with: + os: ${{ matrix.os }} + python-version: ${{ matrix.python-version }} + environment: "qibotn" + secrets: inherit From a39fe3efbc72737dd3d44a64b4edbf2cf3577e28 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 09:23:29 +0100 Subject: [PATCH 08/39] Add pylint and pytest configs --- pyproject.toml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5693b81 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[tool.pylint.reports] +output-format = "colorized" + +[tool.pytest.ini_options] +testpaths = ["tests/"] +addopts = ["--cov=qibotn", "--cov-report=xml"] From 625e3ecd95b4e2c4ac66949ed00d6f31c1275efe Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 09:27:10 +0100 Subject: [PATCH 09/39] Trim down setup file and deps --- setup.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/setup.py b/setup.py index 9b2ae6a..1fa40bf 100644 --- a/setup.py +++ b/setup.py @@ -1,18 +1,15 @@ # Installation script for python from setuptools import setup, find_packages -import os -import re +import pathlib PACKAGE = "qibotn" -# load long description from README -this_directory = os.path.abspath(os.path.dirname(__file__)) -with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f: - long_description = f.read() +HERE = pathlib.Path(__file__).parent +LONG_DESCRIPTION = (HERE / "README.md").read_text(encoding="utf-8") setup( name="qibotn", - version="0.1", + version="0.0.1", description="A tensor-network translation module for quantum computing", author="The Qibo team", author_email="", @@ -27,19 +24,14 @@ setup( "Topic :: Scientific/Engineering :: Physics", ], install_requires=[ - "networkx>=2.3", - "opt_einsum>=3.2", - "autoray>=0.2.0", - "diskcache>=3.0", - "randomgen>=1.18", "quimb", - "qibo" + "qibo", ], extras_require={ - "docs": ["sphinx", "sphinx_rtd_theme", "recommonmark", "sphinxcontrib-bibtex", "sphinx_markdown_tables", "nbsphinx", "IPython", "doc2dash>=2.4.1", ], - "tests": ["pytest", "cirq", "ply", "sklearn", "dill", "coverage", "pytest-cov"], + "docs": [], + "tests": ["pytest", "pytest-cov"], }, python_requires=">=3.7.0", - long_description=long_description, - long_description_content_type='text/markdown', + long_description=LONG_DESCRIPTION, + long_description_content_type="text/markdown", ) From 21c207d76f66065f135f933af6115f481c53325b Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 09:32:42 +0100 Subject: [PATCH 10/39] Specify deps versions --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 1fa40bf..49beffa 100644 --- a/setup.py +++ b/setup.py @@ -24,12 +24,12 @@ setup( "Topic :: Scientific/Engineering :: Physics", ], install_requires=[ - "quimb", - "qibo", + "qibo>=0.1.10", + "quimb>=1.4.0", ], extras_require={ "docs": [], - "tests": ["pytest", "pytest-cov"], + "tests": ["pytest>=7.2.0", "pytest-cov>=4.0.0"], }, python_requires=">=3.7.0", long_description=LONG_DESCRIPTION, From 93a59ffc3e1722375ff635ff1866686450985f6e Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 09:35:01 +0100 Subject: [PATCH 11/39] Update gitignore with GitHub maintened one Available at https://github.com/github/gitignore/blob/main/Python.gitignore --- .gitignore | 239 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 135 insertions(+), 104 deletions(-) diff --git a/.gitignore b/.gitignore index 6a256b3..68bc17f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,129 +1,160 @@ # Byte-compiled / optimized / DLL files - __pycache__/ - *.py[cod] - *$py.class +__pycache__/ +*.py[cod] +*$py.class - # C extensions - *.so +# C extensions +*.so - # Distribution / packaging - .Python - build/ - develop-eggs/ - dist/ - downloads/ - eggs/ - .eggs/ - lib/ - lib64/ - parts/ - sdist/ - var/ - wheels/ - pip-wheel-metadata/ - share/python-wheels/ - *.egg-info/ - .installed.cfg - *.egg - MANIFEST +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST - # PyInstaller - # Usually these files are written by a python script from a template - # before PyInstaller builds the exe, so as to inject date/other infos into it. - *.manifest - *.spec +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec - # Installer logs - pip-log.txt - pip-delete-this-directory.txt +# Installer logs +pip-log.txt +pip-delete-this-directory.txt - # Unit test / coverage reports - htmlcov/ - .tox/ - .nox/ - .coverage - .coverage.* - .cache - nosetests.xml - coverage.xml - *.cover - *.py,cover - .hypothesis/ - .pytest_cache/ +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ - # Translations - *.mo - *.pot +# Translations +*.mo +*.pot - # Django stuff: - *.log - local_settings.py - db.sqlite3 - db.sqlite3-journal +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal - # Flask stuff: - instance/ - .webassets-cache +# Flask stuff: +instance/ +.webassets-cache - # Scrapy stuff: - .scrapy +# Scrapy stuff: +.scrapy - # Sphinx documentation - docs/_build/ +# Sphinx documentation +docs/_build/ - # PyBuilder - target/ +# PyBuilder +.pybuilder/ +target/ - # Jupyter Notebook - .ipynb_checkpoints +# Jupyter Notebook +.ipynb_checkpoints - # IPython - profile_default/ - ipython_config.py +# IPython +profile_default/ +ipython_config.py - # pyenv - .python-version +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version - # pipenv - # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. - # However, in case of collaboration, if having platform-specific dependencies or dependencies - # having no cross-platform support, pipenv may install dependencies that don't work, or not - # install all needed dependencies. - #Pipfile.lock +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock - # PEP 582; used by e.g. github.com/David-OConnor/pyflow - __pypackages__/ +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock - # Celery stuff - celerybeat-schedule - celerybeat.pid +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml - # SageMath parsed files - *.sage.py +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ - # Environments - .env - .venv - env/ - venv/ - ENV/ - env.bak/ - venv.bak/ +# Celery stuff +celerybeat-schedule +celerybeat.pid - # Spyder project settings - .spyderproject - .spyproject +# SageMath parsed files +*.sage.py - # Rope project settings - .ropeproject +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ - # mkdocs documentation - /site +# Spyder project settings +.spyderproject +.spyproject - # mypy - .mypy_cache/ - .dmypy.json - dmypy.json +# Rope project settings +.ropeproject - # Pyre type checker - .pyre/ +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ From 5c6f056228f52457b6fc1d1c0e0c56fb76219aa0 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 09:41:30 +0100 Subject: [PATCH 12/39] Split original module --- setup.py | 1 - src/qibotn/__init__.py | 2 +- src/qibotn/__main__.py | 20 +++ src/qibotn/qasm_quimb.py | 214 +++++++++++++++++++++++++ src/qibotn/test_qasm_quimb_backend.py | 221 -------------------------- 5 files changed, 235 insertions(+), 223 deletions(-) create mode 100644 src/qibotn/__main__.py create mode 100644 src/qibotn/qasm_quimb.py delete mode 100644 src/qibotn/test_qasm_quimb_backend.py diff --git a/setup.py b/setup.py index 49beffa..876f18a 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -# Installation script for python from setuptools import setup, find_packages import pathlib diff --git a/src/qibotn/__init__.py b/src/qibotn/__init__.py index a4e2017..f102a9c 100644 --- a/src/qibotn/__init__.py +++ b/src/qibotn/__init__.py @@ -1 +1 @@ -__version__ = "0.1" +__version__ = "0.0.1" diff --git a/src/qibotn/__main__.py b/src/qibotn/__main__.py new file mode 100644 index 0000000..807b547 --- /dev/null +++ b/src/qibotn/__main__.py @@ -0,0 +1,20 @@ +import argparse +from qibotn import qasm_quimb + + +def parser(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--nqubits", default=10, type=int, help="Number of quibits in the circuits." + ) + return parser.parse_args() + + +def main(args: argparse.Namespace): + print("Testing for %d nqubits" % (args.nqubits)) + result = qasm_quimb.eval_QI_qft(args.nqubits) + print(result) + + +if __name__ == "__main__": + main(parser()) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py new file mode 100644 index 0000000..bb17de3 --- /dev/null +++ b/src/qibotn/qasm_quimb.py @@ -0,0 +1,214 @@ +import argparse +import quimb as qu +import quimb.tensor as qtn +import numpy as np +import re, copy + +import qibo +from qibo.models import QFT as qibo_qft + +from timeit import default_timer as timer + + +def get_gate_params(operation): + if "h " in operation: + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no.insert(0, "H") + elif "x " in operation: + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no.insert(0, "X") + elif "y " in operation: + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no.insert(0, "Y") + elif "z " in operation: + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no.insert(0, "Z") + elif "s " in operation: + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no.insert(0, "S") + elif "t " in operation: + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no.insert(0, "T") + elif "cu1" in operation: + lamda = float( + ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ) + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["CU1", lamda] + elif "cu2" in operation: + angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) + phi = float(".".join(angles[0:2])) + lamba = float(".".join(angles[2:])) + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["CU2", phi, lamda] + elif "cu3" in operation: + angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) + theta = float(".".join(angles[0:2])) + phi = float(".".join(angles[2:4])) + lamba = float(".".join(angles[4:])) + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["CU3", theta, phi, lamda] + elif " cx " in operation: + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CX") + elif " cy " in operation: + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CY") + elif " cz " in operation: + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CZ") + elif " ccx " in operation: + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CCX") + elif " ccy " in operation: + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CCY") + elif " ccz " in operation: + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no.insert(0, "CCZ") + elif " rx " in operation: + theta = float( + ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ) + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no[0:0] = ["RX", theta] + elif "^ry " in operation: + theta = float( + ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ) + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no[0:0] = ["RY", theta] + elif "^rz " in operation: + theta = float( + ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ) + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no[0:0] = ["RZ", theta] + elif "^rzz " in operation: + theta = float( + ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ) + qbit_no = re.findall(r"\d+", operation.split(" ")[1]) + qbit_no = [int(x) for x in qbit_no] + qbit_no[0:0] = ["RZZ", theta] + elif "^u1 " in operation: + lamda = float( + ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ) + qbit_no = [int(re.findall(r"\d+", operation)[0])] + qbit_no[0:0] = ["U1", lamda] + elif "^u2 " in operation: + angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) + phi = float(".".join(angles[0:2])) + lamba = float(".".join(angles[2:])) + qbit_no = int(re.findall(r"\d+", operation)[0]) + qbit_no[0:0] = ["U2", phi, lamda] + elif "^u3 " in operation: + angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) + theta = float(".".join(angles[0:2])) + phi = float(".".join(angles[2:4])) + lamba = float(".".join(angles[4:])) + qbit_no = int(re.findall(r"\d+", operation)[0]) + qbit_no[0:0] = ["U3", theta, phi, lamda] + else: + assert "Unsupported gate" + + return qbit_no + + +def get_gate_functions(qasm_str, start_idx): + func_list = [] + result = [] + idx_inc = 0 + for line in qasm_str[start_idx:]: + if "gate " in line: + result = re.findall("[^,\s()]+", line) + elif result and "{" not in line and "}" not in line: + params = get_gate_params(line) + func_list.append(*params) + elif "}" in line: + print("Returning the list") + print(func_list) + return func_list, idx_incsss + idx_inc += 1 + + +def qasm_QFT(nqubits: int, qasm_str: str, with_swaps: bool = True, psi0=None): + circ = qtn.Circuit(nqubits, psi0=psi0) + + qasm_str = qasm_str.split("\n") + for idx, line in enumerate(qasm_str): + command = line.split(" ")[0] + if re.search("include|//|OPENQASM", command): + continue + elif "qreg" in command: + nbits = int(re.findall(r"\d+", line)[0]) + assert nbits == nqubits + elif "swap" in command: + break + elif "gate" in command: # TODO: Complete gate handling + gate_func, increment = get_gate_functions(qasm_str, idx) + pass + elif "barrier" in command: # TODO: Complete barrier handling + pass + elif "measure" in command: # TODO: Complete measure handling + pass + else: + params = get_gate_params(line) + circ.apply_gate(*params) + + if with_swaps: + for i in range(nqubits // 2): # TODO: Ignore the barrier indices? + circ.apply_gate("SWAP", i, nqubits - i - 1) + + return circ + + +def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=True): + # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. + # qibo_backend: qibojit, qibotf, tensorflow, numpy + + # generate random statevector as initial state + init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) + init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) + init_state_quimb = copy.deepcopy(init_state) + + # Qibo circuit + # qibo.set_backend(backend=qibo_backend, platform="numba") + qibo.set_backend(backend=qibo_backend, platform="numpy") + + start = timer() + circ_qibo = qibo_qft(nqubits, with_swaps) + amplitudes_reference = np.array(circ_qibo(init_state)) + end = timer() + print("qibo time is " + str(end - start)) + qasm_circ = circ_qibo.to_qasm() + + ##################################################################### + # Quimb circuit + qu.core.pnjit() + ## convert vector to MPS + dims = tuple(2 * np.ones(nqubits, dtype=int)) + init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense(init_state_quimb, dims) + + # construct quimb qft circuit + start = timer() + circ_quimb = qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) + + interim = circ_quimb.psi.full_simplify(seq="DRC") + + result = interim.to_dense(backend=backend) + amplitudes = result.flatten() + end = timer() + quimb_qft_time = end - start + print("quimb time is " + str(quimb_qft_time)) + assert np.allclose(amplitudes, amplitudes_reference, atol=1e-06) diff --git a/src/qibotn/test_qasm_quimb_backend.py b/src/qibotn/test_qasm_quimb_backend.py deleted file mode 100644 index 548b95d..0000000 --- a/src/qibotn/test_qasm_quimb_backend.py +++ /dev/null @@ -1,221 +0,0 @@ -import argparse -import quimb as qu -import quimb.tensor as qtn -import numpy as np -import re, copy - -import qibo -from qibo.models import QFT as qibo_qft - -from timeit import default_timer as timer - -def get_gate_params(operation): - if "h " in operation: - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no.insert(0, "H") - elif "x " in operation: - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no.insert(0, "X") - elif "y " in operation: - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no.insert(0, "Y") - elif "z " in operation: - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no.insert(0, "Z") - elif "s " in operation: - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no.insert(0, "S") - elif "t " in operation: - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no.insert(0, "T") - elif "cu1" in operation: - lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ - operation.split(" ")[0]))) - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU1", lamda] - elif "cu2" in operation: - angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) - phi = float('.'.join(angles[0:2])) - lamba = float('.'.join(angles[2:])) - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU2", phi, lamda] - elif "cu3" in operation: - angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) - theta = float('.'.join(angles[0:2])) - phi = float('.'.join(angles[2:4])) - lamba = float('.'.join(angles[4:])) - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU3", theta, phi, lamda] - elif " cx " in operation: - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CX") - elif " cy " in operation: - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CY") - elif " cz " in operation: - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CZ") - elif " ccx " in operation: - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CCX") - elif " ccy " in operation: - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CCY") - elif " ccz " in operation: - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CCZ") - elif " rx " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ - operation.split(" ")[0]))) - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no[0:0] = ["RX", theta] - elif "^ry " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ - operation.split(" ")[0]))) - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no[0:0] = ["RY", theta] - elif "^rz " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ - operation.split(" ")[0]))) - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no[0:0] = ["RZ", theta] - elif "^rzz " in operation: - theta = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ - operation.split(" ")[0]))) - qbit_no = re.findall(r'\d+', operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["RZZ", theta] - elif "^u1 " in operation: - lamda = float('.'.join(re.findall(r'\b\d+(?:[Ee][+-]?\d+)?', \ - operation.split(" ")[0]))) - qbit_no = [int(re.findall(r'\d+', operation)[0])] - qbit_no[0:0] = ["U1", lamda] - elif "^u2 " in operation: - angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) - phi = float('.'.join(angles[0:2])) - lamba = float('.'.join(angles[2:])) - qbit_no = int(re.findall(r'\d+', operation)[0]) - qbit_no[0:0] = ["U2", phi, lamda] - elif "^u3 " in operation: - angles = re.findall(r'\b\d+(?:[Ee][+-]?\d+)?',operation.split(" ")[0]) - theta = float('.'.join(angles[0:2])) - phi = float('.'.join(angles[2:4])) - lamba = float('.'.join(angles[4:])) - qbit_no = int(re.findall(r'\d+', operation)[0]) - qbit_no[0:0] = ["U3", theta, phi, lamda] - else: - assert("Unsupported gate") - - return qbit_no - - -def get_gate_functions(qasm_str, start_idx): - func_list = [] - result = [] - idx_inc = 0 - for line in qasm_str[start_idx:]: - if "gate " in line: - result = re.findall("[^,\s()]+", line) - elif result and "{" not in line and "}" not in line: - params = get_gate_params(line) - func_list.append(*params) - elif "}" in line: - print("Returning the list") - print(func_list) - return func_list, idx_incsss - idx_inc += 1 - -def qasm_QFT(nqubits:int, qasm_str:str, with_swaps: bool = True, psi0 = None): - circ = qtn.Circuit(nqubits, psi0 = psi0) - - qasm_str = qasm_str.split('\n') - for idx, line in enumerate(qasm_str): - command = line.split(" ")[0] - if re.search("include|//|OPENQASM", command): - continue - elif "qreg" in command: - nbits = int(re.findall(r'\d+', line)[0]) - assert(nbits == nqubits) - elif "swap" in command: - break - elif "gate" in command: # TODO: Complete gate handling - gate_func, increment = get_gate_functions(qasm_str, idx) - pass - elif "barrier" in command: # TODO: Complete barrier handling - pass - elif "measure" in command: # TODO: Complete measure handling - pass - else: - params = get_gate_params(line) - circ.apply_gate(*params) - - if with_swaps: - for i in range(nqubits // 2): # TODO: Ignore the barrier indices? - circ.apply_gate('SWAP', i, nqubits - i - 1) - - return circ - - -def eval_QI_qft(nqubits, backend='numpy', qibo_backend='qibojit', \ - with_swaps=True): - # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. - # qibo_backend: qibojit, qibotf, tensorflow, numpy - - # generate random statevector as initial state - init_state = np.random.random(2 ** nqubits) + 1j * \ - np.random.random(2 ** nqubits) - init_state = init_state / np.sqrt((np.abs(init_state)**2).sum()) - init_state_quimb = copy.deepcopy(init_state) - - # Qibo circuit - # qibo.set_backend(backend=qibo_backend, platform="numba") - qibo.set_backend(backend=qibo_backend, platform="numpy") - - start = timer() - circ_qibo = qibo_qft(nqubits, with_swaps) - amplitudes_reference = np.array(circ_qibo(init_state)) - end = timer() - print("qibo time is " + str(end-start)) - qasm_circ = circ_qibo.to_qasm() - - - ##################################################################### - # Quimb circuit - qu.core.pnjit() - ## convert vector to MPS - dims = tuple(2*np.ones(nqubits, dtype=int)) - init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense \ - (init_state_quimb, dims) - - - # construct quimb qft circuit - start = timer() - circ_quimb = qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) - - interim = circ_quimb.psi.full_simplify(seq="DRC") - - result = interim.to_dense(backend=backend) - amplitudes = result.flatten() - end = timer() - quimb_qft_time = end-start - print("quimb time is " + str(quimb_qft_time)) - assert(np.allclose(amplitudes,amplitudes_reference,atol=1e-06)) - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--nqubits", default=10, type=int, - help="Number of quibits in the circuits.") - - args = parser.parse_args() - - print("Testing for %d nqubits" % (args.nqubits)) - result = eval_QI_qft(args.nqubits) From c8ccb1849cfb5b04e819eb4161efd4326666b6bf Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 09:52:28 +0100 Subject: [PATCH 13/39] Specify required quimb extra --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 876f18a..4306e33 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ setup( ], install_requires=[ "qibo>=0.1.10", - "quimb>=1.4.0", + "quimb[tensor]>=1.4.0", ], extras_require={ "docs": [], From f595c268ad775060dc530565a3410ee0e4cd811b Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 10:19:43 +0100 Subject: [PATCH 14/39] Solve trivial Pylint errors --- src/qibotn/qasm_quimb.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index bb17de3..89242a9 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -1,14 +1,14 @@ -import argparse +import re +import copy +from timeit import default_timer as timer + +import numpy as np import quimb as qu import quimb.tensor as qtn -import numpy as np -import re, copy import qibo from qibo.models import QFT as qibo_qft -from timeit import default_timer as timer - def get_gate_params(operation): if "h " in operation: @@ -138,7 +138,7 @@ def get_gate_functions(qasm_str, start_idx): elif "}" in line: print("Returning the list") print(func_list) - return func_list, idx_incsss + return func_list, idx_inc idx_inc += 1 @@ -196,7 +196,7 @@ def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=Tru ##################################################################### # Quimb circuit qu.core.pnjit() - ## convert vector to MPS + # convert vector to MPS dims = tuple(2 * np.ones(nqubits, dtype=int)) init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense(init_state_quimb, dims) From b8f09ddf36cddf976fef8227c2ec5224263b043c Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 10:28:53 +0100 Subject: [PATCH 15/39] provide suiitable test --- pyproject.toml | 1 + setup.py | 7 ++++++- tests/test_qasm_quimb_backend.py | 9 +++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/test_qasm_quimb_backend.py diff --git a/pyproject.toml b/pyproject.toml index 5693b81..f2546e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,3 +4,4 @@ output-format = "colorized" [tool.pytest.ini_options] testpaths = ["tests/"] addopts = ["--cov=qibotn", "--cov-report=xml"] +env = ["D:NUMBA_DISABLE_JIT=1"] diff --git a/setup.py b/setup.py index 4306e33..532723b 100644 --- a/setup.py +++ b/setup.py @@ -24,11 +24,16 @@ setup( ], install_requires=[ "qibo>=0.1.10", + "qibojit>=0.0.7", "quimb[tensor]>=1.4.0", ], extras_require={ "docs": [], - "tests": ["pytest>=7.2.0", "pytest-cov>=4.0.0"], + "tests": [ + "pytest>=7.2.0", + "pytest-cov>=4.0.0", + "pytest-env>=0.8.1", + ], }, python_requires=">=3.7.0", long_description=LONG_DESCRIPTION, diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py new file mode 100644 index 0000000..d9e3cf9 --- /dev/null +++ b/tests/test_qasm_quimb_backend.py @@ -0,0 +1,9 @@ +import pytest + +from qibotn import qasm_quimb + + +@pytest.mark.parametrize("nqubits", [1, 2, 5, 10]) +def test_eval(nqubits: int): + print(f"Testing for {nqubits} nqubits") + result = qasm_quimb.eval_QI_qft(nqubits) From 35d47ecd1ca9d145ba21457a266c523f32f6032e Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 12:05:24 +0100 Subject: [PATCH 16/39] Add pylint dep --- .github/workflows/rules.yml | 1 + setup.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/rules.yml b/.github/workflows/rules.yml index e087400..4b2cb05 100644 --- a/.github/workflows/rules.yml +++ b/.github/workflows/rules.yml @@ -18,4 +18,5 @@ jobs: os: ${{ matrix.os }} python-version: ${{ matrix.python-version }} environment: "qibotn" + pip-extras: "analysis,tests" secrets: inherit diff --git a/setup.py b/setup.py index 532723b..08b5515 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,9 @@ setup( "pytest-cov>=4.0.0", "pytest-env>=0.8.1", ], + "analysis": [ + "pylint>=2.16.0", + ], }, python_requires=">=3.7.0", long_description=LONG_DESCRIPTION, From 73a747f2bd36efc1aea10334f150f4d5e2b66741 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 12:38:20 +0100 Subject: [PATCH 17/39] Temporary solution to qiboteam/qibojit#107 in tests --- tests/test_qasm_quimb_backend.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index d9e3cf9..ba99dcb 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -1,9 +1,12 @@ -import pytest +import os -from qibotn import qasm_quimb +import pytest @pytest.mark.parametrize("nqubits", [1, 2, 5, 10]) def test_eval(nqubits: int): + os.environ["QUIMB_NUM_PROCS"] = str(os.cpu_count()) + from qibotn import qasm_quimb + print(f"Testing for {nqubits} nqubits") result = qasm_quimb.eval_QI_qft(nqubits) From 82e8e872c0220107e8c23ee79b6a57d79820d5b1 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 7 Feb 2023 12:42:44 +0100 Subject: [PATCH 18/39] Fix and silence Pylint errors --- src/qibotn/__main__.py | 3 +-- src/qibotn/qasm_quimb.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qibotn/__main__.py b/src/qibotn/__main__.py index 807b547..2dbf82e 100644 --- a/src/qibotn/__main__.py +++ b/src/qibotn/__main__.py @@ -12,8 +12,7 @@ def parser(): def main(args: argparse.Namespace): print("Testing for %d nqubits" % (args.nqubits)) - result = qasm_quimb.eval_QI_qft(args.nqubits) - print(result) + qasm_quimb.eval_QI_qft(args.nqubits) if __name__ == "__main__": diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index 89242a9..1d7a5ce 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -111,14 +111,14 @@ def get_gate_params(operation): phi = float(".".join(angles[0:2])) lamba = float(".".join(angles[2:])) qbit_no = int(re.findall(r"\d+", operation)[0]) - qbit_no[0:0] = ["U2", phi, lamda] + qbit_no[0:0] = ["U2", phi, lamda] # pylint: disable=E1137 elif "^u3 " in operation: angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) theta = float(".".join(angles[0:2])) phi = float(".".join(angles[2:4])) lamba = float(".".join(angles[4:])) qbit_no = int(re.findall(r"\d+", operation)[0]) - qbit_no[0:0] = ["U3", theta, phi, lamda] + qbit_no[0:0] = ["U3", theta, phi, lamda] # pylint: disable=E1137 else: assert "Unsupported gate" From 75d21d46a3d5b5ead7f70e652a2ddbd462e18a70 Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Thu, 9 Feb 2023 16:34:31 +0800 Subject: [PATCH 19/39] Remove unused pnjit decorator --- src/qibotn/qasm_quimb.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index 1d7a5ce..2ac3797 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -195,7 +195,6 @@ def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=Tru ##################################################################### # Quimb circuit - qu.core.pnjit() # convert vector to MPS dims = tuple(2 * np.ones(nqubits, dtype=int)) init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense(init_state_quimb, dims) From 01a0d02bc2003f512acb1adc613837aff868034c Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Thu, 9 Feb 2023 18:35:57 +0800 Subject: [PATCH 20/39] Remove unneeded print() --- tests/test_qasm_quimb_backend.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index ba99dcb..77fcd54 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -8,5 +8,4 @@ def test_eval(nqubits: int): os.environ["QUIMB_NUM_PROCS"] = str(os.cpu_count()) from qibotn import qasm_quimb - print(f"Testing for {nqubits} nqubits") result = qasm_quimb.eval_QI_qft(nqubits) From 9ab7f5ec588bad14ccbcf3ab350f1070e9e3177d Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Thu, 9 Feb 2023 18:56:43 +0800 Subject: [PATCH 21/39] Remove printing of execution time. --- src/qibotn/qasm_quimb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index 2ac3797..9aa7f4b 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -190,7 +190,7 @@ def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=Tru circ_qibo = qibo_qft(nqubits, with_swaps) amplitudes_reference = np.array(circ_qibo(init_state)) end = timer() - print("qibo time is " + str(end - start)) + qibo_qft_time = end - start qasm_circ = circ_qibo.to_qasm() ##################################################################### From 0e4f01264c9a531089811a8e2fe89950ef1fa038 Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Thu, 9 Feb 2023 23:37:13 +0800 Subject: [PATCH 22/39] Refactor lamda and lamba to lambda_ --- src/qibotn/qasm_quimb.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index 9aa7f4b..c0193a3 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -30,27 +30,27 @@ def get_gate_params(operation): qbit_no = [int(re.findall(r"\d+", operation)[0])] qbit_no.insert(0, "T") elif "cu1" in operation: - lamda = float( + lambda_ = float( ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = re.findall(r"\d+", operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU1", lamda] + qbit_no[0:0] = ["CU1", lambda_] elif "cu2" in operation: angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) phi = float(".".join(angles[0:2])) - lamba = float(".".join(angles[2:])) + lambda_ = float(".".join(angles[2:])) qbit_no = re.findall(r"\d+", operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU2", phi, lamda] + qbit_no[0:0] = ["CU2", phi, lambda_] elif "cu3" in operation: angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) theta = float(".".join(angles[0:2])) phi = float(".".join(angles[2:4])) - lamba = float(".".join(angles[4:])) + lambda_ = float(".".join(angles[4:])) qbit_no = re.findall(r"\d+", operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU3", theta, phi, lamda] + qbit_no[0:0] = ["CU3", theta, phi, lambda_] elif " cx " in operation: qbit_no = re.findall(r"\d+", operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] @@ -101,24 +101,24 @@ def get_gate_params(operation): qbit_no = [int(x) for x in qbit_no] qbit_no[0:0] = ["RZZ", theta] elif "^u1 " in operation: - lamda = float( + lambda_ = float( ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no[0:0] = ["U1", lamda] + qbit_no[0:0] = ["U1", lambda_] elif "^u2 " in operation: angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) phi = float(".".join(angles[0:2])) - lamba = float(".".join(angles[2:])) + lambda_ = float(".".join(angles[2:])) qbit_no = int(re.findall(r"\d+", operation)[0]) - qbit_no[0:0] = ["U2", phi, lamda] # pylint: disable=E1137 + qbit_no[0:0] = ["U2", phi, lambda_] # pylint: disable=E1137 elif "^u3 " in operation: angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) theta = float(".".join(angles[0:2])) phi = float(".".join(angles[2:4])) - lamba = float(".".join(angles[4:])) + lambda_ = float(".".join(angles[4:])) qbit_no = int(re.findall(r"\d+", operation)[0]) - qbit_no[0:0] = ["U3", theta, phi, lamda] # pylint: disable=E1137 + qbit_no[0:0] = ["U3", theta, phi, lambda_] # pylint: disable=E1137 else: assert "Unsupported gate" From 877e7851b973c66866ac83992132c54efe174e97 Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Fri, 10 Feb 2023 00:19:37 +0800 Subject: [PATCH 23/39] Moved quimb calls into a separate core function --- src/qibotn/qasm_quimb.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index c0193a3..882b06d 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -173,6 +173,18 @@ def qasm_QFT(nqubits: int, qasm_str: str, with_swaps: bool = True, psi0=None): return circ +def tn_circ_eval(nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", + backend='numpy'): + if tn_lib == "quimb": + circ_quimb = qasm_QFT(nqubits, qasm_circ, swaps, psi0=init_state) + interim = circ_quimb.psi.full_simplify(seq="DRC") + result = interim.to_dense(backend=backend).flatten() + return result + else: + # TODO: Change assert or value. Add cuquantum later + assert False, "Unsupported tensor network library" + + def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=True): # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. # qibo_backend: qibojit, qibotf, tensorflow, numpy @@ -197,17 +209,14 @@ def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=Tru # Quimb circuit # convert vector to MPS dims = tuple(2 * np.ones(nqubits, dtype=int)) - init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense(init_state_quimb, dims) + init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense( + init_state_quimb, dims) # construct quimb qft circuit start = timer() - circ_quimb = qasm_QFT(nqubits, qasm_circ, with_swaps, psi0=init_state_MPS) - - interim = circ_quimb.psi.full_simplify(seq="DRC") - - result = interim.to_dense(backend=backend) - amplitudes = result.flatten() + amplitudes = tn_circ_eval(nqubits=nqubits, qasm_circ=qasm_circ, + init_state=init_state_MPS, swaps=with_swaps, + tn_lib="quimb") end = timer() quimb_qft_time = end - start - print("quimb time is " + str(quimb_qft_time)) assert np.allclose(amplitudes, amplitudes_reference, atol=1e-06) From 23babbd3a8c74c337483f134948b2dd7681852e4 Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Mon, 13 Feb 2023 17:41:59 +0800 Subject: [PATCH 24/39] Put the initialization of states into a function to facilitate testing --- src/qibotn/qasm_quimb.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index 882b06d..dd94db8 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -173,6 +173,19 @@ def qasm_QFT(nqubits: int, qasm_str: str, with_swaps: bool = True, psi0=None): return circ +def init_state_tn(nqubits, init_state_sv, tn_lib="quimb"): + dims = tuple(2 * np.ones(nqubits, dtype=int)) + + if tn_lib == "quimb": + init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense( + init_state_sv, dims) + else: + # TODO: Add cuquantum later + assert False, "Unsupported tensor network backend in initilization" + + return init_state_MPS + + def tn_circ_eval(nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", backend='numpy'): if tn_lib == "quimb": @@ -207,10 +220,8 @@ def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=Tru ##################################################################### # Quimb circuit - # convert vector to MPS - dims = tuple(2 * np.ones(nqubits, dtype=int)) - init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense( - init_state_quimb, dims) + init_state_MPS = init_state_tn(nqubits=nqubits, + init_state_sv=init_state_quimb) # construct quimb qft circuit start = timer() From a8aa3e2cffed79d40c47688fef7a7e59e831debd Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Tue, 14 Feb 2023 17:01:36 +0800 Subject: [PATCH 25/39] Add missing packages --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 2568f2b..30f5e17 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,6 @@ from setuptools import setup, find_packages +import os +import re import pathlib PACKAGE = "qibotn" From d3e0e113b0502e34df98d67dc8462a2d5c0b598d Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Tue, 14 Feb 2023 17:51:00 +0800 Subject: [PATCH 26/39] Add the end-of-line new line back as per autopep8 formatter --- src/qibotn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibotn/__init__.py b/src/qibotn/__init__.py index b1596d1..15addcb 100644 --- a/src/qibotn/__init__.py +++ b/src/qibotn/__init__.py @@ -1 +1 @@ -__version__ = "0.0.1.dev0" \ No newline at end of file +__version__ = "0.0.1.dev0" From 00fdf932b7380004f08cf38354fb732b5715163a Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 14 Feb 2023 14:05:35 +0100 Subject: [PATCH 27/39] Polish version retrieval and long description loading --- setup.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/setup.py b/setup.py index 30f5e17..aefac89 100644 --- a/setup.py +++ b/setup.py @@ -1,33 +1,30 @@ from setuptools import setup, find_packages -import os import re import pathlib +HERE = pathlib.Path(__file__).parent.absolute() PACKAGE = "qibotn" # Returns the qibotn version -def get_version(): - """ Gets the version from the package's __init__ file - if there is some problem, let it happily fail """ - VERSIONFILE = os.path.join("src", PACKAGE, "__init__.py") - initfile_lines = open(VERSIONFILE, "rt").readlines() - VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]" - for line in initfile_lines: - mo = re.search(VSRE, line, re.M) - if mo: - return mo.group(1) +def version(): + """Gets the version from the package's __init__ file + if there is some problem, let it happily fail""" + version_file = HERE / "src" / PACKAGE / "__init__.py" + version_regex = r"^__version__ = ['\"]([^'\"]*)['\"]" + + initfile = version_file.read_text(encoding="utf-8") + matched = re.search(version_regex, initfile, re.M) + + if matched is not None: + return matched.group(1) + return "0.0.0" # load long description from README -this_directory = os.path.abspath(os.path.dirname(__file__)) -with open(os.path.join(this_directory, "README.md"), encoding="utf-8") as f: - long_description = f.read() - - setup( name="qibotn", - version=get_version(), + version=version(), description="A tensor-network translation module for quantum computing", author="The Qibo team", author_email="", @@ -58,6 +55,6 @@ setup( ], }, python_requires=">=3.7.0", - long_description=long_description, - long_description_content_type='text/markdown', + long_description=(HERE / "README.md").read_text(encoding="utf-8"), + long_description_content_type="text/markdown", ) From 2e8e13aa0c7b4872fb1219e36e09fa0ec4999869 Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Tue, 14 Feb 2023 21:31:41 +0800 Subject: [PATCH 28/39] Updates to test file and library file to keep module and testing functions separate. The Config file needs to be reviewed to either change it to json or other formats. --- src/qibotn/qasm_quimb.py | 40 +++++---------------------- tests/test_qasm_quimb_backend.py | 46 +++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index dd94db8..a7fadc8 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -1,13 +1,8 @@ import re -import copy -from timeit import default_timer as timer -import numpy as np import quimb as qu import quimb.tensor as qtn - -import qibo -from qibo.models import QFT as qibo_qft +import numpy as np def get_gate_params(operation): @@ -189,6 +184,7 @@ def init_state_tn(nqubits, init_state_sv, tn_lib="quimb"): def tn_circ_eval(nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", backend='numpy'): if tn_lib == "quimb": + circ_quimb = qasm_QFT(nqubits, qasm_circ, swaps, psi0=init_state) interim = circ_quimb.psi.full_simplify(seq="DRC") result = interim.to_dense(backend=backend).flatten() @@ -198,36 +194,12 @@ def tn_circ_eval(nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", assert False, "Unsupported tensor network library" -def eval_QI_qft(nqubits, backend="numpy", qibo_backend="qibojit", with_swaps=True): +def eval_QI_qft(nqubits, qasm_circ, init_state, backend="numpy", swaps=True): # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. - # qibo_backend: qibojit, qibotf, tensorflow, numpy - # generate random statevector as initial state - init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) - init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) - init_state_quimb = copy.deepcopy(init_state) - - # Qibo circuit - # qibo.set_backend(backend=qibo_backend, platform="numba") - qibo.set_backend(backend=qibo_backend, platform="numpy") - - start = timer() - circ_qibo = qibo_qft(nqubits, with_swaps) - amplitudes_reference = np.array(circ_qibo(init_state)) - end = timer() - qibo_qft_time = end - start - qasm_circ = circ_qibo.to_qasm() - - ##################################################################### # Quimb circuit - init_state_MPS = init_state_tn(nqubits=nqubits, - init_state_sv=init_state_quimb) - - # construct quimb qft circuit - start = timer() + init_state_mps = init_state_tn(nqubits=nqubits, init_state_sv=init_state) amplitudes = tn_circ_eval(nqubits=nqubits, qasm_circ=qasm_circ, - init_state=init_state_MPS, swaps=with_swaps, + init_state=init_state_mps, swaps=swaps, tn_lib="quimb") - end = timer() - quimb_qft_time = end - start - assert np.allclose(amplitudes, amplitudes_reference, atol=1e-06) + return amplitudes \ No newline at end of file diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index 77fcd54..dfe83c9 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -1,6 +1,27 @@ import os import pytest +import qibo +from qibo.models import QFT +import numpy as np +import copy +from timeit import default_timer as timer + +import config + + +def init_state_sv(nqubits): + init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) + init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) + # An unmodified init_state has to be converted to tn format + init_state_for_tn = copy.deepcopy(init_state) + return init_state, init_state_for_tn + + +def qibo_qft(nqubits, init_state, swaps): + circ_qibo = QFT(nqubits, swaps) + state_vec = np.array(circ_qibo(init_state)) + return circ_qibo, state_vec @pytest.mark.parametrize("nqubits", [1, 2, 5, 10]) @@ -8,4 +29,27 @@ def test_eval(nqubits: int): os.environ["QUIMB_NUM_PROCS"] = str(os.cpu_count()) from qibotn import qasm_quimb - result = qasm_quimb.eval_QI_qft(nqubits) + init_state_qibo, init_state_for_tn = init_state_sv(nqubits=nqubits) + + # Test qibo + qibo.set_backend(backend=config.qibo['backend'], \ + platform=config.qibo['platform']) + start_time = timer() + qibo_circ, result_sv = qibo_qft(nqubits, init_state=init_state_qibo, \ + swaps=config.qibo['swaps']) + end_time = timer() + qibo_time = end_time - start_time + + # Convert to qasm for other backends + qasm_circ = qibo_circ.to_qasm() + + # Test quimb + start_time = timer() + result_tn = qasm_quimb.eval_QI_qft(nqubits=nqubits, qasm_circ=qasm_circ, \ + init_state=init_state_for_tn, backend=config.quimb['backend'], \ + swaps=config.quimb['swaps']) + end_time = timer() + quimb_time = end_time - start_time + + assert np.allclose(result_sv, result_tn), \ + "Resulting dense vectors do not match" From 46d7c30caf3dc506d339edc2c64c7e44ca3b2af8 Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Tue, 14 Feb 2023 21:36:08 +0800 Subject: [PATCH 29/39] Adding config file to store the initial setup parameters --- tests/config.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/config.py diff --git a/tests/config.py b/tests/config.py new file mode 100644 index 0000000..fbdd3dd --- /dev/null +++ b/tests/config.py @@ -0,0 +1,10 @@ +qibo = dict( + backend = 'qibojit', + platform = 'numpy', + swaps = True +) + +quimb = dict( + backend = 'numpy', + swaps = True +) \ No newline at end of file From bc13eed8f44ca6f7be0cbb447daede6b460f23e7 Mon Sep 17 00:00:00 2001 From: Nitin Shivaraman Date: Tue, 14 Feb 2023 21:42:05 +0800 Subject: [PATCH 30/39] Added newline at the end of the file; fixed the arguments for eval_qft function in main file. --- src/qibotn/__main__.py | 2 +- tests/config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibotn/__main__.py b/src/qibotn/__main__.py index 2dbf82e..8ed7439 100644 --- a/src/qibotn/__main__.py +++ b/src/qibotn/__main__.py @@ -12,7 +12,7 @@ def parser(): def main(args: argparse.Namespace): print("Testing for %d nqubits" % (args.nqubits)) - qasm_quimb.eval_QI_qft(args.nqubits) + qasm_quimb.eval_QI_qft(args.nqubits, args.qasm_circ, args.init_state) if __name__ == "__main__": diff --git a/tests/config.py b/tests/config.py index fbdd3dd..96621a2 100644 --- a/tests/config.py +++ b/tests/config.py @@ -7,4 +7,4 @@ qibo = dict( quimb = dict( backend = 'numpy', swaps = True -) \ No newline at end of file +) From 53382b8184761409e81d6be4fbd17b3be3931ace Mon Sep 17 00:00:00 2001 From: Liwei Yang Date: Wed, 15 Feb 2023 17:28:06 +0800 Subject: [PATCH 31/39] Use autopep8 for PEP-8 formatting --- src/qibotn/qasm_quimb.py | 22 ++++++++++++++-------- tests/test_qasm_quimb_backend.py | 18 ++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index a7fadc8..a552ad0 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -26,7 +26,8 @@ def get_gate_params(operation): qbit_no.insert(0, "T") elif "cu1" in operation: lambda_ = float( - ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ".".join(re.findall( + r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = re.findall(r"\d+", operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] @@ -72,32 +73,37 @@ def get_gate_params(operation): qbit_no.insert(0, "CCZ") elif " rx " in operation: theta = float( - ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ".".join(re.findall( + r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = [int(re.findall(r"\d+", operation)[0])] qbit_no[0:0] = ["RX", theta] elif "^ry " in operation: theta = float( - ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ".".join(re.findall( + r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = [int(re.findall(r"\d+", operation)[0])] qbit_no[0:0] = ["RY", theta] elif "^rz " in operation: theta = float( - ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ".".join(re.findall( + r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = [int(re.findall(r"\d+", operation)[0])] qbit_no[0:0] = ["RZ", theta] elif "^rzz " in operation: theta = float( - ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ".".join(re.findall( + r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = re.findall(r"\d+", operation.split(" ")[1]) qbit_no = [int(x) for x in qbit_no] qbit_no[0:0] = ["RZZ", theta] elif "^u1 " in operation: lambda_ = float( - ".".join(re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) + ".".join(re.findall( + r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) ) qbit_no = [int(re.findall(r"\d+", operation)[0])] qbit_no[0:0] = ["U1", lambda_] @@ -182,7 +188,7 @@ def init_state_tn(nqubits, init_state_sv, tn_lib="quimb"): def tn_circ_eval(nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", - backend='numpy'): + backend='numpy'): if tn_lib == "quimb": circ_quimb = qasm_QFT(nqubits, qasm_circ, swaps, psi0=init_state) @@ -202,4 +208,4 @@ def eval_QI_qft(nqubits, qasm_circ, init_state, backend="numpy", swaps=True): amplitudes = tn_circ_eval(nqubits=nqubits, qasm_circ=qasm_circ, init_state=init_state_mps, swaps=swaps, tn_lib="quimb") - return amplitudes \ No newline at end of file + return amplitudes diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index dfe83c9..450104b 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -11,7 +11,8 @@ import config def init_state_sv(nqubits): - init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) + init_state = np.random.random(2**nqubits) + \ + 1j * np.random.random(2**nqubits) init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) # An unmodified init_state has to be converted to tn format init_state_for_tn = copy.deepcopy(init_state) @@ -32,11 +33,11 @@ def test_eval(nqubits: int): init_state_qibo, init_state_for_tn = init_state_sv(nqubits=nqubits) # Test qibo - qibo.set_backend(backend=config.qibo['backend'], \ - platform=config.qibo['platform']) + qibo.set_backend(backend=config.qibo['backend'], + platform=config.qibo['platform']) start_time = timer() - qibo_circ, result_sv = qibo_qft(nqubits, init_state=init_state_qibo, \ - swaps=config.qibo['swaps']) + qibo_circ, result_sv = qibo_qft(nqubits, init_state=init_state_qibo, + swaps=config.qibo['swaps']) end_time = timer() qibo_time = end_time - start_time @@ -45,9 +46,10 @@ def test_eval(nqubits: int): # Test quimb start_time = timer() - result_tn = qasm_quimb.eval_QI_qft(nqubits=nqubits, qasm_circ=qasm_circ, \ - init_state=init_state_for_tn, backend=config.quimb['backend'], \ - swaps=config.quimb['swaps']) + result_tn = qasm_quimb.eval_QI_qft(nqubits=nqubits, qasm_circ=qasm_circ, + init_state=init_state_for_tn, + backend=config.quimb['backend'], + swaps=config.quimb['swaps']) end_time = timer() quimb_time = end_time - start_time From d42041ec3911a5437dbe3d38740b1bd3f364fb21 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 15 Feb 2023 17:18:06 +0100 Subject: [PATCH 32/39] Drop tests on MacOS not to exceed billing quota --- .github/workflows/rules.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rules.yml b/.github/workflows/rules.yml index 4b2cb05..727612d 100644 --- a/.github/workflows/rules.yml +++ b/.github/workflows/rules.yml @@ -11,7 +11,7 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'run-workflow') || github.event_name == 'push' strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, windows-latest] python-version: [3.7, 3.8, 3.9, "3.10"] uses: qiboteam/workflows/.github/workflows/rules.yml@main with: From ed624c1889ac30fb7c960eef19d3b2cfe84a03bd Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Thu, 16 Feb 2023 08:23:52 +0100 Subject: [PATCH 33/39] Drop tests on Windows not to exceed billing quota --- .github/workflows/rules.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rules.yml b/.github/workflows/rules.yml index 727612d..177ed86 100644 --- a/.github/workflows/rules.yml +++ b/.github/workflows/rules.yml @@ -11,7 +11,7 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'run-workflow') || github.event_name == 'push' strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest] python-version: [3.7, 3.8, 3.9, "3.10"] uses: qiboteam/workflows/.github/workflows/rules.yml@main with: From c07d9bf6c9931e84b6a4f7bebcd22a84b78ff3f6 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 15 Feb 2023 11:01:24 +0100 Subject: [PATCH 34/39] Drop previous parser --- src/qibotn/qasm_quimb.py | 139 +++---------------------------- tests/test_qasm_quimb_backend.py | 26 +++--- 2 files changed, 26 insertions(+), 139 deletions(-) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/qasm_quimb.py index a552ad0..f7546eb 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/qasm_quimb.py @@ -5,127 +5,6 @@ import quimb.tensor as qtn import numpy as np -def get_gate_params(operation): - if "h " in operation: - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no.insert(0, "H") - elif "x " in operation: - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no.insert(0, "X") - elif "y " in operation: - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no.insert(0, "Y") - elif "z " in operation: - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no.insert(0, "Z") - elif "s " in operation: - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no.insert(0, "S") - elif "t " in operation: - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no.insert(0, "T") - elif "cu1" in operation: - lambda_ = float( - ".".join(re.findall( - r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) - ) - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU1", lambda_] - elif "cu2" in operation: - angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) - phi = float(".".join(angles[0:2])) - lambda_ = float(".".join(angles[2:])) - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU2", phi, lambda_] - elif "cu3" in operation: - angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) - theta = float(".".join(angles[0:2])) - phi = float(".".join(angles[2:4])) - lambda_ = float(".".join(angles[4:])) - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["CU3", theta, phi, lambda_] - elif " cx " in operation: - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CX") - elif " cy " in operation: - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CY") - elif " cz " in operation: - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CZ") - elif " ccx " in operation: - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CCX") - elif " ccy " in operation: - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CCY") - elif " ccz " in operation: - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no.insert(0, "CCZ") - elif " rx " in operation: - theta = float( - ".".join(re.findall( - r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) - ) - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no[0:0] = ["RX", theta] - elif "^ry " in operation: - theta = float( - ".".join(re.findall( - r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) - ) - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no[0:0] = ["RY", theta] - elif "^rz " in operation: - theta = float( - ".".join(re.findall( - r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) - ) - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no[0:0] = ["RZ", theta] - elif "^rzz " in operation: - theta = float( - ".".join(re.findall( - r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) - ) - qbit_no = re.findall(r"\d+", operation.split(" ")[1]) - qbit_no = [int(x) for x in qbit_no] - qbit_no[0:0] = ["RZZ", theta] - elif "^u1 " in operation: - lambda_ = float( - ".".join(re.findall( - r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0])) - ) - qbit_no = [int(re.findall(r"\d+", operation)[0])] - qbit_no[0:0] = ["U1", lambda_] - elif "^u2 " in operation: - angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) - phi = float(".".join(angles[0:2])) - lambda_ = float(".".join(angles[2:])) - qbit_no = int(re.findall(r"\d+", operation)[0]) - qbit_no[0:0] = ["U2", phi, lambda_] # pylint: disable=E1137 - elif "^u3 " in operation: - angles = re.findall(r"\b\d+(?:[Ee][+-]?\d+)?", operation.split(" ")[0]) - theta = float(".".join(angles[0:2])) - phi = float(".".join(angles[2:4])) - lambda_ = float(".".join(angles[4:])) - qbit_no = int(re.findall(r"\d+", operation)[0]) - qbit_no[0:0] = ["U3", theta, phi, lambda_] # pylint: disable=E1137 - else: - assert "Unsupported gate" - - return qbit_no - - def get_gate_functions(qasm_str, start_idx): func_list = [] result = [] @@ -179,7 +58,8 @@ def init_state_tn(nqubits, init_state_sv, tn_lib="quimb"): if tn_lib == "quimb": init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense( - init_state_sv, dims) + init_state_sv, dims + ) else: # TODO: Add cuquantum later assert False, "Unsupported tensor network backend in initilization" @@ -187,8 +67,9 @@ def init_state_tn(nqubits, init_state_sv, tn_lib="quimb"): return init_state_MPS -def tn_circ_eval(nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", - backend='numpy'): +def tn_circ_eval( + nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", backend="numpy" +): if tn_lib == "quimb": circ_quimb = qasm_QFT(nqubits, qasm_circ, swaps, psi0=init_state) @@ -205,7 +86,11 @@ def eval_QI_qft(nqubits, qasm_circ, init_state, backend="numpy", swaps=True): # Quimb circuit init_state_mps = init_state_tn(nqubits=nqubits, init_state_sv=init_state) - amplitudes = tn_circ_eval(nqubits=nqubits, qasm_circ=qasm_circ, - init_state=init_state_mps, swaps=swaps, - tn_lib="quimb") + amplitudes = tn_circ_eval( + nqubits=nqubits, + qasm_circ=qasm_circ, + init_state=init_state_mps, + swaps=swaps, + tn_lib="quimb", + ) return amplitudes diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index 450104b..edb99a2 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -11,8 +11,7 @@ import config def init_state_sv(nqubits): - init_state = np.random.random(2**nqubits) + \ - 1j * np.random.random(2**nqubits) + init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) # An unmodified init_state has to be converted to tn format init_state_for_tn = copy.deepcopy(init_state) @@ -33,25 +32,28 @@ def test_eval(nqubits: int): init_state_qibo, init_state_for_tn = init_state_sv(nqubits=nqubits) # Test qibo - qibo.set_backend(backend=config.qibo['backend'], - platform=config.qibo['platform']) + qibo.set_backend(backend=config.qibo["backend"], platform=config.qibo["platform"]) start_time = timer() - qibo_circ, result_sv = qibo_qft(nqubits, init_state=init_state_qibo, - swaps=config.qibo['swaps']) + qibo_circ, result_sv = qibo_qft( + nqubits, init_state=init_state_qibo, swaps=config.qibo["swaps"] + ) end_time = timer() qibo_time = end_time - start_time # Convert to qasm for other backends qasm_circ = qibo_circ.to_qasm() + __import__("pdb").set_trace() # Test quimb start_time = timer() - result_tn = qasm_quimb.eval_QI_qft(nqubits=nqubits, qasm_circ=qasm_circ, - init_state=init_state_for_tn, - backend=config.quimb['backend'], - swaps=config.quimb['swaps']) + result_tn = qasm_quimb.eval_QI_qft( + nqubits=nqubits, + qasm_circ=qasm_circ, + init_state=init_state_for_tn, + backend=config.quimb["backend"], + swaps=config.quimb["swaps"], + ) end_time = timer() quimb_time = end_time - start_time - assert np.allclose(result_sv, result_tn), \ - "Resulting dense vectors do not match" + assert np.allclose(result_sv, result_tn), "Resulting dense vectors do not match" From 250c41bf4dbe72508ec32eafe2cd231942188d8c Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 15 Feb 2023 12:37:50 +0100 Subject: [PATCH 35/39] Start reworking qasm parser --- src/qibotn/{qasm_quimb.py => quimb.py} | 48 +++++++------------------- tests/test_qasm_quimb_backend.py | 11 +++--- 2 files changed, 17 insertions(+), 42 deletions(-) rename src/qibotn/{qasm_quimb.py => quimb.py} (55%) diff --git a/src/qibotn/qasm_quimb.py b/src/qibotn/quimb.py similarity index 55% rename from src/qibotn/qasm_quimb.py rename to src/qibotn/quimb.py index f7546eb..93457f4 100644 --- a/src/qibotn/qasm_quimb.py +++ b/src/qibotn/quimb.py @@ -1,6 +1,6 @@ import re -import quimb as qu +import qibo import quimb.tensor as qtn import numpy as np @@ -22,7 +22,7 @@ def get_gate_functions(qasm_str, start_idx): idx_inc += 1 -def qasm_QFT(nqubits: int, qasm_str: str, with_swaps: bool = True, psi0=None): +def convert(nqubits: int, qasm_str: str, with_swaps: bool = True, psi0=None): circ = qtn.Circuit(nqubits, psi0=psi0) qasm_str = qasm_str.split("\n") @@ -53,44 +53,22 @@ def qasm_QFT(nqubits: int, qasm_str: str, with_swaps: bool = True, psi0=None): return circ -def init_state_tn(nqubits, init_state_sv, tn_lib="quimb"): +def init_state_tn(nqubits, init_state_sv): dims = tuple(2 * np.ones(nqubits, dtype=int)) - if tn_lib == "quimb": - init_state_MPS = qtn.tensor_1d.MatrixProductState.from_dense( - init_state_sv, dims - ) - else: - # TODO: Add cuquantum later - assert False, "Unsupported tensor network backend in initilization" - - return init_state_MPS + return qtn.tensor_1d.MatrixProductState.from_dense(init_state_sv, dims) -def tn_circ_eval( - nqubits, qasm_circ, init_state, swaps=True, tn_lib="quimb", backend="numpy" -): - if tn_lib == "quimb": +def eval(qasm: str, init_state, backend="numpy", swaps=True): + """Evaluate QASM with Quimb - circ_quimb = qasm_QFT(nqubits, qasm_circ, swaps, psi0=init_state) - interim = circ_quimb.psi.full_simplify(seq="DRC") - result = interim.to_dense(backend=backend).flatten() - return result - else: - # TODO: Change assert or value. Add cuquantum later - assert False, "Unsupported tensor network library" + backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. + """ + circuit = qibo.models.Circuit.from_qasm(qasm) + init_state_mps = init_state_tn(circuit.nqubits, init_state) + circ_quimb = convert(circuit, swaps=swaps, psi0=init_state_mps) + interim = circ_quimb.psi.full_simplify(seq="DRC") + amplitudes = interim.to_dense(backend=backend).flatten() -def eval_QI_qft(nqubits, qasm_circ, init_state, backend="numpy", swaps=True): - # backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. - - # Quimb circuit - init_state_mps = init_state_tn(nqubits=nqubits, init_state_sv=init_state) - amplitudes = tn_circ_eval( - nqubits=nqubits, - qasm_circ=qasm_circ, - init_state=init_state_mps, - swaps=swaps, - tn_lib="quimb", - ) return amplitudes diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index edb99a2..9f4c854 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -14,8 +14,7 @@ def init_state_sv(nqubits): init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) # An unmodified init_state has to be converted to tn format - init_state_for_tn = copy.deepcopy(init_state) - return init_state, init_state_for_tn + return init_state def qibo_qft(nqubits, init_state, swaps): @@ -29,14 +28,12 @@ def test_eval(nqubits: int): os.environ["QUIMB_NUM_PROCS"] = str(os.cpu_count()) from qibotn import qasm_quimb - init_state_qibo, init_state_for_tn = init_state_sv(nqubits=nqubits) + init_state = init_state_sv(nqubits=nqubits) # Test qibo qibo.set_backend(backend=config.qibo["backend"], platform=config.qibo["platform"]) start_time = timer() - qibo_circ, result_sv = qibo_qft( - nqubits, init_state=init_state_qibo, swaps=config.qibo["swaps"] - ) + qibo_circ, result_sv = qibo_qft(nqubits, init_state, swaps=config.qibo["swaps"]) end_time = timer() qibo_time = end_time - start_time @@ -49,7 +46,7 @@ def test_eval(nqubits: int): result_tn = qasm_quimb.eval_QI_qft( nqubits=nqubits, qasm_circ=qasm_circ, - init_state=init_state_for_tn, + init_state=copy.deepcopy(init_state), backend=config.quimb["backend"], swaps=config.quimb["swaps"], ) From bdecea17edd18905600a8bb8db90c2c8a6368054 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 15 Feb 2023 13:13:10 +0100 Subject: [PATCH 36/39] Clean up tests --- src/qibotn/quimb.py | 8 +++--- tests/config.py | 21 ++++++++------- tests/test_qasm_quimb_backend.py | 46 +++++++++++++++++++------------- 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/qibotn/quimb.py b/src/qibotn/quimb.py index 93457f4..4f7244f 100644 --- a/src/qibotn/quimb.py +++ b/src/qibotn/quimb.py @@ -1,6 +1,6 @@ import re -import qibo +from qibo.models import Circuit as QiboCircuit import quimb.tensor as qtn import numpy as np @@ -22,7 +22,7 @@ def get_gate_functions(qasm_str, start_idx): idx_inc += 1 -def convert(nqubits: int, qasm_str: str, with_swaps: bool = True, psi0=None): +def from_qibo(circuit: QiboCircuit, with_swaps: bool = True, psi0=None): circ = qtn.Circuit(nqubits, psi0=psi0) qasm_str = qasm_str.split("\n") @@ -65,9 +65,9 @@ def eval(qasm: str, init_state, backend="numpy", swaps=True): backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. """ - circuit = qibo.models.Circuit.from_qasm(qasm) + circuit = QiboCircuit.from_qasm(qasm) init_state_mps = init_state_tn(circuit.nqubits, init_state) - circ_quimb = convert(circuit, swaps=swaps, psi0=init_state_mps) + circ_quimb = from_qibo(circuit, swaps=swaps, psi0=init_state_mps) interim = circ_quimb.psi.full_simplify(seq="DRC") amplitudes = interim.to_dense(backend=backend).flatten() diff --git a/tests/config.py b/tests/config.py index 96621a2..7570e30 100644 --- a/tests/config.py +++ b/tests/config.py @@ -1,10 +1,13 @@ -qibo = dict( - backend = 'qibojit', - platform = 'numpy', - swaps = True -) +from dataclasses import dataclass +from typing import Optional -quimb = dict( - backend = 'numpy', - swaps = True -) + +@dataclass +class Executor: + backend: str + platform: Optional[str] = None + swaps: bool = True + + +qibo = Executor(backend="qibojit", platform="numpy") +quimb = Executor(backend="numpy") diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index 9f4c854..db1ad27 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -10,10 +10,9 @@ from timeit import default_timer as timer import config -def init_state_sv(nqubits): +def create_init_state(nqubits): init_state = np.random.random(2**nqubits) + 1j * np.random.random(2**nqubits) init_state = init_state / np.sqrt((np.abs(init_state) ** 2).sum()) - # An unmodified init_state has to be converted to tn format return init_state @@ -23,34 +22,43 @@ def qibo_qft(nqubits, init_state, swaps): return circ_qibo, state_vec +def time(func): + start = timer() + res = func() + end = timer() + time = end - start + return time, res + + @pytest.mark.parametrize("nqubits", [1, 2, 5, 10]) def test_eval(nqubits: int): + # hack quimb to use the correct number of processes + # TODO: remove completely, or at least delegate to the backend + # implementation os.environ["QUIMB_NUM_PROCS"] = str(os.cpu_count()) - from qibotn import qasm_quimb + import qibotn.quimb - init_state = init_state_sv(nqubits=nqubits) + init_state = create_init_state(nqubits=nqubits) + init_state_tn = copy.deepcopy(init_state) # Test qibo - qibo.set_backend(backend=config.qibo["backend"], platform=config.qibo["platform"]) - start_time = timer() - qibo_circ, result_sv = qibo_qft(nqubits, init_state, swaps=config.qibo["swaps"]) - end_time = timer() - qibo_time = end_time - start_time + qibo.set_backend(backend=config.qibo.backend, platform=config.qibo.platform) + qibo_time, (qibo_circ, result_sv) = time( + lambda: qibo_qft(nqubits, init_state, swaps=config.qibo.swaps) + ) # Convert to qasm for other backends qasm_circ = qibo_circ.to_qasm() - __import__("pdb").set_trace() # Test quimb - start_time = timer() - result_tn = qasm_quimb.eval_QI_qft( - nqubits=nqubits, - qasm_circ=qasm_circ, - init_state=copy.deepcopy(init_state), - backend=config.quimb["backend"], - swaps=config.quimb["swaps"], + quimb_time, result_tn = time( + lambda: qibotn.quimb.eval( + qasm_circ, + init_state_tn, + backend=config.quimb.backend, + swaps=config.quimb.swaps, + ) ) - end_time = timer() - quimb_time = end_time - start_time + assert 1e-2 * qibo_time < quimb_time < 1e2 * qibo_time assert np.allclose(result_sv, result_tn), "Resulting dense vectors do not match" From 458ad3cfc53817e37b5c57232342d982cd9fedfe Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 15 Feb 2023 13:34:32 +0100 Subject: [PATCH 37/39] Add pre-commit --- .pre-commit-config.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..177c408 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,25 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: check-merge-conflict + - id: debug-statements + - repo: https://github.com/psf/black + rev: 23.1.0 + hooks: + - id: black + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + args: ["--profile", "black"] + - repo: https://github.com/asottile/pyupgrade + rev: v3.3.1 + hooks: + - id: pyupgrade From 0af53d1ab0ad4256c73fedfd551ef02577ccced5 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 15 Feb 2023 13:35:00 +0100 Subject: [PATCH 38/39] Drop gate definition parser --- src/qibotn/quimb.py | 56 ++++++++------------------------------------- 1 file changed, 10 insertions(+), 46 deletions(-) diff --git a/src/qibotn/quimb.py b/src/qibotn/quimb.py index 4f7244f..46a527c 100644 --- a/src/qibotn/quimb.py +++ b/src/qibotn/quimb.py @@ -1,56 +1,20 @@ -import re - -from qibo.models import Circuit as QiboCircuit -import quimb.tensor as qtn import numpy as np +import quimb.tensor as qtn +from qibo.models import Circuit as QiboCircuit -def get_gate_functions(qasm_str, start_idx): - func_list = [] - result = [] - idx_inc = 0 - for line in qasm_str[start_idx:]: - if "gate " in line: - result = re.findall("[^,\s()]+", line) - elif result and "{" not in line and "}" not in line: - params = get_gate_params(line) - func_list.append(*params) - elif "}" in line: - print("Returning the list") - print(func_list) - return func_list, idx_inc - idx_inc += 1 +def from_qibo(circuit: QiboCircuit, swaps: bool = True, psi0=None): + nqubits = circuit.nqubits + tncirc = qtn.Circuit(nqubits, psi0=psi0) + for gate in circuit.queue: + tncirc.apply_gate(gate.name) -def from_qibo(circuit: QiboCircuit, with_swaps: bool = True, psi0=None): - circ = qtn.Circuit(nqubits, psi0=psi0) - - qasm_str = qasm_str.split("\n") - for idx, line in enumerate(qasm_str): - command = line.split(" ")[0] - if re.search("include|//|OPENQASM", command): - continue - elif "qreg" in command: - nbits = int(re.findall(r"\d+", line)[0]) - assert nbits == nqubits - elif "swap" in command: - break - elif "gate" in command: # TODO: Complete gate handling - gate_func, increment = get_gate_functions(qasm_str, idx) - pass - elif "barrier" in command: # TODO: Complete barrier handling - pass - elif "measure" in command: # TODO: Complete measure handling - pass - else: - params = get_gate_params(line) - circ.apply_gate(*params) - - if with_swaps: + if swaps: for i in range(nqubits // 2): # TODO: Ignore the barrier indices? - circ.apply_gate("SWAP", i, nqubits - i - 1) + tncirc.apply_gate("SWAP", i, nqubits - i - 1) - return circ + return tncirc def init_state_tn(nqubits, init_state_sv): From 662adfe1585c7eebede9006a76dfd379ff13734c Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 15 Feb 2023 16:36:42 +0100 Subject: [PATCH 39/39] Drop circuit-specific dedicated handling for swaps --- src/qibotn/quimb.py | 17 +++++++++-------- tests/config.py | 1 - tests/test_qasm_quimb_backend.py | 18 +++++++----------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/qibotn/quimb.py b/src/qibotn/quimb.py index 46a527c..8414540 100644 --- a/src/qibotn/quimb.py +++ b/src/qibotn/quimb.py @@ -3,16 +3,17 @@ import quimb.tensor as qtn from qibo.models import Circuit as QiboCircuit -def from_qibo(circuit: QiboCircuit, swaps: bool = True, psi0=None): +def from_qibo(circuit: QiboCircuit, psi0=None): nqubits = circuit.nqubits tncirc = qtn.Circuit(nqubits, psi0=psi0) for gate in circuit.queue: - tncirc.apply_gate(gate.name) - - if swaps: - for i in range(nqubits // 2): # TODO: Ignore the barrier indices? - tncirc.apply_gate("SWAP", i, nqubits - i - 1) + tncirc.apply_gate( + gate.name, + *gate.parameters, + *gate.qubits, + parametrize=len(gate.parameters) > 0 + ) return tncirc @@ -23,7 +24,7 @@ def init_state_tn(nqubits, init_state_sv): return qtn.tensor_1d.MatrixProductState.from_dense(init_state_sv, dims) -def eval(qasm: str, init_state, backend="numpy", swaps=True): +def eval(qasm: str, init_state, backend="numpy"): """Evaluate QASM with Quimb backend (quimb): numpy, cupy, jax. Passed to ``opt_einsum``. @@ -31,7 +32,7 @@ def eval(qasm: str, init_state, backend="numpy", swaps=True): """ circuit = QiboCircuit.from_qasm(qasm) init_state_mps = init_state_tn(circuit.nqubits, init_state) - circ_quimb = from_qibo(circuit, swaps=swaps, psi0=init_state_mps) + circ_quimb = from_qibo(circuit, psi0=init_state_mps) interim = circ_quimb.psi.full_simplify(seq="DRC") amplitudes = interim.to_dense(backend=backend).flatten() diff --git a/tests/config.py b/tests/config.py index 7570e30..7403673 100644 --- a/tests/config.py +++ b/tests/config.py @@ -6,7 +6,6 @@ from typing import Optional class Executor: backend: str platform: Optional[str] = None - swaps: bool = True qibo = Executor(backend="qibojit", platform="numpy") diff --git a/tests/test_qasm_quimb_backend.py b/tests/test_qasm_quimb_backend.py index db1ad27..e962018 100644 --- a/tests/test_qasm_quimb_backend.py +++ b/tests/test_qasm_quimb_backend.py @@ -1,13 +1,12 @@ -import os - -import pytest -import qibo -from qibo.models import QFT -import numpy as np import copy +import os from timeit import default_timer as timer import config +import numpy as np +import pytest +import qibo +from qibo.models import QFT def create_init_state(nqubits): @@ -44,7 +43,7 @@ def test_eval(nqubits: int): # Test qibo qibo.set_backend(backend=config.qibo.backend, platform=config.qibo.platform) qibo_time, (qibo_circ, result_sv) = time( - lambda: qibo_qft(nqubits, init_state, swaps=config.qibo.swaps) + lambda: qibo_qft(nqubits, init_state, swaps=True) ) # Convert to qasm for other backends @@ -53,10 +52,7 @@ def test_eval(nqubits: int): # Test quimb quimb_time, result_tn = time( lambda: qibotn.quimb.eval( - qasm_circ, - init_state_tn, - backend=config.quimb.backend, - swaps=config.quimb.swaps, + qasm_circ, init_state_tn, backend=config.quimb.backend ) )