From 9cd1dc9dbc96ac66f5d20d19a12700170e9e860f Mon Sep 17 00:00:00 2001 From: "Davide Gessa (dakk)" Date: Thu, 26 Oct 2023 11:31:33 +0200 Subject: [PATCH] new example, minor fixes --- docs/source/howitworks.rst | 123 +++++++++++------------- examples/ex1_2.py | 35 +++++++ qlasskit/compiler/compiler.py | 4 +- qlasskit/compiler/tweedledumcompiler.py | 7 +- qlasskit/qcircuit.py | 2 +- test/test_qlassf_for_loop.py | 5 + 6 files changed, 103 insertions(+), 73 deletions(-) create mode 100644 examples/ex1_2.py diff --git a/docs/source/howitworks.rst b/docs/source/howitworks.rst index dbe30828..649dee3d 100644 --- a/docs/source/howitworks.rst +++ b/docs/source/howitworks.rst @@ -14,66 +14,55 @@ For instance, let assume we have the following function: .. code-block:: python - def f_comp(n: Qint4) -> bool: - return n > 3 or n == 7 + def f_comp(b: bool, n: Qint2) -> Qint2: + for i in range(3): + n += (1 if b else 2) + return n -If we compile the whole function to a quantum circuit, we obtain the following circuit, created by -this boolean expression `n.2 | n.3 | (n.0 & n.1 & n.2 & ~n.3)`: +If we compile the whole function to a quantum circuit, we obtain the following quantum circuit: .. code-block:: text - f_comp - q_0: ───░─────────────────────■───────────────── - ░ │ - q_1: ───░─────────────────────■───────────────── - ░ │ - q_2: ───░──────■──────────────■───────────────── - ░ │ │ - q_3: ───░──────┼────■─────────┼───────────────── - ░ ┌─┴─┐ │ ┌───┐ │ - q_4: ───░────┤ X ├──┼──┤ X ├──┼─────────■─────── - ░ └───┘┌─┴─┐├───┤ │ │ - q_5: ───░─────────┤ X ├┤ X ├──■─────────■─────── - ░ └───┘└───┘┌─┴─┐┌───┐ │ - q_6: ───░───────────────────┤ X ├┤ X ├──■─────── - ░ └───┘└───┘┌─┴─┐┌───┐ - q_7: ───░─────────────────────────────┤ X ├┤ X ├ - ░ └───┘└───┘ - - -While if we decompose the function in 3 operations `n==7`, `n>3`, `a and b`, we obtain something like -the following circuit (qubit uncomputing is disabled to show the real number of gates): + q_0: ───░──────■────■────■────■────■────■────■───────────────── + ░ │ ┌─┴─┐ │ ┌─┴─┐ │ │ │ + q_1: ───░──────■──┤ X ├──■──┤ X ├──■────┼────┼────■──────────── + ░ │ └───┘ │ └───┘ │ │ │ │ + q_2: ───░──────┼─────────┼─────────┼────┼────┼────┼────■─────── + ░ │ │ │ ┌─┴─┐ │ ┌─┴─┐ │ + q_3: ───░──────┼─────────┼─────────┼──┤ X ├──┼──┤ X ├──┼─────── + ░ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐└───┘┌─┴─┐└───┘┌─┴─┐┌───┐ + q_4: ───░────┤ X ├─────┤ X ├─────┤ X ├─────┤ X ├─────┤ X ├┤ X ├ + ░ └───┘ └───┘ └───┘ └───┘ └───┘└───┘ + + -.. code-block:: text - = > | - q_0: ─░─────────────■───░───────────────────────────░────────────────────────── - ░ │ ░ ░ - q_1: ─░─────────────■───░───────────────────────────░────────────────────────── - ░ │ ░ ░ - q_2: ─░─────────────■───░───■───────────────────────░────────────────────────── - ░ │ ░ │ ░ - q_3: ─░───■─────────┼───░───┼────■──────────────────░────────────────────────── - ░ ┌─┴─┐┌───┐ │ ░ │ │ ░ - q_4: ─░─┤ X ├┤ X ├──■───░───┼────┼──────────────────░────────────────────────── - ░ └───┘└───┘┌─┴─┐ ░ │ │ ░ - q_5: ─░───────────┤ X ├─░───┼────┼──────────────────░───■────────────────────── - ░ └───┘ ░ │ │ ░ │ - q_6: ─░─────────────────░───┼────┼──────────────────░───┼────────────────────── - ░ ░ ┌─┴─┐ │ ┌───┐ ░ │ - q_7: ─░─────────────────░─┤ X ├──┼──┤ X ├──■────────░───┼────────────────────── - ░ ░ └───┘┌─┴─┐├───┤ │ ░ │ - q_8: ─░─────────────────░──────┤ X ├┤ X ├──■────────░───┼────────────────────── - ░ ░ └───┘└───┘┌─┴─┐┌───┐ ░ │ - q_9: ─░─────────────────░────────────────┤ X ├┤ X ├─░───┼────■───────────────── - ░ ░ └───┘└───┘ ░ ┌─┴─┐ │ ┌───┐ - q_10: ─░─────────────────░───────────────────────────░─┤ X ├──┼──┤ X ├──■─────── - ░ ░ ░ └───┘┌─┴─┐├───┤ │ - q_11: ─░─────────────────░───────────────────────────░──────┤ X ├┤ X ├──■─────── - ░ ░ ░ └───┘└───┘┌─┴─┐┌───┐ - q_12: ─░─────────────────░───────────────────────────░────────────────┤ X ├┤ X ├ - ░ ░ ░ └───┘└───┘ +While if we write three separate sums, compiling them separately, we obtain something like the +following circuit: + +.. code-block:: text + q_0: ─░───■────■────■──────────────────░───■────■────■──────────────────░───■────■────■───────────────── + ░ │ │ │ ░ │ │ │ ░ │ │ │ + q_1: ─░───■────┼────┼────■─────────────░───┼────┼────┼──────────────────░───┼────┼────┼───────────────── + ░ │ │ │ │ ░ │ │ │ ░ │ │ │ + q_2: ─░───┼────┼────┼────┼────■────────░───┼────┼────┼──────────────────░───┼────┼────┼───────────────── + ░ │ ┌─┴─┐ │ ┌─┴─┐ │ ░ │ │ │ ░ │ │ │ + q_3: ─░───┼──┤ X ├──┼──┤ X ├──┼────────░───■────┼────┼────■─────────────░───┼────┼────┼───────────────── + ░ ┌─┴─┐└───┘┌─┴─┐└───┘┌─┴─┐┌───┐ ░ │ │ │ │ ░ │ │ │ + q_4: ─░─┤ X ├─────┤ X ├─────┤ X ├┤ X ├─░───┼────┼────┼────┼────■────────░───┼────┼────┼───────────────── + ░ └───┘ └───┘ └───┘└───┘ ░ │ ┌─┴─┐ │ ┌─┴─┐ │ ░ │ │ │ + q_5: ─░────────────────────────────────░───┼──┤ X ├──┼──┤ X ├──┼────────░───■────┼────┼────■──────────── + ░ ░ ┌─┴─┐└───┘┌─┴─┐└───┘┌─┴─┐┌───┐ ░ │ │ │ │ + q_6: ─░────────────────────────────────░─┤ X ├─────┤ X ├─────┤ X ├┤ X ├─░───┼────┼────┼────┼────■─────── + ░ ░ └───┘ └───┘ └───┘└───┘ ░ │ ┌─┴─┐ │ ┌─┴─┐ │ + q_7: ─░────────────────────────────────░────────────────────────────────░───┼──┤ X ├──┼──┤ X ├──┼─────── + ░ ░ ░ ┌─┴─┐└───┘┌─┴─┐└───┘┌─┴─┐┌───┐ + q_8: ─░────────────────────────────────░────────────────────────────────░─┤ X ├─────┤ X ├─────┤ X ├┤ X ├ + ░ ░ ░ └───┘ └───┘ └───┘└───┘ + + +As we can see from the circuit drawings, qlasskit approach needs half the number of qubits and approximately half the number of gates. AST Traslator @@ -117,17 +106,17 @@ The previous example function `f`, is translated to the following quantum circui .. code-block:: text - q_0: ─────────────────■── - │ - q_1: ─────────────────■── - │ - q_2: ──■──────────────┼── - │ │ - q_3: ──┼────■─────────┼── - ┌─┴─┐ │ ┌───┐ │ - q_4: ┤ X ├──┼──┤ X ├──■── - └───┘┌─┴─┐├───┤ │ - q_5: ─────┤ X ├┤ X ├──■── - └───┘└───┘┌─┴─┐ - q_6: ───────────────┤ X ├ - └───┘ + q_0: ─────────■─────────────────────────────────────■────────── + │ │ + q_1: ─────────■─────────────────────────────────────■────────── + ┌───┐ │ ┌───┐┌───┐ │ ┌───┐ + q_2: ┤ X ├────┼────────■────┤ X ├┤ X ├────■─────────┼─────┤ X ├ + ├───┤ │ │ └───┘├───┤ │ │ └───┘ + q_3: ┤ X ├────┼────────┼──────■──┤ X ├────┼─────────┼────────── + └───┘ │ │ ┌─┴─┐└───┘ │ │ + q_4: ─────────┼────────┼────┤ X ├─────────┼─────────┼────────── + ┌───┴───┐ │ └─┬─┘ │ ┌───┴────┐ + q_5: ─────┤ Rx(π) ├────■──────┼───────────■─────┤ Rx(-π) ├───── + └───────┘┌───┴───┐ │ ┌───┴────┐└────────┘ + q_6: ──────────────┤ Rx(π) ├──■───────┤ Rx(-π) ├─────────────── + └───────┘ └────────┘ diff --git a/examples/ex1_2.py b/examples/ex1_2.py new file mode 100644 index 00000000..a4641b03 --- /dev/null +++ b/examples/ex1_2.py @@ -0,0 +1,35 @@ +from qiskit import QuantumCircuit + +from qlasskit import Qint2, qlassf + +INTSIZ = 2 + +@qlassf +def f1(b: bool, n: Qint2) -> Qint2: + return n + (1 if b else 2) + +@qlassf +def f_comp(b: bool, n: Qint2) -> Qint2: + for i in range(3): + n += (1 if b else 2) + return n + + +print(f_comp.expressions) +gate = f_comp.gate() +qc = QuantumCircuit(gate.num_qubits) +qc.barrier(label="f_comp") +qc.append(gate, list(range(gate.num_qubits))) +print(qc.decompose().draw("text")) +print(qc.decompose().count_ops()) + + +gate1 = f1.gate() +qc = QuantumCircuit(gate.num_qubits*3) + +for i in range(3): + qc.barrier(label="=") + qc.append(gate1, [0] + list(range(1+i * INTSIZ, 1+i*INTSIZ+INTSIZ*2))) + +print(qc.decompose().draw("text")) +print(qc.decompose().count_ops()) diff --git a/qlasskit/compiler/compiler.py b/qlasskit/compiler/compiler.py index 8fc987dc..72591faf 100644 --- a/qlasskit/compiler/compiler.py +++ b/qlasskit/compiler/compiler.py @@ -15,7 +15,7 @@ from sympy import Symbol from sympy.logic import ITE, And, Implies, Not, Or, Xor -from sympy.logic.boolalg import Boolean, BooleanFalse, BooleanTrue +from sympy.logic.boolalg import Boolean, BooleanFalse, BooleanTrue #, to_anf from .. import QCircuit from ..ast2logic.typing import Arg, Args, BoolExpList @@ -84,8 +84,8 @@ def __init__(self): pass def _symplify_exp(self, exp): - # exp = simplify_logic(exp) exp = optimizer(exp) + # exp = to_anf(exp, deep=False) return exp def compile( diff --git a/qlasskit/compiler/tweedledumcompiler.py b/qlasskit/compiler/tweedledumcompiler.py index 8f153667..fb87ce36 100644 --- a/qlasskit/compiler/tweedledumcompiler.py +++ b/qlasskit/compiler/tweedledumcompiler.py @@ -89,14 +89,12 @@ def twcircuit_to_qcircuit(twc): class TweedledumCompiler(Compiler): """Compile using tweedledum synthesis library""" - def compile(self, name, args: Args, returns: Arg, exprs: BoolExpList) -> QCircuit: + def compile(self, name, args: Args, returns: Arg, exprs: BoolExpList) -> QCircuit: # noqa: C901 exprs = [(symb, self._symplify_exp(exp)) for symb, exp in exprs] - _logic_network = sympy_to_logic_network(name, args, returns, exprs) sy = xag_synth(_logic_network) sy = parity_decomp(sy) - # print(exprs) # print(sy) qc = QCircuit(sy.num_qubits(), native=sy) @@ -127,6 +125,9 @@ def compile(self, name, args: Args, returns: Arg, exprs: BoolExpList) -> QCircui qc.x(u) qb.append(u) + if op == "rx": + op = "x" + angle = None qc.mctrl_gate(op, qb[0:-1], qb[-1], angle) for u, pol in qubits: diff --git a/qlasskit/qcircuit.py b/qlasskit/qcircuit.py index da76c0ba..f61b6484 100644 --- a/qlasskit/qcircuit.py +++ b/qlasskit/qcircuit.py @@ -42,7 +42,7 @@ def __init__(self, num_qubits=0, name="qc", native=None): for x in range(num_qubits): self.qubit_map[f"q{x}"] = x - + self.__native = native def get_key_by_index(self, i: int): diff --git a/test/test_qlassf_for_loop.py b/test/test_qlassf_for_loop.py index e7fc25ca..2c8a9697 100644 --- a/test/test_qlassf_for_loop.py +++ b/test/test_qlassf_for_loop.py @@ -31,6 +31,11 @@ def test_for_1it(self): f = "def test(a: Qint2) -> Qint2:\n\tfor x in range(1):\n\t\ta += 1\n\treturn a" qf = qlassf(f, to_compile=COMPILATION_ENABLED) compute_and_compare_results(self, qf) + + def test_for_4it(self): + f = "def test(a: Qint2) -> Qint2:\n\tfor x in range(4):\n\t\ta += 1\n\treturn a" + qf = qlassf(f, to_compile=COMPILATION_ENABLED) + compute_and_compare_results(self, qf) def test_for_3it(self): f = "def test(a: Qint2) -> Qint2:\n\tfor i in range(3):\n\t\ta += i\n\treturn a"