Skip to content

Commit

Permalink
fix sympy exporter, update exporters testing and new release
Browse files Browse the repository at this point in the history
  • Loading branch information
dakk committed Dec 19, 2023
1 parent a685fbd commit ab9184d
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 113 deletions.
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
### Week 1: (18 Dec 23)
- [x] Pennylane exporter
- [x] Regression test for qubit number and gates
- [ ] Sympy exporter
- [x] Sympy exporter


### Week 2: (25 Dec 23)
Expand Down
2 changes: 1 addition & 1 deletion qlasskit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.
# isort:skip_file

__version__ = "0.1.9"
__version__ = "0.1.10"

from .qcircuit import QCircuit, SupportedFrameworks, SupportedFramework # noqa: F401
from .qlassfun import QlassF, qlassf, qlassfa # noqa: F401
Expand Down
46 changes: 19 additions & 27 deletions qlasskit/qcircuit/exporter_sympy.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,41 @@

from typing import Literal

from sympy.physics.quantum.gate import CNOT, H, T, X
from sympy.physics.quantum.gate import CNOT, CGate, H, X, XGate
from sympy.physics.quantum.qubit import Qubit

from . import gates
from .exporter import QCircuitExporter


def mcx(w):
return CGate(tuple(w[0:-1]), XGate(w[-1]))


def toffoli(q0, q1, q2):
return CGate((q0, q1), XGate(q2))


class SympyExporter(QCircuitExporter):
def export(self, _selfqc, mode: Literal["circuit", "gate"]):
def toffoli(q0, q1, q2):
# TODO: investigate why t**-1 raises max recursion on qapply
return (
H(q2)
* CNOT(q2, q1)
* T(q2) ** -1
* CNOT(q0, q2)
* T(q2)
* CNOT(q1, q2)
* T(q2) ** -1
* CNOT(q0, q2)
* T(q1)
* T(q2)
* H(q2)
* CNOT(q0, q1)
* T(q0)
* T(q1) ** -1
* CNOT(q0, q1)
)

qstate = Qubit("0" * _selfqc.num_qubits)

for g, w, p in _selfqc.gates:
ga = None
if isinstance(g, gates.X):
ga = X(w[0])
elif isinstance(g, gates.H):
ga = H(w[0])
elif isinstance(g, gates.CX):
ga = CNOT(w[0], w[1])
elif isinstance(g, gates.CCX):
raise Exception("Not implemented yet")
elif isinstance(g, gates.MCX):
raise Exception("Not implemented yet")
elif g != "bar":
raise Exception(f"not handled {g}")
elif isinstance(g, gates.CCX) or isinstance(g, gates.MCX):
ga = mcx(w)
elif isinstance(g, gates.Barrier) and mode != "gate":
pass
elif isinstance(g, gates.NopGate):
pass
else:
raise Exception("not handled")

if ga:
qstate = ga * qstate
Expand Down
186 changes: 102 additions & 84 deletions test/test_qcircuit_exporters.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import ast
import unittest

import cirq
import numpy as np
import pennylane as qml
from parameterized import parameterized_class
from sympy import Symbol
from sympy.physics.quantum.qapply import qapply
from sympy.physics.quantum.qubit import Qubit, measure_all
Expand All @@ -24,130 +28,144 @@
from .utils import qiskit_measure_and_count


class TestQCircuitExportQASM(unittest.TestCase):
def test_export_qasm(self):
qc = QCircuit()
a, b = qc.add_qubit(), qc.add_qubit()
qc.x(a)
qc.cx(a, b)
qasm_c = qc.export("gate", "qasm")
self.assertEqual(qasm_c, "gate qc q0 q1 {\n\tx q0\n\tcx q0 q1\n}\n\n")

def test_export_qasm_toffoli(self):
qc = QCircuit()
a, b, c = qc.add_qubit("a"), qc.add_qubit("b"), qc.add_qubit("c")
qc.x(a)
qc.x(b)
qc.ccx(a, b, c)
qasm_c = qc.export("gate", "qasm")
self.assertEqual(qasm_c, "gate qc a b c {\n\tx a\n\tx b\n\tccx a b c\n}\n\n")
def cx_circuit():
qc = QCircuit()
a, b = qc.add_qubit(), qc.add_qubit()
qc.x(a)
qc.cx(a, b)
return qc


def ccx_circuit():
qc = QCircuit()
a, b, c = qc.add_qubit("a"), qc.add_qubit("b"), qc.add_qubit("c")
qc.x(a)
qc.x(b)
qc.ccx(a, b, c)
return qc


def bell_circuit():
qc = QCircuit()
a, b = qc.add_qubit("a"), qc.add_qubit("b")
qc.h(a)
qc.cx(a, b)
return qc


@parameterized_class(
("qc", "result"),
[
(cx_circuit(), "gate qc q0 q1 {\n\tx q0\n\tcx q0 q1\n}\n\n"),
(ccx_circuit(), "gate qc a b c {\n\tx a\n\tx b\n\tccx a b c\n}\n\n"),
(bell_circuit(), "gate qc a b {\n\th a\n\tcx a b\n}\n\n"),
],
)
class TestQCircuitExportQASM(unittest.TestCase):
def test_export_qasm_gate(self):
qasm_c = self.qc.export("gate", "qasm")
self.assertEqual(qasm_c, self.result)

def test_export_qasm_circuit(self):
qasm_c = self.qc.export("circuit", "qasm")
self.assertEqual(qasm_c, f"OPENQASM 3.0;\n\n{self.result}")


