Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GateWithRegisters] Port swap_network gates to bloqs #961

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion qualtran/_infra/gate_with_registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
24 changes: 21 additions & 3 deletions qualtran/bloqs/swap_network/cswap_approx.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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$
Expand Down Expand Up @@ -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]:
Expand Down Expand Up @@ -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
Expand Down
10 changes: 2 additions & 8 deletions qualtran/bloqs/swap_network/swap_with_zero.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
103 changes: 52 additions & 51 deletions qualtran/bloqs/swap_network/swap_with_zero_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)──────────
""",
)

Expand All @@ -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)───────────
└────────┘
""",
)


Expand Down
Loading