Skip to content

Commit bf77986

Browse files
authored
Override ctrl system for Toffoli (#1552)
1 parent 841acad commit bf77986

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

qualtran/bloqs/basic_gates/toffoli.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414
import itertools
1515
from functools import cached_property
16-
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING, Union
16+
from typing import cast, Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
1717

1818
import numpy as np
1919
from attrs import frozen
@@ -25,6 +25,7 @@
2525
BloqDocSpec,
2626
CompositeBloq,
2727
Connection,
28+
CtrlSpec,
2829
DecomposeTypeError,
2930
QBit,
3031
Register,
@@ -35,6 +36,7 @@
3536
import cirq
3637
import quimb.tensor as qtn
3738

39+
from qualtran import AddControlledT, BloqBuilder, SoquetT
3840
from qualtran.cirq_interop import CirqQuregT
3941
from qualtran.drawing import WireSymbol
4042
from qualtran.simulation.classical_sim import ClassicalValT
@@ -127,6 +129,29 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
127129
return ModPlus()
128130
raise ValueError(f'Unknown wire symbol register name: {reg.name}')
129131

132+
def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']:
133+
from qualtran.bloqs.basic_gates import CNOT
134+
from qualtran.bloqs.mcmt import ControlledViaAnd
135+
136+
if ctrl_spec != CtrlSpec():
137+
return super().get_ctrl_system(ctrl_spec)
138+
139+
cc_cnot = ControlledViaAnd(CNOT(), CtrlSpec(cvs=[1, 1]))
140+
141+
def add_controlled(
142+
bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: dict[str, 'SoquetT']
143+
) -> tuple[Iterable['SoquetT'], Iterable['SoquetT']]:
144+
(new_ctrl,) = ctrl_soqs
145+
ctrl0, ctrl1 = cast(NDArray, in_soqs.pop('ctrl'))
146+
147+
(new_ctrl, ctrl0), ctrl1, target = bb.add(
148+
cc_cnot, ctrl2=np.array([new_ctrl, ctrl0]), ctrl=ctrl1, target=in_soqs.pop('target')
149+
)
150+
151+
return [new_ctrl], [ctrl0, ctrl1, target]
152+
153+
return cc_cnot, add_controlled
154+
130155

131156
@bloq_example
132157
def _toffoli() -> Toffoli:

qualtran/bloqs/basic_gates/toffoli_test.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
import cirq
1717
import numpy as np
1818

19-
from qualtran import BloqBuilder
19+
from qualtran import BloqBuilder, CtrlSpec
2020
from qualtran.bloqs.basic_gates import Toffoli, ZeroState
2121
from qualtran.bloqs.basic_gates.toffoli import _toffoli
22+
from qualtran.bloqs.mcmt import And
2223
from qualtran.drawing.musical_score import Circle, ModPlus
24+
from qualtran.resource_counting import GateCounts, get_cost_value, QECGatesCost
2325
from qualtran.testing import assert_wire_symbols_match_expected
2426

2527

@@ -85,3 +87,18 @@ def test_toffoli_tensors():
8587
unitary = tof.tensor_contract()
8688
cirq_unitary = cirq.unitary(cirq.TOFFOLI)
8789
np.testing.assert_allclose(cirq_unitary, unitary)
90+
91+
92+
def test_ctrl_toffoli_cost():
93+
ctrl_tof = Toffoli().controlled()
94+
95+
_, sigma = ctrl_tof.call_graph()
96+
assert sigma == {Toffoli(): 1, And(): 1, And().adjoint(): 1}
97+
98+
gc = get_cost_value(ctrl_tof, QECGatesCost())
99+
assert gc == GateCounts(and_bloq=1, toffoli=1, clifford=1, measurement=1)
100+
101+
cc_tof = Toffoli().controlled(CtrlSpec(cvs=[1, 1]))
102+
103+
_, sigma = cc_tof.call_graph()
104+
assert sigma == {Toffoli(): 1, And(): 2, And().adjoint(): 2}

0 commit comments

Comments
 (0)