diff --git a/modules/pytket-aqt/pytket/extensions/aqt/backends/aqt.py b/modules/pytket-aqt/pytket/extensions/aqt/backends/aqt.py index b987bcda..e7be1838 100644 --- a/modules/pytket-aqt/pytket/extensions/aqt/backends/aqt.py +++ b/modules/pytket-aqt/pytket/extensions/aqt/backends/aqt.py @@ -39,6 +39,7 @@ DecomposeBoxes, RenameQubitsPass, SimplifyInitial, + auto_rebase_pass, ) from pytket.predicates import ( # type: ignore GateSetPredicate, @@ -376,19 +377,20 @@ def _translate_aqt(circ: Circuit) -> Tuple[List[List], str]: return (gates, json.dumps(measures)) -def _aqt_rebase() -> BasePass: +def _aqt_rebase() -> RebaseCustom: + return auto_rebase_pass({OpType.XXPhase, OpType.Rx, OpType.Ry}) # CX replacement - c_cx = Circuit(2) - c_cx.Ry(0.5, 0).Rx(0.5, 0) - c_cx.Rx(-0.5, 1) - c_cx.add_gate(OpType.XXPhase, 0.5, [0, 1]) - c_cx.Ry(0.5, 0).Rx(-1, 0) - c_cx.add_phase(-0.25) + # c_cx = Circuit(2) + # c_cx.Ry(0.5, 0).Rx(0.5, 0) + # c_cx.Rx(-0.5, 1) + # c_cx.add_gate(OpType.XXPhase, 0.5, [0, 1]) + # c_cx.Ry(0.5, 0).Rx(-1, 0) + # c_cx.add_phase(-0.25) - # TK1 replacement - c_tk1 = lambda a, b, c: Circuit(1).Rx(-0.5, 0).Ry(c, 0).Rx(b, 0).Ry(a, 0).Rx(0.5, 0) + # # TK1 replacement + # c_tk1 = lambda a, b, c: Circuit(1).Rx(-0.5, 0).Ry(c, 0).Rx(b, 0).Ry(a, 0).Rx(0.5, 0) - return RebaseCustom({OpType.XXPhase}, c_cx, {OpType.Rx, OpType.Ry}, c_tk1) + # return RebaseCustom({OpType.XXPhase, OpType.Rx, OpType.Ry}, c_cx, c_tk1) _xcirc = Circuit(1).Rx(1, 0) diff --git a/modules/pytket-braket/pytket/extensions/braket/backends/braket.py b/modules/pytket-braket/pytket/extensions/braket/backends/braket.py index 7ada0cd0..7eda3261 100644 --- a/modules/pytket-braket/pytket/extensions/braket/backends/braket.py +++ b/modules/pytket-braket/pytket/extensions/braket/backends/braket.py @@ -55,6 +55,7 @@ DecomposeBoxes, SimplifyInitial, ) +from pytket._tket.circuit._library import _TK1_to_RzRx # type: ignore from pytket.pauli import Pauli, QubitPauliString # type: ignore from pytket.predicates import ( # type: ignore ConnectivityPredicate, @@ -355,14 +356,13 @@ def __init__( self._req_preds.append(ConnectivityPredicate(arch)) self._rebase_pass = RebaseCustom( - self._multiqs, + self._multiqs | self._singleqs, Circuit(), - self._singleqs, - lambda a, b, c: Circuit(1).Rz(c, 0).Rx(b, 0).Rz(a, 0), + _TK1_to_RzRx, ) self._squash_pass = SquashCustom( self._singleqs, - lambda a, b, c: Circuit(1).Rz(c, 0).Rx(b, 0).Rz(a, 0), + _TK1_to_RzRx, ) @staticmethod diff --git a/modules/pytket-cirq/pytket/extensions/cirq/backends/cirq.py b/modules/pytket-cirq/pytket/extensions/cirq/backends/cirq.py index d2c1e564..db061db1 100644 --- a/modules/pytket-cirq/pytket/extensions/cirq/backends/cirq.py +++ b/modules/pytket-cirq/pytket/extensions/cirq/backends/cirq.py @@ -32,7 +32,7 @@ from pytket.transform import Transform # type: ignore from pytket.passes import ( # type: ignore BasePass, - RebaseCirq, + auto_rebase_pass, SequencePass, RebaseCustom, SquashCustom, @@ -42,6 +42,7 @@ RemoveRedundancies, FullPeepholeOptimise, ) +from pytket._tket.circuit._library import _TK1_to_PhasedXRz, _CX # type: ignore from pytket.predicates import ( # type: ignore GateSetPredicate, NoClassicalControlPredicate, @@ -89,7 +90,7 @@ def __init__(self) -> None: self._gate_set_predicate = _regular_gate_set_predicate def rebase_pass(self) -> BasePass: - return RebaseCirq() + return auto_rebase_pass({OpType.CZ, OpType.PhasedX, OpType.Rz}) @property def required_predicates(self) -> List[Predicate]: @@ -498,16 +499,8 @@ def package_results( return all_backres -def _tk1_to_phasedxrz(a: float, b: float, c: float) -> Circuit: - circ = Circuit(1) - circ.Rz(a + c, 0) - circ.add_gate(OpType.PhasedX, [b, a], [0]) - RemoveRedundancies().apply(circ) - return circ - - _cirq_squash = SquashCustom( - {OpType.PhasedX, OpType.Rz, OpType.Rx, OpType.Ry}, _tk1_to_phasedxrz + {OpType.PhasedX, OpType.Rz, OpType.Rx, OpType.Ry}, _TK1_to_PhasedXRz ) _regular_gate_set_predicate = GateSetPredicate( @@ -559,14 +552,12 @@ def _tk1_to_phasedxrz(a: float, b: float, c: float) -> Circuit: def _tk1_to_phasedxrz_clifford(a: float, b: float, c: float) -> Circuit: - circ = _tk1_to_phasedxrz(a, b, c) + circ = _TK1_to_PhasedXRz(a, b, c) Transform.RebaseToCliffordSingles().apply(circ) return circ _partial_clifford_rebase = RebaseCustom( - {OpType.CX, OpType.CZ}, - Circuit(2).CX(0, 1), { OpType.PhasedX, OpType.Rz, @@ -580,6 +571,9 @@ def _tk1_to_phasedxrz_clifford(a: float, b: float, c: float) -> Circuit: OpType.S, OpType.Sdg, OpType.H, + OpType.CX, + OpType.CZ, }, + _CX(), _tk1_to_phasedxrz_clifford, ) diff --git a/modules/pytket-honeywell/pytket/extensions/honeywell/backends/honeywell.py b/modules/pytket-honeywell/pytket/extensions/honeywell/backends/honeywell.py index c74557bd..ef226ff9 100644 --- a/modules/pytket-honeywell/pytket/extensions/honeywell/backends/honeywell.py +++ b/modules/pytket-honeywell/pytket/extensions/honeywell/backends/honeywell.py @@ -37,12 +37,12 @@ SequencePass, SynthesiseTket, RemoveRedundancies, - RebaseHQS, - SquashHQS, FullPeepholeOptimise, DecomposeBoxes, DecomposeClassicalExp, SimplifyInitial, + auto_rebase_pass, + auto_squash_pass, ) from pytket.predicates import ( # type: ignore GateSetPredicate, @@ -254,11 +254,12 @@ def required_predicates(self) -> List[Predicate]: return preds def rebase_pass(self) -> BasePass: - return RebaseHQS() + return auto_rebase_pass(_GATE_SET) def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) passlist = [DecomposeClassicalExp(), DecomposeBoxes()] + squash = auto_squash_pass({OpType.PhasedX, OpType.Rz}) if optimisation_level == 0: return SequencePass(passlist + [self.rebase_pass()]) elif optimisation_level == 1: @@ -268,7 +269,7 @@ def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: SynthesiseTket(), self.rebase_pass(), RemoveRedundancies(), - SquashHQS(), + squash, SimplifyInitial( allow_classical=False, create_all_qubits=True, xcirc=_xcirc ), @@ -281,7 +282,7 @@ def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: FullPeepholeOptimise(), self.rebase_pass(), RemoveRedundancies(), - SquashHQS(), + squash, SimplifyInitial( allow_classical=False, create_all_qubits=True, xcirc=_xcirc ), diff --git a/modules/pytket-honeywell/tests/convert_test.py b/modules/pytket-honeywell/tests/convert_test.py index e15def7b..c5175800 100644 --- a/modules/pytket-honeywell/tests/convert_test.py +++ b/modules/pytket-honeywell/tests/convert_test.py @@ -13,7 +13,7 @@ # limitations under the License. from pytket.circuit import Circuit, OpType # type: ignore -from pytket.passes import RebaseHQS # type: ignore +from pytket.extensions.honeywell import HoneywellBackend from pytket.qasm import circuit_to_qasm_str @@ -26,7 +26,7 @@ def test_convert() -> None: circ.ZZPhase(0.3, 2, 3).CX(3, 0).Tdg(1) circ.measure_all() - RebaseHQS().apply(circ) + HoneywellBackend("", login=False).rebase_pass().apply(circ) circ_hqs = circuit_to_qasm_str(circ, header="hqslib1") qasm_str = circ_hqs.split("\n")[6:-1] test = True diff --git a/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq.py b/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq.py index f0eaf8a6..89b497ed 100644 --- a/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq.py +++ b/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq.py @@ -36,6 +36,7 @@ RenameQubitsPass, SimplifyInitial, ) +from pytket._tket.circuit._library import _TK1_to_RzRx from pytket.predicates import ( # type: ignore GateSetPredicate, MaxNQubitsPredicate, @@ -186,7 +187,7 @@ def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: self.rebase_pass(), SquashCustom( ionq_singleqs, - lambda a, b, c: Circuit(1).Rz(c, 0).Rx(b, 0).Rz(a, 0), + _TK1_to_RzRx, ), SimplifyInitial(allow_classical=False, create_all_qubits=True), ] diff --git a/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq_convert.py b/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq_convert.py index ff6823b0..fabecac5 100644 --- a/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq_convert.py +++ b/modules/pytket-ionq/pytket/extensions/ionq/backends/ionq_convert.py @@ -14,18 +14,11 @@ from typing import Dict, Tuple, Any, List from pytket.passes import RebaseCustom # type: ignore +from pytket._tket.circuit._library import _TK1_to_RzRx # type: ignore from pytket.circuit import Circuit, OpType, Command # type: ignore from numpy import pi -def _from_tk1(a: float, b: float, c: float) -> Circuit: - circ = Circuit(1) - circ.Rz(c, 0) - circ.Rx(b, 0) - circ.Rz(a, 0) - return circ - - ionq_multiqs = { OpType.SWAP, OpType.CX, @@ -56,10 +49,9 @@ def _from_tk1(a: float, b: float, c: float) -> Circuit: ionq_gates = ionq_multiqs.union(ionq_singleqs) ionq_rebase_pass = RebaseCustom( - ionq_multiqs, + ionq_multiqs | ionq_singleqs, Circuit(), # cx_replacement (irrelevant) - ionq_singleqs, # singleqs - _from_tk1, + _TK1_to_RzRx, ) # tk1_replacement ionq_gate_dict = { diff --git a/modules/pytket-iqm/pytket/extensions/iqm/backends/iqm.py b/modules/pytket-iqm/pytket/extensions/iqm/backends/iqm.py index ff0b7df2..4c97f415 100644 --- a/modules/pytket-iqm/pytket/extensions/iqm/backends/iqm.py +++ b/modules/pytket-iqm/pytket/extensions/iqm/backends/iqm.py @@ -343,7 +343,7 @@ def _iqm_rebase() -> BasePass: .add_gate(OpType.PhasedX, [1 + b, a], [0]) ) - return RebaseCustom({OpType.CZ}, c_cx, {OpType.PhasedX}, c_tk1) + return RebaseCustom({OpType.CZ, OpType.PhasedX}, c_cx, c_tk1) _xcirc = Circuit(1).add_gate(OpType.PhasedX, [1, 0], [0]).add_phase(0.5) diff --git a/modules/pytket-projectq/pytket/extensions/projectq/backends/projectq_backend.py b/modules/pytket-projectq/pytket/extensions/projectq/backends/projectq_backend.py index d09de694..e83b5bc2 100644 --- a/modules/pytket-projectq/pytket/extensions/projectq/backends/projectq_backend.py +++ b/modules/pytket-projectq/pytket/extensions/projectq/backends/projectq_backend.py @@ -45,7 +45,6 @@ from pytket.backends.backendresult import BackendResult from pytket.passes import ( # type: ignore BasePass, - RebaseProjectQ, SequencePass, SynthesiseTket, FullPeepholeOptimise, @@ -63,7 +62,7 @@ Predicate, ) from pytket.routing import Architecture # type: ignore -from pytket.extensions.projectq.projectq_convert import tk_to_projectq # type: ignore +from pytket.extensions.projectq.projectq_convert import tk_to_projectq, _REBASE # type: ignore from pytket.extensions.projectq._metadata import __extension_version__ # type: ignore from pytket.utils.operators import QubitPauliOperator from pytket.utils.results import KwargTypes @@ -134,7 +133,7 @@ def required_predicates(self) -> List[Predicate]: ] def rebase_pass(self) -> BasePass: - return RebaseProjectQ() + return _REBASE def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) diff --git a/modules/pytket-projectq/pytket/extensions/projectq/projectq_convert.py b/modules/pytket-projectq/pytket/extensions/projectq/projectq_convert.py index bbb404eb..41840983 100644 --- a/modules/pytket-projectq/pytket/extensions/projectq/projectq_convert.py +++ b/modules/pytket-projectq/pytket/extensions/projectq/projectq_convert.py @@ -24,6 +24,8 @@ from projectq.types._qubit import Qureg # type: ignore from pytket.circuit import OpType, Op, Circuit, Command, Bit # type: ignore from pytket.transform import Transform # type: ignore +from pytket.passes import RebaseCustom # type: ignore +from pytket._tket.circuit._library import _CX, _TK1_to_RzRx # type: ignore import numpy as np _pq_to_tk_singleqs = { @@ -56,7 +58,7 @@ _ALLOWED_GATES = {**_pq_to_tk_singleqs, **_pq_to_tk_multiqs, **_OTHER_KNOWN_GATES} - +_REBASE = RebaseCustom(set(_ALLOWED_GATES.values()), _CX(), _TK1_to_RzRx) _tk_to_pq_singleqs: dict = dict( ((item[1], item[0]) for item in _pq_to_tk_singleqs.items()) ) @@ -325,7 +327,7 @@ def _optimise( # ProjectQ commands if self._circuit.n_qubits != 0: Transform.OptimisePhaseGadgets().apply(self._circuit) - Transform.RebaseToProjectQ().apply(self._circuit) + _REBASE.apply(self._circuit) cmd_list = [] diff --git a/modules/pytket-pyquil/pytket/extensions/pyquil/backends/forest.py b/modules/pytket-pyquil/pytket/extensions/pyquil/backends/forest.py index b04a9e5f..1a5cdfe0 100644 --- a/modules/pytket-pyquil/pytket/extensions/pyquil/backends/forest.py +++ b/modules/pytket-pyquil/pytket/extensions/pyquil/backends/forest.py @@ -45,7 +45,7 @@ BasePass, EulerAngleReduction, CXMappingPass, - RebaseQuil, + auto_rebase_pass, SequencePass, SynthesiseTket, DecomposeBoxes, @@ -126,7 +126,7 @@ def required_predicates(self) -> List[Predicate]: ] def rebase_pass(self) -> BasePass: - return RebaseQuil() + return auto_rebase_pass({OpType.CZ, OpType.Rz, OpType.Rx}) def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) @@ -339,7 +339,7 @@ def required_predicates(self) -> List[Predicate]: ] def rebase_pass(self) -> BasePass: - return RebaseQuil() + return auto_rebase_pass({OpType.CZ, OpType.Rz, OpType.Rx}) def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) diff --git a/modules/pytket-qiskit/pytket/extensions/qiskit/backends/aer.py b/modules/pytket-qiskit/pytket/extensions/qiskit/backends/aer.py index 3d810905..b7c0d48e 100644 --- a/modules/pytket-qiskit/pytket/extensions/qiskit/backends/aer.py +++ b/modules/pytket-qiskit/pytket/extensions/qiskit/backends/aer.py @@ -41,9 +41,9 @@ CXMappingPass, DecomposeBoxes, FullPeepholeOptimise, - RebaseCustom, SequencePass, SynthesiseTket, + auto_rebase_pass, ) from pytket.pauli import Pauli, QubitPauliString # type: ignore from pytket.predicates import ( # type: ignore @@ -89,15 +89,6 @@ def _default_q_index(q: Qubit) -> int: _required_gates: Set[OpType] = {OpType.CX, OpType.U1, OpType.U2, OpType.U3} -_1q_gates: Set[OpType] = set(_qiskit_gates_1q.values()) -_2q_gates: Set[OpType] = set(_qiskit_gates_2q.values()) - - -def _tk1_to_u(a: float, b: float, c: float) -> Circuit: - circ = Circuit(1) - circ.add_gate(OpType.U3, [b, a - 0.5, c + 0.5], [0]) - circ.add_phase(-0.5 * (a + c)) - return circ class _AerBaseBackend(Backend): @@ -142,11 +133,8 @@ def backend_info(self) -> BackendInfo: return self._backend_info def rebase_pass(self) -> BasePass: - return RebaseCustom( - self._gate_set & _2q_gates, - Circuit(2).CX(0, 1), - self._gate_set & _1q_gates, - _tk1_to_u, + return auto_rebase_pass( + self._gate_set, ) def process_circuits( diff --git a/modules/pytket-qiskit/pytket/extensions/qiskit/backends/ibm.py b/modules/pytket-qiskit/pytket/extensions/qiskit/backends/ibm.py index 07764c26..865dfd92 100644 --- a/modules/pytket-qiskit/pytket/extensions/qiskit/backends/ibm.py +++ b/modules/pytket-qiskit/pytket/extensions/qiskit/backends/ibm.py @@ -51,7 +51,7 @@ from pytket.extensions.qiskit._metadata import __extension_version__ from pytket.passes import ( # type: ignore BasePass, - RebaseCustom, + auto_rebase_pass, RemoveRedundancies, SequencePass, SynthesiseTket, @@ -61,6 +61,7 @@ CliffordSimp, SimplifyInitial, ) +from pytket._tket.circuit._library import _CX # type: ignore from pytket.predicates import ( # type: ignore NoMidMeasurePredicate, NoSymbolsPredicate, @@ -125,76 +126,6 @@ def __init__(self) -> None: ) -def _approx_0_mod_2(x: Union[float, Expr], eps: float = 1e-10) -> bool: - if isinstance(x, Expr) and not x.is_constant(): - return False - x = float(x) - x %= 2 - return min(x, 2 - x) < eps - - -def int_half(angle: float) -> int: - # assume float is approximately an even integer, and return the half - two_x = round(angle) - assert not two_x % 2 - return two_x // 2 - - -def _tk1_to_x_sx_rz( - a: Union[float, Expr], b: Union[float, Expr], c: Union[float, Expr] -) -> Circuit: - circ = Circuit(1) - correction_phase = 0.0 - - # all phase identities use, for integer k, - # Rx(2k) = Rz(2k) = (-1)^{k}I - - # _approx_0_mod_2 checks if parameters are constant - # so they can be assumed to be constant - if _approx_0_mod_2(b): - circ.Rz(a + c, 0) - # b = 2k, if k is odd, then Rx(b) = -I - correction_phase += int_half(float(b)) - - elif _approx_0_mod_2(b + 1): - # Use Rx(2k-1) = i(-1)^{k}X - correction_phase += -0.5 + int_half(float(b) - 1) - if _approx_0_mod_2(a - c): - circ.X(0) - # a - c = 2m - # overall operation is (-1)^{m}Rx(2k -1) - correction_phase += int_half(float(a - c)) - - else: - circ.Rz(c, 0).X(0).Rz(a, 0) - - elif _approx_0_mod_2(b - 0.5) and _approx_0_mod_2(a) and _approx_0_mod_2(c): - # a = 2k, b = 2m+0.5, c = 2n - # Rz(2k)Rx(2m + 0.5)Rz(2n) = (-1)^{k+m+n}e^{-i \pi /4} SX - circ.SX(0) - correction_phase += ( - int_half(float(b) - 0.5) + int_half(float(a)) + int_half(float(c)) - 0.25 - ) - - elif _approx_0_mod_2(b + 0.5) and _approx_0_mod_2(a) and _approx_0_mod_2(c): - # a = 2k, b = 2m-0.5, c = 2n - # Rz(2k)Rx(2m - 0.5)Rz(2n) = (-1)^{k+m+n}e^{i \pi /4} X.SX - circ.X(0).SX(0) - correction_phase += ( - int_half(float(b) + 0.5) + int_half(float(a)) + int_half(float(c)) + 0.25 - ) - elif _approx_0_mod_2(a - 0.5) and _approx_0_mod_2(c - 0.5): - # Rz(2k + 0.5)Rx(b)Rz(2m + 0.5) = -i(-1)^{k+m}SX.Rz(1-b).SX - circ.SX(0).Rz(1 - b, 0).SX(0) - correction_phase += int_half(float(a) - 0.5) + int_half(float(c) - 0.5) - 0.5 - else: - circ.Rz(c + 0.5, 0).SX(0).Rz(b - 1, 0).SX(0).Rz(a + 0.5, 0) - correction_phase += -0.5 - - circ.add_phase(correction_phase) - return circ - - class IBMQBackend(Backend): _supports_shots = True _supports_counts = True @@ -430,11 +361,8 @@ def _result_id_type(self) -> _ResultIdTuple: return (str, int, str) def rebase_pass(self) -> BasePass: - return RebaseCustom( - {OpType.CX}, - Circuit(2).CX(0, 1), - {OpType.X, OpType.SX, OpType.Rz}, - _tk1_to_x_sx_rz, + return auto_rebase_pass( + {OpType.CX, OpType.X, OpType.SX, OpType.Rz}, ) def process_circuits( diff --git a/modules/pytket-qsharp/pytket/extensions/qsharp/backends/common.py b/modules/pytket-qsharp/pytket/extensions/qsharp/backends/common.py index c93bf460..8e8ef423 100644 --- a/modules/pytket-qsharp/pytket/extensions/qsharp/backends/common.py +++ b/modules/pytket-qsharp/pytket/extensions/qsharp/backends/common.py @@ -45,6 +45,7 @@ FullPeepholeOptimise, FlattenRegisters, ) +from pytket._tket.circuit._library import _TK1_to_RzRx # type: ignore from pytket.predicates import ( # type: ignore GateSetPredicate, NoClassicalControlPredicate, @@ -61,14 +62,6 @@ from qsharp.loader import QSharpCallable # type: ignore -def _from_tk1(a: float, b: float, c: float) -> Circuit: - circ = Circuit(1) - circ.Rz(c, 0) - circ.Rx(b, 0) - circ.Rz(a, 0) - return circ - - def qs_predicates(gate_set: Set[OpType]) -> List[Predicate]: return [ NoMidMeasurePredicate(), @@ -124,9 +117,6 @@ def rebase_pass(self) -> BasePass: OpType.PauliExpBox, OpType.SWAP, OpType.CnX, - }, # multiqs - Circuit(), # cx_replacement (irrelevant) - { OpType.H, OpType.Rx, OpType.Ry, @@ -136,8 +126,9 @@ def rebase_pass(self) -> BasePass: OpType.X, OpType.Y, OpType.Z, - }, # singleqs - _from_tk1, + }, + Circuit(), # cx_replacement (irrelevant) + _TK1_to_RzRx, ) # tk1_replacement def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: diff --git a/modules/pytket-qsharp/pytket/extensions/qsharp/backends/toffoli.py b/modules/pytket-qsharp/pytket/extensions/qsharp/backends/toffoli.py index 5196af71..c4bc86ae 100644 --- a/modules/pytket-qsharp/pytket/extensions/qsharp/backends/toffoli.py +++ b/modules/pytket-qsharp/pytket/extensions/qsharp/backends/toffoli.py @@ -17,24 +17,20 @@ from pytket.circuit import Circuit, OpType # type: ignore from pytket.passes import BasePass, RebaseCustom # type: ignore from pytket.utils.outcomearray import OutcomeArray +from pytket.passes._decompositions import approx_0_mod_2 from .common import _QsharpSimBaseBackend, BackendResult if TYPE_CHECKING: from qsharp.loader import QSharpCallable # type: ignore -def is_approx_0_mod_2(x: float, tol: float = 1e-10) -> bool: - x %= 2 # --> [0,2) - return min(x, 2 - x) < tol - - def toffoli_from_tk1(a: float, b: float, c: float) -> Circuit: """Only accept operations equivalent to I or X.""" circ = Circuit(1) - if is_approx_0_mod_2(b) and is_approx_0_mod_2(a + c): + if approx_0_mod_2(b) and approx_0_mod_2(a + c): # identity pass - elif is_approx_0_mod_2(b + 1) and is_approx_0_mod_2(a - c): + elif approx_0_mod_2(b + 1) and approx_0_mod_2(a - c): # X circ.X() else: @@ -52,9 +48,8 @@ class QsharpToffoliSimulatorBackend(_QsharpSimBaseBackend): def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) return RebaseCustom( - {OpType.CX, OpType.CCX, OpType.CnX, OpType.SWAP}, # multiqs + {OpType.CX, OpType.CCX, OpType.CnX, OpType.SWAP, OpType.X}, Circuit(), # cx_replacement (irrelevant) - {OpType.X}, # singleqs toffoli_from_tk1, ) # tk1_replacement diff --git a/modules/pytket-qulacs/pytket/extensions/qulacs/backends/qulacs_backend.py b/modules/pytket-qulacs/pytket/extensions/qulacs/backends/qulacs_backend.py index 7954cfad..c12d23a2 100644 --- a/modules/pytket-qulacs/pytket/extensions/qulacs/backends/qulacs_backend.py +++ b/modules/pytket-qulacs/pytket/extensions/qulacs/backends/qulacs_backend.py @@ -39,7 +39,6 @@ SynthesiseTket, SequencePass, DecomposeBoxes, - RebaseCustom, FullPeepholeOptimise, FlattenRegisters, ) @@ -53,6 +52,7 @@ Predicate, ) from pytket.circuit import Pauli # type: ignore +from pytket.passes import auto_rebase_pass from pytket.pauli import QubitPauliString # type: ignore from pytket.routing import Architecture # type: ignore from pytket.utils.operators import QubitPauliOperator @@ -137,12 +137,7 @@ def required_predicates(self) -> List[Predicate]: ] def rebase_pass(self) -> BasePass: - return RebaseCustom( - set(_TWO_QUBIT_GATES), - Circuit(2).CX(0, 1), - _1Q_GATES, - _tk1_to_u, - ) + return auto_rebase_pass(set(_TWO_QUBIT_GATES) | _1Q_GATES) def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) diff --git a/modules/pytket-stim/pytket/extensions/stim/backends/stim_backend.py b/modules/pytket-stim/pytket/extensions/stim/backends/stim_backend.py index f7428441..ff035fb5 100644 --- a/modules/pytket-stim/pytket/extensions/stim/backends/stim_backend.py +++ b/modules/pytket-stim/pytket/extensions/stim/backends/stim_backend.py @@ -131,7 +131,7 @@ def required_predicates(self) -> List[Predicate]: ] def rebase_pass(self) -> BasePass: - return RebaseCustom({OpType.CX}, Circuit(), {OpType.H, OpType.S}, _tk1_to_cliff) + return RebaseCustom({OpType.CX, OpType.H, OpType.S}, Circuit(), _tk1_to_cliff) def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: # No optimization.