diff --git a/qualtran/_infra/gate_with_registers.py b/qualtran/_infra/gate_with_registers.py index 6afd4265d..21f921a5a 100644 --- a/qualtran/_infra/gate_with_registers.py +++ b/qualtran/_infra/gate_with_registers.py @@ -283,7 +283,7 @@ def decompose_bloq(self) -> 'CompositeBloq': - `build_composite_bloq` raises a `DecomposeNotImplementedError` and - `decompose_from_registers` raises a `DecomposeNotImplementedError`. """ - from qualtran.cirq_interop._cirq_to_bloq import decompose_from_cirq_style_method + from qualtran.cirq_interop import decompose_from_cirq_style_method try: return Bloq.decompose_bloq(self) diff --git a/qualtran/bloqs/swap_network/cswap_approx.py b/qualtran/bloqs/swap_network/cswap_approx.py index 3e5dcbdf5..937183929 100644 --- a/qualtran/bloqs/swap_network/cswap_approx.py +++ b/qualtran/bloqs/swap_network/cswap_approx.py @@ -13,16 +13,18 @@ # limitations under the License. from functools import cached_property -from typing import Dict, Iterator, Set, TYPE_CHECKING +from typing import Dict, Iterator, Optional, Set, Tuple, TYPE_CHECKING import cirq from attrs import frozen from numpy.typing import NDArray -from qualtran import bloq_example, BloqDocSpec, GateWithRegisters, Signature +from qualtran import Bloq, bloq_example, BloqDocSpec, CompositeBloq, Register, Signature from qualtran.bloqs.basic_gates import TGate from qualtran.bloqs.bookkeeping import ArbitraryClifford from qualtran.bloqs.mcmt.multi_control_multi_target_pauli import MultiTargetCNOT +from qualtran.cirq_interop import decompose_from_cirq_style_method +from qualtran.drawing import Circle, TextBox, WireSymbol from qualtran.resource_counting.generalizers import ( cirq_to_bloqs, generalize_rotation_angle, @@ -37,7 +39,7 @@ @frozen -class CSwapApprox(GateWithRegisters): +class CSwapApprox(Bloq): r"""Approximately implements a multi-target controlled swap unitary using only $4n$ T-gates. Implements $\mathrm{CSWAP}_n = |0 \rangle\langle 0| I + |1 \rangle\langle 1| \mathrm{SWAP}_n$ @@ -65,6 +67,9 @@ class CSwapApprox(GateWithRegisters): def signature(self) -> Signature: return Signature.build(ctrl=1, x=self.bitsize, y=self.bitsize) + def decompose_bloq(self) -> 'CompositeBloq': + return decompose_from_cirq_style_method(self) + def decompose_from_registers( self, *, context: cirq.DecompositionContext, **quregs: NDArray[cirq.Qid] # type: ignore[type-var] ) -> Iterator[cirq.OP_TREE]: @@ -105,6 +110,19 @@ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.Circ ("@(approx)",) + ("×(x)",) * self.bitsize + ("×(y)",) * self.bitsize ) + def wire_symbol( + self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple() + ) -> 'WireSymbol': + if reg is None: + return TextBox("approx") + if reg.name == 'ctrl': + return Circle() + if reg.name == 'x': + return TextBox("×(x)") + if reg.name == 'y': + return TextBox("×(y)") + raise ValueError(f"Unknown register {reg}.") + def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']: n = self.bitsize # 4 * n: G gates, each wth 1 T and 4 single qubit cliffords diff --git a/qualtran/bloqs/swap_network/swap_with_zero.py b/qualtran/bloqs/swap_network/swap_with_zero.py index a4f7f6f9c..27dd4bb80 100644 --- a/qualtran/bloqs/swap_network/swap_with_zero.py +++ b/qualtran/bloqs/swap_network/swap_with_zero.py @@ -16,16 +16,15 @@ from typing import Dict, Iterable, Set, Tuple, TYPE_CHECKING, Union import attrs -import cirq import numpy as np from numpy.typing import NDArray from qualtran import ( + Bloq, bloq_example, BloqBuilder, BloqDocSpec, BoundedQUInt, - GateWithRegisters, QAny, Register, Signature, @@ -50,7 +49,7 @@ def _to_tuple(x: Union[SymbolicInt, Iterable[SymbolicInt]]) -> Tuple[SymbolicInt @attrs.frozen -class SwapWithZero(GateWithRegisters): +class SwapWithZero(Bloq): r"""Swaps $|\Psi_0\rangle$ with $|\Psi_x\rangle$ if selection register stores index `x`. Implements the unitary @@ -155,11 +154,6 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']: num_swaps = prod(x for x in self.n_target_registers) - 1 return {(self.cswap_n, num_swaps)} - def _circuit_diagram_info_(self, args) -> cirq.CircuitDiagramInfo: - from qualtran.cirq_interop._bloq_to_cirq import _wire_symbol_to_cirq_diagram_info - - return _wire_symbol_to_cirq_diagram_info(self, args) - def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol': if reg is None: return super().wire_symbol(reg, idx) diff --git a/qualtran/bloqs/swap_network/swap_with_zero_test.py b/qualtran/bloqs/swap_network/swap_with_zero_test.py index c5a7c2abc..79605f006 100644 --- a/qualtran/bloqs/swap_network/swap_with_zero_test.py +++ b/qualtran/bloqs/swap_network/swap_with_zero_test.py @@ -74,27 +74,27 @@ def test_swap_with_zero_cirq_gate_diagram(): cirq.testing.assert_has_diagram( cirq.Circuit(gh.operation, cirq.decompose_once(gh.operation)), """ -selection0: ──────@(r⇋0)─────────────────────────────────────── +selection0: ──────@(r⇋0)──────────────────────── │ -selection1: ──────@(r⇋0)───────────────────────────@(approx)─── - │ │ -selection2: ──────@(r⇋0)───@(approx)───@(approx)───┼─────────── - │ │ │ │ -targets[0][0]: ───swap_0───×(x)────────┼───────────×(x)──────── - │ │ │ │ -targets[0][1]: ───swap_0───×(x)────────┼───────────×(x)──────── - │ │ │ │ -targets[1][0]: ───swap_1───×(y)────────┼───────────┼─────────── - │ │ │ │ -targets[1][1]: ───swap_1───×(y)────────┼───────────┼─────────── - │ │ │ -targets[2][0]: ───swap_2───────────────×(x)────────×(y)──────── - │ │ │ -targets[2][1]: ───swap_2───────────────×(x)────────×(y)──────── - │ │ -targets[3][0]: ───swap_3───────────────×(y)──────────────────── - │ │ -targets[3][1]: ───swap_3───────────────×(y)──────────────────── +selection1: ──────@(r⇋0)─────────────────@────── + │ │ +selection2: ──────@(r⇋0)───@──────@──────┼────── + │ │ │ │ +targets[0][0]: ───swap_0───×(x)───┼──────×(x)─── + │ │ │ │ +targets[0][1]: ───swap_0───×(x)───┼──────×(x)─── + │ │ │ │ +targets[1][0]: ───swap_1───×(y)───┼──────┼────── + │ │ │ │ +targets[1][1]: ───swap_1───×(y)───┼──────┼────── + │ │ │ +targets[2][0]: ───swap_2──────────×(x)───×(y)─── + │ │ │ +targets[2][1]: ───swap_2──────────×(x)───×(y)─── + │ │ +targets[3][0]: ───swap_3──────────×(y)────────── + │ │ +targets[3][1]: ───swap_3──────────×(y)────────── """, ) @@ -107,37 +107,38 @@ def test_swap_with_zero_cirq_gate_diagram_multi_dim(): cirq.testing.assert_has_diagram( cirq.Circuit(gh.operation, cirq.decompose_once(gh.operation)), """ - ┌──────────────────┐ -selection0_0: ───────@(r⇋0)────────────────────────────────────────────────────@(approx)─── - │ │ -selection0_1: ───────@(r⇋0)───────────────────────────────────────@(approx)────┼─────────── - │ │ │ -selection1_: ────────@(r⇋0)─────@(approx)───@(approx)────@(approx)┼────────────┼─────────── - │ │ │ │ │ │ -targets[0, 0][0]: ───swap_0_0───×(x)────────┼────────────┼────────×(x)─────────×(x)──────── - │ │ │ │ │ │ -targets[0, 0][1]: ───swap_0_0───×(x)────────┼────────────┼────────×(x)─────────×(x)──────── - │ │ │ │ │ │ -targets[0, 1][0]: ───swap_0_1───×(y)────────┼────────────┼────────┼────────────┼─────────── - │ │ │ │ │ │ -targets[0, 1][1]: ───swap_0_1───×(y)────────┼────────────┼────────┼────────────┼─────────── - │ │ │ │ │ -targets[1, 0][0]: ───swap_1_0───────────────×(x)─────────┼────────×(y)─────────┼─────────── - │ │ │ │ │ -targets[1, 0][1]: ───swap_1_0───────────────×(x)─────────┼────────×(y)─────────┼─────────── - │ │ │ │ -targets[1, 1][0]: ───swap_1_1───────────────×(y)─────────┼─────────────────────┼─────────── - │ │ │ │ -targets[1, 1][1]: ───swap_1_1───────────────×(y)─────────┼─────────────────────┼─────────── - │ │ │ -targets[2, 0][0]: ───swap_2_0────────────────────────────×(x)──────────────────×(y)──────── - │ │ │ -targets[2, 0][1]: ───swap_2_0────────────────────────────×(x)──────────────────×(y)──────── - │ │ -targets[2, 1][0]: ───swap_2_1────────────────────────────×(y)────────────────────────────── - │ │ -targets[2, 1][1]: ───swap_2_1────────────────────────────×(y)────────────────────────────── - └──────────────────┘""", + ┌────────┐ +selection0_0: ───────@(r⇋0)────────────────────────────────@────── + │ │ +selection0_1: ───────@(r⇋0)────────────────────@───────────┼────── + │ │ │ +selection1_: ────────@(r⇋0)─────@──────@───────┼───@───────┼────── + │ │ │ │ │ │ +targets[0, 0][0]: ───swap_0_0───×(x)───┼───────×(x)┼───────×(x)─── + │ │ │ │ │ │ +targets[0, 0][1]: ───swap_0_0───×(x)───┼───────×(x)┼───────×(x)─── + │ │ │ │ │ │ +targets[0, 1][0]: ───swap_0_1───×(y)───┼───────┼───┼───────┼────── + │ │ │ │ │ │ +targets[0, 1][1]: ───swap_0_1───×(y)───┼───────┼───┼───────┼────── + │ │ │ │ │ +targets[1, 0][0]: ───swap_1_0──────────×(x)────×(y)┼───────┼────── + │ │ │ │ │ +targets[1, 0][1]: ───swap_1_0──────────×(x)────×(y)┼───────┼────── + │ │ │ │ +targets[1, 1][0]: ───swap_1_1──────────×(y)────────┼───────┼────── + │ │ │ │ +targets[1, 1][1]: ───swap_1_1──────────×(y)────────┼───────┼────── + │ │ │ +targets[2, 0][0]: ───swap_2_0──────────────────────×(x)────×(y)─── + │ │ │ +targets[2, 0][1]: ───swap_2_0──────────────────────×(x)────×(y)─── + │ │ +targets[2, 1][0]: ───swap_2_1──────────────────────×(y)─────────── + │ │ +targets[2, 1][1]: ───swap_2_1──────────────────────×(y)─────────── + └────────┘ +""", )