diff --git a/qualtran/bloqs/mcmt/__init__.py b/qualtran/bloqs/mcmt/__init__.py index a3b2b0073..23b8caf45 100644 --- a/qualtran/bloqs/mcmt/__init__.py +++ b/qualtran/bloqs/mcmt/__init__.py @@ -15,5 +15,5 @@ from qualtran.bloqs.mcmt.and_bloq import And, MultiAnd from qualtran.bloqs.mcmt.controlled_via_and import ControlledViaAnd from qualtran.bloqs.mcmt.ctrl_spec_and import CtrlSpecAnd -from qualtran.bloqs.mcmt.multi_control_pauli import MultiControlPauli, MultiControlX, MultiControlZ +from qualtran.bloqs.mcmt.multi_control_pauli import MultiControlX, MultiControlZ from qualtran.bloqs.mcmt.multi_target_cnot import MultiTargetCNOT diff --git a/qualtran/bloqs/mcmt/multi_control_multi_target_pauli.ipynb b/qualtran/bloqs/mcmt/multi_control_multi_target_pauli.ipynb index 6fb6eeeef..65993bfff 100644 --- a/qualtran/bloqs/mcmt/multi_control_multi_target_pauli.ipynb +++ b/qualtran/bloqs/mcmt/multi_control_multi_target_pauli.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "5c75973b", + "id": "8533d106", "metadata": { "cq.autogen": "title_cell" }, @@ -13,7 +13,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c0d3d2b2", + "id": "b5831fa4", "metadata": { "cq.autogen": "top_imports" }, @@ -30,7 +30,7 @@ }, { "cell_type": "markdown", - "id": "ac237fd0", + "id": "b85b5ac2", "metadata": { "cq.autogen": "MultiTargetCNOT.bloq_doc.md" }, @@ -48,7 +48,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a9e53831", + "id": "387c77c3", "metadata": { "cq.autogen": "MultiTargetCNOT.bloq_doc.py" }, @@ -59,7 +59,7 @@ }, { "cell_type": "markdown", - "id": "70036306", + "id": "cb66ffb6", "metadata": { "cq.autogen": "MultiTargetCNOT.example_instances.md" }, @@ -70,7 +70,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40a9ec07", + "id": "e4d9154a", "metadata": { "cq.autogen": "MultiTargetCNOT.c_multi_not_symb" }, @@ -83,7 +83,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ecddf931", + "id": "ca47c43a", "metadata": { "cq.autogen": "MultiTargetCNOT.c_multi_not" }, @@ -94,7 +94,7 @@ }, { "cell_type": "markdown", - "id": "251ca68a", + "id": "a44ef0b1", "metadata": { "cq.autogen": "MultiTargetCNOT.graphical_signature.md" }, @@ -105,7 +105,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bff75a03", + "id": "baafd2bf", "metadata": { "cq.autogen": "MultiTargetCNOT.graphical_signature.py" }, @@ -118,7 +118,7 @@ }, { "cell_type": "markdown", - "id": "bd425677", + "id": "60bc96ef", "metadata": { "cq.autogen": "MultiTargetCNOT.call_graph.md" }, @@ -129,7 +129,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a0082f8f", + "id": "59e8162e", "metadata": { "cq.autogen": "MultiTargetCNOT.call_graph.py" }, @@ -141,57 +141,46 @@ "show_counts_sigma(c_multi_not_symb_sigma)" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "5457e35b", - "metadata": {}, - "outputs": [], - "source": [ - "from qualtran.drawing import get_musical_score_data, draw_musical_score\n", - "\n", - "draw_musical_score(get_musical_score_data(c_multi_not.decompose_bloq()))" - ] - }, { "cell_type": "markdown", - "id": "aba024ec", + "id": "2de64cfb", "metadata": { - "cq.autogen": "MultiControlPauli.bloq_doc.md" + "cq.autogen": "MultiControlX.bloq_doc.md" }, "source": [ - "## `MultiControlPauli`\n", - "Implements multi-control, single-target C^{n}P gate.\n", + "## `MultiControlX`\n", + "Implements multi-control, single-target X gate.\n", "\n", - "Implements $C^{n}P = (1 - |1^{n}><1^{n}|) I + |1^{n}><1^{n}| P^{n}$ using $n-1$\n", - "clean ancillas using a multi-controlled `AND` gate. Uses the Toffoli ladder\n", - "construction described in \"n−2 Ancilla Bits\" section of Ref[1] but uses an\n", - "$\\text{AND} / \\text{AND}^\\dagger$ ladder instead for computing / uncomputing\n", - "using clean ancillas instead of the Toffoli ladder. The measurement based\n", - "uncomputation of $\\text{AND}$ does not consume any magic states and thus has\n", - "better constant factors.\n", + "Reduces multiple controls to a single control using an `And` ladder.\n", + "See class `ControlledViaAnd` for details on construction.\n", "\n", - "#### References\n", - " - [Constructing Large Controlled Nots](https://algassert.com/circuits/2015/06/05/Constructing-Large-Controlled-Nots.html). \n" + "Alternatively, one can directly use `XGate().controlled(CtrlSpec(cvs=cvs))`\n", + "\n", + "#### Parameters\n", + " - `cvs`: a tuple of `n` control bits, or a `HasLength(n)` to control by `n` 1s. \n", + "\n", + "#### Registers\n", + " - `controls`: control register of type `QBit` and shape `(n,)`.\n", + " - `target`: single qubit target register.\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "bf4f6c5a", + "id": "9b43be2a", "metadata": { - "cq.autogen": "MultiControlPauli.bloq_doc.py" + "cq.autogen": "MultiControlX.bloq_doc.py" }, "outputs": [], "source": [ - "from qualtran.bloqs.mcmt import MultiControlPauli" + "from qualtran.bloqs.mcmt import MultiControlX" ] }, { "cell_type": "markdown", - "id": "a3deef58", + "id": "f9fbb578", "metadata": { - "cq.autogen": "MultiControlPauli.example_instances.md" + "cq.autogen": "MultiControlX.example_instances.md" }, "source": [ "### Example Instances" @@ -200,20 +189,20 @@ { "cell_type": "code", "execution_count": null, - "id": "610dfdf5", + "id": "050b0f8d", "metadata": { - "cq.autogen": "MultiControlPauli.ccpauli" + "cq.autogen": "MultiControlX.ccpauli" }, "outputs": [], "source": [ - "ccpauli = MultiControlPauli(cvs=(1, 0, 1, 0, 1), target_gate=cirq.X)" + "ccpauli = MultiControlX(cvs=(1, 0, 1, 0, 1))" ] }, { "cell_type": "markdown", - "id": "29045880", + "id": "ccf7ef61", "metadata": { - "cq.autogen": "MultiControlPauli.graphical_signature.md" + "cq.autogen": "MultiControlX.graphical_signature.md" }, "source": [ "#### Graphical Signature" @@ -222,9 +211,9 @@ { "cell_type": "code", "execution_count": null, - "id": "df830018", + "id": "4fb51559", "metadata": { - "cq.autogen": "MultiControlPauli.graphical_signature.py" + "cq.autogen": "MultiControlX.graphical_signature.py" }, "outputs": [], "source": [ @@ -235,9 +224,9 @@ }, { "cell_type": "markdown", - "id": "6849b86b", + "id": "358ff8ae", "metadata": { - "cq.autogen": "MultiControlPauli.call_graph.md" + "cq.autogen": "MultiControlX.call_graph.md" }, "source": [ "### Call Graph" @@ -246,9 +235,9 @@ { "cell_type": "code", "execution_count": null, - "id": "dd1f8a53", + "id": "216d9bdf", "metadata": { - "cq.autogen": "MultiControlPauli.call_graph.py" + "cq.autogen": "MultiControlX.call_graph.py" }, "outputs": [], "source": [ @@ -261,21 +250,12 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "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.10.9" + "name": "python" } }, "nbformat": 4, diff --git a/qualtran/bloqs/mcmt/multi_control_pauli.py b/qualtran/bloqs/mcmt/multi_control_pauli.py index 27300e739..a871d59a8 100644 --- a/qualtran/bloqs/mcmt/multi_control_pauli.py +++ b/qualtran/bloqs/mcmt/multi_control_pauli.py @@ -13,12 +13,12 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Tuple, TYPE_CHECKING, Union +from typing import Dict, Optional, Tuple, TYPE_CHECKING, Union -import cirq import numpy as np import sympy from attrs import field, frozen +from numpy.typing import NDArray from qualtran import ( Bloq, @@ -33,18 +33,20 @@ Signature, SoquetT, ) -from qualtran.bloqs.basic_gates import XGate -from qualtran.bloqs.mcmt.and_bloq import _to_tuple_or_has_length, is_symbolic +from qualtran.bloqs.basic_gates import XGate, ZGate +from qualtran.bloqs.mcmt.and_bloq import _to_tuple_or_has_length from qualtran.bloqs.mcmt.controlled_via_and import ControlledViaAnd -from qualtran.symbolics import HasLength, SymbolicInt +from qualtran.drawing import Circle, TextBox, WireSymbol +from qualtran.symbolics import HasLength, is_symbolic, Shaped, slen, SymbolicInt if TYPE_CHECKING: + import cirq + from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator - from qualtran.simulation.classical_sim import ClassicalValT @frozen -class MultiControlPauli(GateWithRegisters): +class _MultiControlPauli(GateWithRegisters): r"""Implements multi-control, single-target C^{n}P gate. Implements $C^{n}P = (1 - |1^{n}><1^{n}|) I + |1^{n}><1^{n}| P^{n}$ using $n-1$ @@ -60,7 +62,7 @@ class MultiControlPauli(GateWithRegisters): """ cvs: Union[HasLength, Tuple[int, ...]] = field(converter=_to_tuple_or_has_length) - target_gate: cirq.Pauli + target_bloq: Bloq @cached_property def signature(self) -> 'Signature': @@ -72,7 +74,7 @@ def signature(self) -> 'Signature': @property def n_ctrls(self) -> SymbolicInt: - return self.cvs.n if isinstance(self.cvs, HasLength) else len(self.cvs) + return slen(self.cvs) @property def concrete_cvs(self) -> Tuple[int, ...]: @@ -80,15 +82,12 @@ def concrete_cvs(self) -> Tuple[int, ...]: raise ValueError(f"{self.cvs} is symbolic") return self.cvs - @property - def target_bloq(self) -> Bloq: - from qualtran.cirq_interop import cirq_gate_to_bloq - - return cirq_gate_to_bloq(self.target_gate) - @property def _multi_ctrl_bloq(self) -> ControlledViaAnd: - ctrl_spec = CtrlSpec(cvs=(np.array(self.concrete_cvs),)) + cvs: Union[NDArray[np.integer], Shaped] = ( + Shaped((self.n_ctrls,)) if is_symbolic(self.n_ctrls) else np.array(self.concrete_cvs) + ) + ctrl_spec = CtrlSpec(cvs=(cvs,)) return ControlledViaAnd(self.target_bloq, ctrl_spec) def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']: @@ -109,52 +108,46 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str return {'controls': out_soqs[ctrl_reg_name], 'target': out_soqs[target_reg_name]} + def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': + if self.n_ctrls == 0: + return {self.target_bloq: 1} + return {self._multi_ctrl_bloq: 1} + def __str__(self) -> str: n = self.n_ctrls ctrl = f'C^{n}' if is_symbolic(n) or n > 2 else ['', 'C', 'CC'][int(n)] - return f'{ctrl}{self.target_gate!s}' + return f'{ctrl}{self.target_bloq!s}' - def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo: - wire_symbols = ["@" if b else "@(0)" for b in self.concrete_cvs] - wire_symbols += [str(self.target_gate)] - return cirq.CircuitDiagramInfo(wire_symbols=wire_symbols) + def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': + if reg is None: + return TextBox(str(self)) + if reg.name == 'target': + (target_reg,) = tuple(self.target_bloq.signature) + return self.target_bloq.wire_symbol(target_reg) - def on_classical_vals(self, **vals: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: - controls, target = vals.get('controls', np.array([])), vals.get('target', 0) - if self.target_gate not in (cirq.X, XGate()): - raise NotImplementedError(f"{self} is not classically simulatable.") + (i,) = idx + cv = self.concrete_cvs[i] + return Circle(filled=(cv == 1)) - if np.all(self.concrete_cvs == controls): - target = (target + 1) % 2 + def _circuit_diagram_info_(self, args) -> 'cirq.CircuitDiagramInfo': + from qualtran.cirq_interop._bloq_to_cirq import _wire_symbol_to_cirq_diagram_info - return {'controls': controls, 'target': target} + return _wire_symbol_to_cirq_diagram_info(self, args) - def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': - if self.n_ctrls == 0: - return {self.target_bloq: 1} - - if is_symbolic(self.cvs): - # TODO CtrlSpec does not support symbolic cvs yet. - # remove this case once support is added. - # https://github.com/quantumlib/Qualtran/issues/1168 - from qualtran.bloqs.mcmt.and_bloq import And, MultiAnd - - if self.n_ctrls == 1: - return {self.target_bloq.controlled(): 1} - elif self.n_ctrls == 2: - and_bloq = And(ssa.new_symbol('cv1'), ssa.new_symbol('cv2')) - return {self.target_bloq.controlled(): 1, and_bloq: 1, and_bloq.adjoint(): 1} - else: - m_and_bloq = MultiAnd(self.cvs) - return {self.target_bloq.controlled(): 1, m_and_bloq: 1, m_and_bloq.adjoint(): 1} + def _apply_unitary_(self, args: 'cirq.ApplyUnitaryArgs') -> np.ndarray: + import cirq - return {self._multi_ctrl_bloq: 1} + from qualtran.cirq_interop import BloqAsCirqGate - def _apply_unitary_(self, args: 'cirq.ApplyUnitaryArgs') -> np.ndarray: + target_gate = ( + self.target_bloq + if isinstance(self.target_bloq, cirq.Gate) + else BloqAsCirqGate(self.target_bloq) + ) cpauli = ( - self.target_gate.controlled(control_values=self.concrete_cvs) + target_gate.controlled(control_values=self.concrete_cvs) if self.n_ctrls - else self.target_gate + else target_gate ) return cirq.apply_unitary(cpauli, args) @@ -162,46 +155,66 @@ def _has_unitary_(self) -> bool: return not is_symbolic(self.n_ctrls) +@frozen +class MultiControlX(_MultiControlPauli): + r"""Implements multi-control, single-target X gate. + + Reduces multiple controls to a single control using an `And` ladder. + See class `ControlledViaAnd` for details on construction. + + Alternatively, one can directly use `XGate().controlled(CtrlSpec(cvs=cvs))` + + Args: + cvs: a tuple of `n` control bits, or a `HasLength(n)` to control by `n` 1s. + + Registers: + controls: control register of type `QBit` and shape `(n,)`. + target: single qubit target register. + """ + + target_bloq: Bloq = field(init=False) + + @target_bloq.default + def _X(self): + return XGate() + + @bloq_example -def _ccpauli() -> MultiControlPauli: - ccpauli = MultiControlPauli(cvs=(1, 0, 1, 0, 1), target_gate=cirq.X) +def _ccpauli() -> MultiControlX: + ccpauli = MultiControlX(cvs=(1, 0, 1, 0, 1)) return ccpauli @bloq_example -def _ccpauli_symb() -> MultiControlPauli: +def _ccpauli_symb() -> MultiControlX: from qualtran.symbolics import HasLength - ccpauli_symb = MultiControlPauli(cvs=HasLength(sympy.Symbol("n")), target_gate=cirq.X) + ccpauli_symb = MultiControlX(cvs=HasLength(sympy.Symbol("n"))) return ccpauli_symb -_CC_PAULI_DOC = BloqDocSpec(bloq_cls=MultiControlPauli, examples=(_ccpauli,)) +_CC_PAULI_DOC = BloqDocSpec(bloq_cls=MultiControlX, examples=(_ccpauli,)) @frozen -class MultiControlX(MultiControlPauli): - r"""Implements multi-control, single-target X gate. - - See :class:`MultiControlPauli` for implementation and costs. - """ - - target_gate: cirq.Pauli = field(init=False) +class MultiControlZ(_MultiControlPauli): + r"""Implements multi-control, single-target Z gate. - @target_gate.default - def _X(self): - return cirq.X + Reduces multiple controls to a single control using an `And` ladder. + See class `ControlledViaAnd` for details on construction. + Alternatively, one can directly use `ZGate().controlled(CtrlSpec(cvs=cvs))` -@frozen -class MultiControlZ(MultiControlPauli): - r"""Implements multi-control, single-target Z gate. + Args: + cvs: a tuple of `n` control bits, or a `HasLength(n)` to control by `n` 1s. - See :class:`MultiControlPauli` for implementation and costs. + Registers: + controls: control register of type `QBit` and shape `(n,)`. + target: single qubit target register. """ - target_gate: cirq.Pauli = field(init=False) + target_bloq: Bloq = field(init=False) - @target_gate.default + @target_bloq.default def _Z(self): - return cirq.Z + return ZGate() diff --git a/qualtran/bloqs/mcmt/multi_control_pauli_test.py b/qualtran/bloqs/mcmt/multi_control_pauli_test.py index 4386cf9bc..2efcf6a60 100644 --- a/qualtran/bloqs/mcmt/multi_control_pauli_test.py +++ b/qualtran/bloqs/mcmt/multi_control_pauli_test.py @@ -17,10 +17,12 @@ import pytest import qualtran.testing as qlt_testing +from qualtran import Bloq +from qualtran.bloqs.basic_gates import XGate, YGate, ZGate from qualtran.bloqs.mcmt.multi_control_pauli import ( _ccpauli, _ccpauli_symb, - MultiControlPauli, + _MultiControlPauli, MultiControlX, ) @@ -35,10 +37,10 @@ def test_ccpauli_symb(): @pytest.mark.parametrize("num_controls", [0, 1, 2, *range(7, 17)]) -@pytest.mark.parametrize("pauli", [cirq.X, cirq.Y, cirq.Z]) +@pytest.mark.parametrize("pauli", [XGate(), YGate(), ZGate()]) @pytest.mark.parametrize('cv', [0, 1]) -def test_t_complexity_mcp(num_controls: int, pauli: cirq.Pauli, cv: int): - gate = MultiControlPauli([cv] * num_controls, target_gate=pauli) +def test_t_complexity_mcp(num_controls: int, pauli: Bloq, cv: int): + gate = _MultiControlPauli([cv] * num_controls, target_bloq=pauli) qlt_testing.assert_valid_bloq_decomposition(gate) qlt_testing.assert_equivalent_bloq_counts(gate) @@ -47,8 +49,10 @@ def test_t_complexity_mcp(num_controls: int, pauli: cirq.Pauli, cv: int): @pytest.mark.parametrize("pauli", [cirq.X, cirq.Y, cirq.Z]) @pytest.mark.parametrize('cv', [0, 1]) def test_mcp_unitary(num_controls: int, pauli: cirq.Pauli, cv: int): + from qualtran.cirq_interop import cirq_gate_to_bloq + cvs = (cv,) * num_controls - gate = MultiControlPauli(cvs, target_gate=pauli) + gate = _MultiControlPauli(cvs, target_bloq=cirq_gate_to_bloq(pauli)) cpauli = pauli.controlled(control_values=cvs) if num_controls else pauli np.testing.assert_allclose(gate.tensor_contract(), cirq.unitary(cpauli)) @@ -70,8 +74,8 @@ def test_multi_control_x(cvs): ((), 0, (), 1), ], ) -def test_classical_multi_control_pauli_target_x(cvs, x, ctrls, result): - bloq = MultiControlPauli(cvs=cvs, target_gate=cirq.X) +def test_classical_multi_control_X_target_x(cvs, x, ctrls, result): + bloq = MultiControlX(cvs=cvs) cbloq = bloq.decompose_bloq() kwargs = {'target': x} | ({'controls': ctrls} if ctrls else {}) bloq_classical = bloq.call_classically(**kwargs) @@ -105,3 +109,8 @@ def test_classical_multi_control_x(cvs, x, ctrls, result): np.testing.assert_array_equal(bloq_classical[i], cbloq_classical[i]) assert bloq_classical[-1] == result + + +@pytest.mark.notebook +def test_notebook(): + qlt_testing.execute_notebook('multi_control_multi_target_pauli') diff --git a/qualtran/bloqs/qubitization/qubitization_walk_operator_test.py b/qualtran/bloqs/qubitization/qubitization_walk_operator_test.py index 69b8da1d5..37cf3dab0 100644 --- a/qualtran/bloqs/qubitization/qubitization_walk_operator_test.py +++ b/qualtran/bloqs/qubitization/qubitization_walk_operator_test.py @@ -16,10 +16,9 @@ import numpy as np import pytest -from qualtran import Adjoint -from qualtran.bloqs.basic_gates import Power, XGate +from qualtran import Adjoint, Controlled +from qualtran.bloqs.basic_gates import Power, XGate, ZGate from qualtran.bloqs.chemistry.ising.walk_operator import get_walk_operator_for_1d_ising_model -from qualtran.bloqs.mcmt import MultiControlPauli from qualtran.bloqs.multiplexers.select_pauli_lcu import SelectPauliLCU from qualtran.bloqs.qubitization.qubitization_walk_operator import ( _thc_walk_op, @@ -174,10 +173,12 @@ def test_qubitization_walk_operator_diagrams(): # 4. Diagram for $Ctrl-W = Ctrl-SELECT.Ctrl-R_{L}$ in terms of $Ctrl-SELECT$ and $PREPARE$. def pred(binst): - bloqs_to_keep = (SelectPauliLCU, StatePreparationAliasSampling, MultiControlPauli, XGate) + bloqs_to_keep = (SelectPauliLCU, StatePreparationAliasSampling) keep = binst.bloq_is(bloqs_to_keep) if binst.bloq_is(Adjoint): keep |= isinstance(binst.bloq.subbloq, bloqs_to_keep) + if binst.bloq_is(Controlled) and isinstance(binst.bloq.subbloq, (XGate, ZGate)): + keep = True return not keep greedy_mm = cirq.GreedyQubitManager(prefix="ancilla", maximize_reuse=True) @@ -186,51 +187,51 @@ def pred(binst): cirq.testing.assert_has_diagram( circuit, ''' - ┌──────────────────────────────┐ -ancilla_0: ─────────────────────sigma_mu─────────────────────────────────sigma_mu───────────────────────── - │ │ -ancilla_1: ─────────────────────sigma_mu─────────────────────────────────sigma_mu───────────────────────── - │ │ -ancilla_2: ─────────────────────sigma_mu─────────────────────────────────sigma_mu───────────────────────── - │ │ -ancilla_3: ─────────────────────sigma_mu─────────────────────────────────sigma_mu───────────────────────── - │ │ -ancilla_4: ─────────────────────sigma_mu─────────────────────────────────sigma_mu───────────────────────── - │ │ -ancilla_5: ─────────────────────alt──────────────────────────────────────alt────────────────────────────── - │ │ -ancilla_6: ─────────────────────alt──────────────────────────────────────alt────────────────────────────── - │ │ -ancilla_7: ─────────────────────alt──────────────────────────────────────alt────────────────────────────── - │ │ -ancilla_8: ─────────────────────keep─────────────────────────────────────keep───────────────────────────── - │ │ -ancilla_9: ─────────────────────keep─────────────────────────────────────keep───────────────────────────── - │ │ -ancilla_10: ────────────────────keep─────────────────────────────────────keep───────────────────────────── - │ │ -ancilla_11: ────────────────────keep─────────────────────────────────────keep───────────────────────────── - │ │ -ancilla_12: ────────────────────keep─────────────────────────────────────keep───────────────────────────── - │ │ -ancilla_13: ────────────────────less_than_equal──────────────────────────less_than_equal────────────────── - │ │ -ctrl: ─────────@────────────────┼───────────────────────────────Z───────Z┼──────────────────────────────── - │ │ │ │ -selection0: ───In───────────────StatePreparationAliasSampling───@(0)─────StatePreparationAliasSampling──── - │ │ │ │ -selection1: ───In───────────────selection───────────────────────@(0)─────selection──────────────────────── - │ │ │ │ -selection2: ───In───────────────selection^-1────────────────────@(0)─────selection──────────────────────── + ┌──────────────────────────────┐ +ancilla_0: ─────────────────────sigma_mu────────────────────────────────sigma_mu───────────────────────── + │ │ +ancilla_1: ─────────────────────sigma_mu────────────────────────────────sigma_mu───────────────────────── + │ │ +ancilla_2: ─────────────────────sigma_mu────────────────────────────────sigma_mu───────────────────────── + │ │ +ancilla_3: ─────────────────────sigma_mu────────────────────────────────sigma_mu───────────────────────── + │ │ +ancilla_4: ─────────────────────sigma_mu────────────────────────────────sigma_mu───────────────────────── + │ │ +ancilla_5: ─────────────────────alt─────────────────────────────────────alt────────────────────────────── + │ │ +ancilla_6: ─────────────────────alt─────────────────────────────────────alt────────────────────────────── + │ │ +ancilla_7: ─────────────────────alt─────────────────────────────────────alt────────────────────────────── + │ │ +ancilla_8: ─────────────────────keep────────────────────────────────────keep───────────────────────────── + │ │ +ancilla_9: ─────────────────────keep────────────────────────────────────keep───────────────────────────── + │ │ +ancilla_10: ────────────────────keep────────────────────────────────────keep───────────────────────────── + │ │ +ancilla_11: ────────────────────keep────────────────────────────────────keep───────────────────────────── + │ │ +ancilla_12: ────────────────────keep────────────────────────────────────keep───────────────────────────── + │ │ +ancilla_13: ────────────────────less_than_equal─────────────────────────less_than_equal────────────────── + │ │ +ctrl: ─────────@────────────────┼───────────────────────────────Z──────Z┼──────────────────────────────── + │ │ │ │ +selection0: ───In───────────────StatePreparationAliasSampling───(0)─────StatePreparationAliasSampling──── + │ │ │ │ +selection1: ───In───────────────selection───────────────────────(0)─────selection──────────────────────── + │ │ │ │ +selection2: ───In───────────────selection^-1────────────────────(0)─────selection──────────────────────── │ -target0: ──────SelectPauliLCU───────────────────────────────────────────────────────────────────────────── +target0: ──────SelectPauliLCU──────────────────────────────────────────────────────────────────────────── │ -target1: ──────SelectPauliLCU───────────────────────────────────────────────────────────────────────────── +target1: ──────SelectPauliLCU──────────────────────────────────────────────────────────────────────────── │ -target2: ──────SelectPauliLCU───────────────────────────────────────────────────────────────────────────── +target2: ──────SelectPauliLCU──────────────────────────────────────────────────────────────────────────── │ -target3: ──────SelectPauliLCU───────────────────────────────────────────────────────────────────────────── - └──────────────────────────────┘ +target3: ──────SelectPauliLCU──────────────────────────────────────────────────────────────────────────── + └──────────────────────────────┘ ''', ) # pylint: enable=line-too-long diff --git a/qualtran/bloqs/reflections/reflection_using_prepare_test.py b/qualtran/bloqs/reflections/reflection_using_prepare_test.py index 30830e6d3..502f6e435 100644 --- a/qualtran/bloqs/reflections/reflection_using_prepare_test.py +++ b/qualtran/bloqs/reflections/reflection_using_prepare_test.py @@ -25,7 +25,7 @@ from qualtran.bloqs.arithmetic import LessThanConstant, LessThanEqual from qualtran.bloqs.basic_gates import ZPowGate from qualtran.bloqs.basic_gates.swap import CSwap -from qualtran.bloqs.mcmt import MultiControlPauli, MultiTargetCNOT +from qualtran.bloqs.mcmt import MultiControlX, MultiTargetCNOT from qualtran.bloqs.mcmt.and_bloq import And from qualtran.bloqs.reflections.prepare_identity import PrepareIdentity from qualtran.bloqs.reflections.reflection_using_prepare import ( @@ -49,7 +49,7 @@ LessThanEqual, CSwap, MultiTargetCNOT, - MultiControlPauli, + MultiControlX, cirq.H, cirq.CCNOT, cirq.CNOT, @@ -151,25 +151,25 @@ def test_reflection_using_prepare_diagram(): cirq.testing.assert_has_diagram( circuit, ''' -ancilla_0: ────X───────────────────────────────Z──────X─────────────────────────────── +ancilla_0: ────X───────────────────────────────Z─────X─────────────────────────────── │ -ancilla_1: ────sigma_mu────────────────────────┼──────sigma_mu──────────────────────── - │ │ │ -ancilla_2: ────alt─────────────────────────────┼──────alt───────────────────────────── - │ │ │ -ancilla_3: ────alt─────────────────────────────┼──────alt───────────────────────────── - │ │ │ -ancilla_4: ────alt─────────────────────────────┼──────alt───────────────────────────── - │ │ │ -ancilla_5: ────keep────────────────────────────┼──────keep──────────────────────────── - │ │ │ -ancilla_6: ────less_than_equal─────────────────┼──────less_than_equal───────────────── - │ │ │ -selection0: ───StatePreparationAliasSampling───@(0)───StatePreparationAliasSampling─── - │ │ │ -selection1: ───selection───────────────────────@(0)───selection─────────────────────── - │ │ │ -selection2: ───selection^-1────────────────────@(0)───selection─────────────────────── +ancilla_1: ────sigma_mu────────────────────────┼─────sigma_mu──────────────────────── + │ │ │ +ancilla_2: ────alt─────────────────────────────┼─────alt───────────────────────────── + │ │ │ +ancilla_3: ────alt─────────────────────────────┼─────alt───────────────────────────── + │ │ │ +ancilla_4: ────alt─────────────────────────────┼─────alt───────────────────────────── + │ │ │ +ancilla_5: ────keep────────────────────────────┼─────keep──────────────────────────── + │ │ │ +ancilla_6: ────less_than_equal─────────────────┼─────less_than_equal───────────────── + │ │ │ +selection0: ───StatePreparationAliasSampling───(0)───StatePreparationAliasSampling─── + │ │ │ +selection1: ───selection───────────────────────(0)───selection─────────────────────── + │ │ │ +selection2: ───selection^-1────────────────────(0)───selection─────────────────────── ''', ) @@ -179,25 +179,25 @@ def test_reflection_using_prepare_diagram(): cirq.testing.assert_has_diagram( circuit, ''' -ancilla_0: ────sigma_mu───────────────────────────────sigma_mu──────────────────────── - │ │ -ancilla_1: ────alt────────────────────────────────────alt───────────────────────────── - │ │ -ancilla_2: ────alt────────────────────────────────────alt───────────────────────────── - │ │ -ancilla_3: ────alt────────────────────────────────────alt───────────────────────────── - │ │ -ancilla_4: ────keep───────────────────────────────────keep──────────────────────────── - │ │ -ancilla_5: ────less_than_equal────────────────────────less_than_equal───────────────── - │ │ -control: ──────┼───────────────────────────────Z──────┼─────────────────────────────── - │ │ │ -selection0: ───StatePreparationAliasSampling───@(0)───StatePreparationAliasSampling─── - │ │ │ -selection1: ───selection───────────────────────@(0)───selection─────────────────────── - │ │ │ -selection2: ───selection^-1────────────────────@(0)───selection─────────────────────── +ancilla_0: ────sigma_mu──────────────────────────────sigma_mu──────────────────────── + │ │ +ancilla_1: ────alt───────────────────────────────────alt───────────────────────────── + │ │ +ancilla_2: ────alt───────────────────────────────────alt───────────────────────────── + │ │ +ancilla_3: ────alt───────────────────────────────────alt───────────────────────────── + │ │ +ancilla_4: ────keep──────────────────────────────────keep──────────────────────────── + │ │ +ancilla_5: ────less_than_equal───────────────────────less_than_equal───────────────── + │ │ +control: ──────┼───────────────────────────────Z─────┼─────────────────────────────── + │ │ │ +selection0: ───StatePreparationAliasSampling───(0)───StatePreparationAliasSampling─── + │ │ │ +selection1: ───selection───────────────────────(0)───selection─────────────────────── + │ │ │ +selection2: ───selection^-1────────────────────(0)───selection─────────────────────── ''', ) @@ -207,27 +207,27 @@ def test_reflection_using_prepare_diagram(): cirq.testing.assert_has_diagram( circuit, ''' - ┌──────────────────────────────┐ ┌──────────────────────────────┐ -ancilla_0: ─────sigma_mu───────────────────────────────────sigma_mu───────────────────────── - │ │ -ancilla_1: ─────alt────────────────────────────────────────alt────────────────────────────── - │ │ -ancilla_2: ─────alt────────────────────────────────────────alt────────────────────────────── - │ │ -ancilla_3: ─────alt────────────────────────────────────────alt────────────────────────────── - │ │ -ancilla_4: ─────keep───────────────────────────────────────keep───────────────────────────── - │ │ -ancilla_5: ─────less_than_equal────────────────────────────less_than_equal────────────────── - │ │ -control: ───────┼────────────────────────────X────Z───────X┼──────────────────────────────── - │ │ │ -selection0: ────StatePreparationAliasSampling─────@(0)─────StatePreparationAliasSampling──── - │ │ │ -selection1: ────selection─────────────────────────@(0)─────selection──────────────────────── - │ │ │ -selection2: ────selection^-1──────────────────────@(0)─────selection──────────────────────── - └──────────────────────────────┘ └──────────────────────────────┘ + ┌──────────────────────────────┐ ┌──────────────────────────────┐ +ancilla_0: ─────sigma_mu──────────────────────────────────sigma_mu───────────────────────── + │ │ +ancilla_1: ─────alt───────────────────────────────────────alt────────────────────────────── + │ │ +ancilla_2: ─────alt───────────────────────────────────────alt────────────────────────────── + │ │ +ancilla_3: ─────alt───────────────────────────────────────alt────────────────────────────── + │ │ +ancilla_4: ─────keep──────────────────────────────────────keep───────────────────────────── + │ │ +ancilla_5: ─────less_than_equal───────────────────────────less_than_equal────────────────── + │ │ +control: ───────┼────────────────────────────X────Z──────X┼──────────────────────────────── + │ │ │ +selection0: ────StatePreparationAliasSampling─────(0)─────StatePreparationAliasSampling──── + │ │ │ +selection1: ────selection─────────────────────────(0)─────selection──────────────────────── + │ │ │ +selection2: ────selection^-1──────────────────────(0)─────selection──────────────────────── + └──────────────────────────────┘ └──────────────────────────────┘ ''', ) diff --git a/qualtran/resource_counting/classify_bloqs.py b/qualtran/resource_counting/classify_bloqs.py index eae56e52e..bb2a57323 100644 --- a/qualtran/resource_counting/classify_bloqs.py +++ b/qualtran/resource_counting/classify_bloqs.py @@ -229,7 +229,7 @@ def bloq_is_rotation(b: Bloq) -> bool: ) if isinstance(b, Controlled): - if b.ctrl_spec.num_qubits > 1: + if b.ctrl_spec.num_qubits != 1: return False # TODO https://github.com/quantumlib/Qualtran/issues/878 diff --git a/qualtran/serialization/resolver_dict.py b/qualtran/serialization/resolver_dict.py index cd01026fb..ff6b9fecb 100644 --- a/qualtran/serialization/resolver_dict.py +++ b/qualtran/serialization/resolver_dict.py @@ -385,7 +385,7 @@ "qualtran.bloqs.mcmt.and_bloq.MultiAnd": qualtran.bloqs.mcmt.and_bloq.MultiAnd, "qualtran.bloqs.mcmt.ctrl_spec_and.CtrlSpecAnd": qualtran.bloqs.mcmt.ctrl_spec_and.CtrlSpecAnd, "qualtran.bloqs.mcmt.controlled_via_and.ControlledViaAnd": qualtran.bloqs.mcmt.controlled_via_and.ControlledViaAnd, - "qualtran.bloqs.mcmt.multi_control_pauli.MultiControlPauli": qualtran.bloqs.mcmt.multi_control_pauli.MultiControlPauli, + "qualtran.bloqs.mcmt.multi_control_pauli._MultiControlPauli": qualtran.bloqs.mcmt.multi_control_pauli._MultiControlPauli, "qualtran.bloqs.mcmt.multi_control_pauli.MultiControlX": qualtran.bloqs.mcmt.multi_control_pauli.MultiControlX, "qualtran.bloqs.mcmt.multi_control_pauli.MultiControlZ": qualtran.bloqs.mcmt.multi_control_pauli.MultiControlZ, "qualtran.bloqs.mcmt.multi_target_cnot.MultiTargetCNOT": qualtran.bloqs.mcmt.multi_target_cnot.MultiTargetCNOT,