@parameterized_class(
("qc", "result"),
[
(cx_circuit(), [(Qubit("11"), 1)]),
(ccx_circuit(), [(Qubit("111"), 1)]),
(bell_circuit(), [(Qubit("00"), 1 / 2), (Qubit("11"), 1 / 2)]),
],
)
class TestQCircuitExportSympy(unittest.TestCase):
def test_export_sympy(self):
qc = QCircuit()
a, b = qc.add_qubit(), qc.add_qubit()
qc.x(a)
qc.cx(a, b)
sym_circ = qc.export("circuit", "sympy")
sym_circ = self.qc.export("circuit", "sympy")
statev = qapply(sym_circ)
meas = measure_all(statev)
self.assertEqual(meas, [(Qubit("11"), 1)])

# def test_export_sympy_toffoli(self):
# qc = QCircuit()
# a, b, c = qc.add_qubit(), qc.add_qubit(), qc.add_qubit()
# qc.x(a)
# qc.x(b)
# qc.ccx(a, b, c)
# sym_circ = qc.export("circuit", "sympy")
# statev = qapply(sym_circ)
# meas = measure_all(statev)
# self.assertEqual(meas, [(Qubit("111"), 1)])
self.assertEqual(meas, self.result)


@parameterized_class(
("qc", "result"),
[
(cx_circuit(), {"11": 1}),
(ccx_circuit(), {"111": 1}),
],
)
class TestQCircuitExportQiskit(unittest.TestCase):
def test_export_qiskit(self):
qc = QCircuit()
a, b = qc.add_qubit(), qc.add_qubit()
qc.x(a)
qc.cx(a, b)
circ = qc.export("circuit", "qiskit")
circ = self.qc.export("circuit", "qiskit")
counts = qiskit_measure_and_count(circ, shots=1)
self.assertDictEqual(counts, {"11": 1})

def test_export_qiskit_toffoli(self):
qc = QCircuit()
a, b, c = qc.add_qubit(), qc.add_qubit(), qc.add_qubit()
qc.x(a)
qc.x(b)
qc.ccx(a, b, c)
circ = qc.export("circuit", "qiskit")
counts = qiskit_measure_and_count(circ, shots=1)
self.assertDictEqual(counts, {"111": 1})
self.assertDictEqual(counts, self.result)


@parameterized_class(
("qc", "result"),
[
(
cx_circuit(),
{
"q(0)": np.array([[[1]]], dtype=np.int8),
"q(1)": np.array([[[1]]], dtype=np.int8),
},
),
(
ccx_circuit(),
{
"q(0)": np.array([[[1]]], dtype=np.int8),
"q(1)": np.array([[[1]]], dtype=np.int8),
"q(2)": np.array([[[1]]], dtype=np.int8),
},
),
],
)
class TestQCircuitExportCirq(unittest.TestCase):
def test_export_cirq_circuit(self):
qc = QCircuit()
a, b = qc.add_qubit(), qc.add_qubit()
qc.x(a)
qc.cx(a, b)
circ = qc.export("circuit", "cirq")

import cirq
import numpy as np
circ = self.qc.export("circuit", "cirq")

circ.append(cirq.measure_each(circ.all_qubits()))
simulator = cirq.Simulator()
result = simulator.run(circ)

self.assertDictEqual(
result.records,
{
"q(0)": np.array([[[1]]], dtype=np.int8),
"q(1)": np.array([[[1]]], dtype=np.int8),
},
self.result,
)

def test_export_cirq_gate(self):
qc = QCircuit()
a, b = qc.add_qubit(), qc.add_qubit()
qc.x(a)
qc.cx(a, b)
gat = qc.export("gate", "cirq")
gat = self.qc.export("gate", "cirq")

import cirq
import numpy as np

qreg = cirq.LineQubit.range(2)
qreg = cirq.LineQubit.range(self.qc.num_qubits)
circ = cirq.Circuit(gat().on(*qreg))

circ.append(cirq.measure_each(circ.all_qubits()))
simulator = cirq.Simulator()
result = simulator.run(circ)
self.assertDictEqual(
result.records,
{
"q(0)": np.array([[[1]]], dtype=np.int8),
"q(1)": np.array([[[1]]], dtype=np.int8),
},
self.result,
)


@parameterized_class(
("qc", "result"),
[
(cx_circuit(), [0, 0, 0, 1]),
(ccx_circuit(), [0, 0, 0, 0, 0, 0, 0, 1]),
(bell_circuit(), [0.5, 0, 0, 0.5]),
],
)
class TestQCircuitExportPennylane(unittest.TestCase):
def test_export_pennylane_circuit(self):
import pennylane as qml

qc = QCircuit()
a, b = qc.add_qubit(), qc.add_qubit()
qc.h(a)
qc.cx(a, b)
tape = qc.export("circuit", "pennylane")
tape = self.qc.export("circuit", "pennylane")
tape = qml.tape.QuantumTape(tape.operations, [qml.probs()])

dev = qml.device("default.qubit", wires=2)
r = qml.execute([tape], dev, gradient_fn=None)

self.assertAlmostEqual(r[0][0], 0.5)
self.assertAlmostEqual(r[0][3], 0.5)
self.assertEqual(len(r[0]), len(self.result))

for a, b in zip(r[0], self.result):
self.assertAlmostEqual(a, b)

0 comments on commit ab9184d

Please sign in to comment.