From 7fdb4f6643b94873a374f8d044d1bad164defbe7 Mon Sep 17 00:00:00 2001 From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:25:24 +0000 Subject: [PATCH] [doc] Miscellaneous doc fixes and improvements (#1163) --- pytket/binders/circuit/Circuit/main.cpp | 16 ++++++++++---- pytket/binders/passes.cpp | 28 +++++++++++++++++++------ pytket/docs/circuit.rst | 3 +++ pytket/pytket/_tket/circuit.pyi | 4 ++++ pytket/pytket/_tket/passes.pyi | 16 ++++++++------ pytket/pytket/passes/auto_rebase.py | 4 ++++ 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/pytket/binders/circuit/Circuit/main.cpp b/pytket/binders/circuit/Circuit/main.cpp index 44ad29ea8c..89d46d3d05 100644 --- a/pytket/binders/circuit/Circuit/main.cpp +++ b/pytket/binders/circuit/Circuit/main.cpp @@ -271,8 +271,12 @@ void def_circuit(py::class_> &pyCircuit) { } return b_regs; }, - "Get all classical registers.\n\n:return: List of " - ":py:class:`BitRegister`") + "Get all classical registers.\n\n" + "This property is only valid if the bits in the circuit are " + "organized into registers (i.e. all bit indices are single numbers " + "and all sets of bits with the same string identifier consist of " + "bits indexed consecutively from zero).\n\n" + ":return: List of :py:class:`BitRegister`") .def( "get_q_register", [](Circuit &circ, const std::string &name) { @@ -307,8 +311,12 @@ void def_circuit(py::class_> &pyCircuit) { } return q_regs; }, - "Get all quantum registers.\n\n:return: List of " - ":py:class:`QubitRegister`") + "Get all quantum registers.\n\n" + "This property is only valid if the qubits in the circuit are " + "organized into registers (i.e. all qubit indices are single numbers " + "and all sets of qubits with the same string identifier consist of " + "qubits indexed consecutively from zero).\n\n" + ":return: List of :py:class:`QubitRegister`") .def( "add_qubit", &Circuit::add_qubit, "Constructs a single qubit with the given id.\n\n:param id: " diff --git a/pytket/binders/passes.cpp b/pytket/binders/passes.cpp index 1228d0ec7b..0d6129cf54 100644 --- a/pytket/binders/passes.cpp +++ b/pytket/binders/passes.cpp @@ -373,6 +373,7 @@ PYBIND11_MODULE(passes, m) { "Using the `allow_swaps=True` (default) option, qubits will be " "swapped when convenient to further reduce the two-qubit gate count " "(only applicable when decomposing to CX gates).\n\n" + "Note that gates containing symbolic parameters are not squashed.\n\n" ":param target_2qb_gate: OpType to decompose to. Either TK2 or CX.\n" ":param cx_fidelity: Estimated CX gate fidelity, used when " "target_2qb_gate=CX.\n" @@ -406,7 +407,8 @@ PYBIND11_MODULE(passes, m) { "over ZZMax and CX if the decomposition results in fewer two-qubit " "gates.\n\n" "All TK2 gate parameters must be normalised, i.e. they must satisfy " - "`NormalisedTK2Predicate`.\n\n" + "`NormalisedTK2Predicate`. (This can be achieved by applying the " + ":py:meth:`NormaliseTK2` pass beforehand.)\n\n" "Using the `allow_swaps=True` (default) option, qubits will be swapped " "when convenient to reduce the two-qubit gate count of the decomposed " "TK2.\n\n" @@ -433,6 +435,9 @@ PYBIND11_MODULE(passes, m) { "ThreeQubitSquash", &ThreeQubitSquash, "Squash three-qubit subcircuits into subcircuits having fewer CX gates, " "when possible, and apply Clifford simplification." + "\n\nThe circuit to which this is applied must consist of single-qubit, " + "pure-classical and CX gates, and Measure, Collapse, Reset, Phase and " + "conditional gates." "\n\n:param allow_swaps: whether to allow implicit wire swaps", py::arg("allow_swaps") = true); m.def( @@ -496,7 +501,11 @@ PYBIND11_MODULE(passes, m) { "2-qubit gate (which may be CX or TK2) and TK1 gates." "\n\n:param allow_swaps: whether to allow implicit wire swaps", py::arg("allow_swaps") = true, py::arg("target_2qb_gate") = OpType::CX); - m.def("RebaseTket", &RebaseTket, "Converts all gates to CX, TK1 and Phase."); + m.def( + "RebaseTket", &RebaseTket, + "Converts all gates to CX, TK1 and Phase. " + "(Any Measure, Reset and Collapse operations are left untouched; " + "Conditional gates are also allowed.)"); m.def( "RemoveRedundancies", &RemoveRedundancies, "Removes gate-inverse pairs, merges rotations, removes identity " @@ -606,7 +615,10 @@ PYBIND11_MODULE(passes, m) { "4. applies the `tk1_replacement` function to each of these triples " ":math:`(a,b,c)` to generate replacement circuits." "\n\n" - ":param gateset: the allowed operations in the rebased circuit" + ":param gateset: the allowed operations in the rebased circuit " + "(in addition, Measure, Reset and Collapse operations are always allowed " + "and are left alone; conditional operations may be present; and Phase " + "gates may also be introduced by the rebase)" "\n:param cx_replacement: the equivalent circuit to replace a CX gate " "using two qubit gates from the desired basis (can use any single qubit " "OpTypes)" @@ -614,7 +626,8 @@ PYBIND11_MODULE(passes, m) { "Rz(a)Rx(b)Rz(c) triple, returns an equivalent circuit in the desired " "basis" "\n:return: a pass that rebases to the given gate set (possibly " - "including conditional and phase operations)", + "including conditional and phase operations, and Measure, Reset and " + "Collapse)", py::arg("gateset"), py::arg("cx_replacement"), py::arg("tk1_replacement")); @@ -631,7 +644,10 @@ PYBIND11_MODULE(passes, m) { "4. if TK2 is not in `gateset`. applies the `tk1_replacement` function " "to each TK1(a,b,c)." "\n\n" - ":param gateset: the allowed operations in the rebased circuit\n" + ":param gateset: the allowed operations in the rebased circuit " + "(in addition, Measure, Reset and Collapse operations are always allowed " + "and are left alone; conditional operations may be present; and Phase " + "gates may also be introduced by the rebase)\n" ":param tk2_replacement: a function which, given the parameters (a,b,c) " "of an XXPhase(a)YYPhase(b)ZZPhase(c) triple, returns an equivalent " "circuit in the desired basis\n" @@ -639,7 +655,7 @@ PYBIND11_MODULE(passes, m) { "of an Rz(a)Rx(b)Rz(c) triple, returns an equivalent circuit in the " "desired basis\n" ":return: a pass that rebases to the given gate set (possibly including " - "conditional and phase operations)", + "conditional and phase operations, and Measure, Reset and Collapse)", py::arg("gateset"), py::arg("tk2_replacement"), py::arg("tk1_replacement")); diff --git a/pytket/docs/circuit.rst b/pytket/docs/circuit.rst index b8f4c3342c..4cae8e2a11 100644 --- a/pytket/docs/circuit.rst +++ b/pytket/docs/circuit.rst @@ -38,6 +38,9 @@ pytket.circuit .. autoclass:: pytket._tket.circuit.PauliExpBox :special-members: :members: +.. autoclass:: pytket._tket.circuit.PauliExpPairBox + :special-members: + :members: .. autoclass:: pytket._tket.circuit.ToffoliBox :special-members: :members: diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index 76282ef6d5..52f1283406 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -2339,6 +2339,8 @@ class Circuit: """ Get all classical registers. + This property is only valid if the bits in the circuit are organized into registers (i.e. all bit indices are single numbers and all sets of bits with the same string identifier consist of bits indexed consecutively from zero). + :return: List of :py:class:`BitRegister` """ @property @@ -2392,6 +2394,8 @@ class Circuit: """ Get all quantum registers. + This property is only valid if the qubits in the circuit are organized into registers (i.e. all qubit indices are single numbers and all sets of qubits with the same string identifier consist of qubits indexed consecutively from zero). + :return: List of :py:class:`QubitRegister` """ @property diff --git a/pytket/pytket/_tket/passes.pyi b/pytket/pytket/_tket/passes.pyi index a45c9cbd82..c4bf9d2b7d 100644 --- a/pytket/pytket/_tket/passes.pyi +++ b/pytket/pytket/_tket/passes.pyi @@ -318,7 +318,7 @@ def DecomposeTK2(allow_swaps: bool = True, **kwargs: Any) -> BasePass: If no fidelities are provided, the TK2 gates will be decomposed exactly using CX gates. For equal fidelities, ZZPhase will be prefered over ZZMax and CX if the decomposition results in fewer two-qubit gates. - All TK2 gate parameters must be normalised, i.e. they must satisfy `NormalisedTK2Predicate`. + All TK2 gate parameters must be normalised, i.e. they must satisfy `NormalisedTK2Predicate`. (This can be achieved by applying the :py:meth:`NormaliseTK2` pass beforehand.) Using the `allow_swaps=True` (default) option, qubits will be swapped when convenient to reduce the two-qubit gate count of the decomposed TK2. @@ -410,6 +410,8 @@ def KAKDecomposition(target_2qb_gate: pytket._tket.circuit.OpType = pytket._tket Using the `allow_swaps=True` (default) option, qubits will be swapped when convenient to further reduce the two-qubit gate count (only applicable when decomposing to CX gates). + Note that gates containing symbolic parameters are not squashed. + :param target_2qb_gate: OpType to decompose to. Either TK2 or CX. :param cx_fidelity: Estimated CX gate fidelity, used when target_2qb_gate=CX. :param allow_swaps: Whether to allow implicit wire swaps. @@ -488,10 +490,10 @@ def RebaseCustom(gateset: set[pytket._tket.circuit.OpType], cx_replacement: pytk 3. converts any single-qubit gates not in the gate type set to the form :math:`\mathrm{Rz}(a)\mathrm{Rx}(b)\mathrm{Rz}(c)` (in matrix-multiplication order, i.e. reverse order in the circuit); 4. applies the `tk1_replacement` function to each of these triples :math:`(a,b,c)` to generate replacement circuits. - :param gateset: the allowed operations in the rebased circuit + :param gateset: the allowed operations in the rebased circuit (in addition, Measure, Reset and Collapse operations are always allowed and are left alone; conditional operations may be present; and Phase gates may also be introduced by the rebase) :param cx_replacement: the equivalent circuit to replace a CX gate using two qubit gates from the desired basis (can use any single qubit OpTypes) :param tk1_replacement: a function which, given the parameters of an Rz(a)Rx(b)Rz(c) triple, returns an equivalent circuit in the desired basis - :return: a pass that rebases to the given gate set (possibly including conditional and phase operations) + :return: a pass that rebases to the given gate set (possibly including conditional and phase operations, and Measure, Reset and Collapse) """ @typing.overload def RebaseCustom(gateset: set[pytket._tket.circuit.OpType], tk2_replacement: typing.Callable[[typing.Union[sympy.Expr, float], typing.Union[sympy.Expr, float], typing.Union[sympy.Expr, float]], pytket._tket.circuit.Circuit], tk1_replacement: typing.Callable[[typing.Union[sympy.Expr, float], typing.Union[sympy.Expr, float], typing.Union[sympy.Expr, float]], pytket._tket.circuit.Circuit]) -> BasePass: @@ -503,14 +505,14 @@ def RebaseCustom(gateset: set[pytket._tket.circuit.OpType], tk2_replacement: typ 3. converts any single-qubit gates not in the gate type set to TK1; 4. if TK2 is not in `gateset`. applies the `tk1_replacement` function to each TK1(a,b,c). - :param gateset: the allowed operations in the rebased circuit + :param gateset: the allowed operations in the rebased circuit (in addition, Measure, Reset and Collapse operations are always allowed and are left alone; conditional operations may be present; and Phase gates may also be introduced by the rebase) :param tk2_replacement: a function which, given the parameters (a,b,c) of an XXPhase(a)YYPhase(b)ZZPhase(c) triple, returns an equivalent circuit in the desired basis :param tk1_replacement: a function which, given the parameters (a,b,c) of an Rz(a)Rx(b)Rz(c) triple, returns an equivalent circuit in the desired basis - :return: a pass that rebases to the given gate set (possibly including conditional and phase operations) + :return: a pass that rebases to the given gate set (possibly including conditional and phase operations, and Measure, Reset and Collapse) """ def RebaseTket() -> BasePass: """ - Converts all gates to CX, TK1 and Phase. + Converts all gates to CX, TK1 and Phase. (Any Measure, Reset and Collapse operations are left untouched; Conditional gates are also allowed.) """ def RemoveBarriers() -> BasePass: """ @@ -605,6 +607,8 @@ def ThreeQubitSquash(allow_swaps: bool = True) -> BasePass: """ Squash three-qubit subcircuits into subcircuits having fewer CX gates, when possible, and apply Clifford simplification. + The circuit to which this is applied must consist of single-qubit, pure-classical and CX gates, and Measure, Collapse, Reset, Phase and conditional gates. + :param allow_swaps: whether to allow implicit wire swaps """ def ZXGraphlikeOptimisation() -> BasePass: diff --git a/pytket/pytket/passes/auto_rebase.py b/pytket/pytket/passes/auto_rebase.py index 6af5c690c6..2c395c44b0 100644 --- a/pytket/pytket/passes/auto_rebase.py +++ b/pytket/pytket/passes/auto_rebase.py @@ -134,6 +134,10 @@ def auto_rebase_pass(gateset: Set[OpType], allow_swaps: bool = False) -> BasePas Raises an error if no known decompositions can be found, in which case try using RebaseCustom with your own decompositions. + In addition to the gate types in ``gateset``, any ``Measure``, ``Reset`` and + ``Collapse`` operations in the original circuit are retained. Conditional + operations are also allowed. ``Phase`` gates may also be introduced. + :param gateset: Set of supported OpTypes, target gate set. :type gateset: FrozenSet[OpType] :raises NoAutoRebase: No suitable decomposition found.