Skip to content
Closed
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
101 changes: 101 additions & 0 deletions cirq_qubitization/bloq_algos/controlled_swap_bloq.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from functools import cached_property
from typing import Dict

import numpy as np
from attrs import frozen
from numpy.typing import NDArray

from cirq_qubitization import TComplexity
from cirq_qubitization.quantum_graph.bloq import Bloq
from cirq_qubitization.quantum_graph.composite_bloq import CompositeBloq, Soquet, SoquetT
from cirq_qubitization.quantum_graph.fancy_registers import FancyRegister, FancyRegisters


@frozen
class CSWAP(Bloq):
"""A controlled swap between two-qubits

Args:
cv1: Whether the control bit is a positive (1) control.
Alternatively, control bit can be negatively (0) controlled.

Registers:
- ctrl: A two-bit control register.
- x: first bit to swap
- y: second bit to swap
"""

cv1: int = 1

@cached_property
def registers(self) -> FancyRegisters:
return FancyRegisters(
[
FancyRegister('ctrl', 1, wireshape=(1,)),
FancyRegister('x', 1, wireshape=(1,)),
FancyRegister('y', 1, wireshape=(1,)),
]
)

def t_complexity(self) -> 'TComplexity':
"""The `TComplexity` for this bloq.

C-swap is decomposed into two CNOT + 1 Toffoli.
Each Toffoli is 7 T-gates, 8 Cliffords, and 0 rotations
"""
num_toffoli = 1
return TComplexity(t=num_toffoli * 7, clifford=2 + 8 * num_toffoli, rotations=0)


@frozen
class CMultiSWAP(Bloq):
"""A controlled n-bit swap between two registers

Args:
cv1: Whether the control bit is a positive (1) control.
Alternatively, control bit can be negatively (0) controlled.
reg_length: Length of the registers

Registers:
- ctrl: A two-bit control register.
- reg_x: The first register of size n-bits
- reg_y: The second register of size n-bits
"""

reg_length: int = None
cv1: int = 1

@cached_property
def registers(self) -> FancyRegisters:
return FancyRegisters(
[
FancyRegister('ctrl', 1, wireshape=(1,)),
FancyRegister('reg_x', self.reg_length, wireshape=(1,)),
FancyRegister('reg_y', self.reg_length, wireshape=(1,)),
Comment on lines +72 to +74
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wireshape=(1,) is equivalent to "list of length 1", which can have a use (usually when writing generic code that works for a list of any size) but is probably inappropriate here. wireshape=tuple() (which is the default argument, so you can just not put it) is analogous to "the item itself -- not in a list".

]
)

def pretty_name(self) -> str:
return "CSWAP"

def build_composite_bloq(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you tried actually decomposing the bloq? That's when it will check the code to see if it results in a well-formed composite bloq.

bloq = CMultiSWAP(...)
cbloq = bloq.decompose_bloq()

from cirq_qubitization.jupyter_tools import show_bloq
show_bloq(cbloq)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't yet..but I will tomorrow!

self, bb: 'CompositeBloqBuilder', *, cntrl_and_targets: NDArray[Soquet]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arguments should match the registers, so you should have three arguments (following the bb and *) named ctrl, reg_x, and reg_y

) -> Dict[str, 'SoquetT']:
"""Decomposes multi-cswap `CnSWAP` in-terms of an `CSWAP`"""
ctrl = (cntrl_and_targets[0],)
reg_x = cntrl_and_targets[1 : self.reg_length + 1]
reg_y = cntrl_and_targets[self.reg_length + 1 :]
returned_x = []
returned_y = []
for n_idx in range(self.reg_length):
# overwrite control with same control
ctrl, out_reg_x, out_reg_y = bb.add(
CSWAP(cv1=self.cv1), ctrl=ctrl, x=reg_x[n_idx], y=reg_y[n_idx]
)
returned_x.append(out_reg_x)
returned_y.append(out_reg_y)
Comment on lines +95 to +96
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this style is good for making it clear that the output quantum variables are distinct from the input ones. You can be more concise by just overwriting the original array values

ctrl, reg_x[n_idx], reg_y[n_idx] = bb.add(...)

return {
'ctrl': np.asarray([ctrl]),
'reg_x': np.asarray(returned_x),
'reg_y': np.asarray(returned_y),
}