Skip to content

Commit 3117a84

Browse files
anurudhpmpharrigan
andauthored
Default Bloq.get_ctrl_system: Use And ladder to reduce multiple controls to single control (#1456)
* default ctrl system: use And ladder to reduce controls to a single control bit * fix tests * test: `XGate().controlled(...)` --------- Co-authored-by: Matthew Harrigan <mpharrigan@google.com>
1 parent 0220df2 commit 3117a84

File tree

5 files changed

+25
-42
lines changed

5 files changed

+25
-42
lines changed

qualtran/_infra/bloq.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,12 @@ def _my_add_controlled(
394394
add_controlled: A function with the signature documented above that the system
395395
can use to automatically wire up the new control registers.
396396
"""
397-
from qualtran import Controlled
397+
from qualtran import Controlled, CtrlSpec
398+
from qualtran.bloqs.mcmt.controlled_via_and import ControlledViaAnd
399+
400+
if ctrl_spec != CtrlSpec():
401+
# reduce controls to a single qubit
402+
return ControlledViaAnd.make_ctrl_system(self, ctrl_spec=ctrl_spec)
398403

399404
return Controlled.make_ctrl_system(self, ctrl_spec=ctrl_spec)
400405

qualtran/_infra/gate_with_registers_test.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,10 @@ def test_gate_with_registers_decompose_from_context_auto_generated():
151151

152152

153153
def test_non_unitary_controlled():
154+
from qualtran.bloqs.mcmt.controlled_via_and import ControlledViaAnd
155+
154156
bloq = BloqWithDecompose()
155-
assert bloq.controlled(control_values=[0]) == Controlled(bloq, CtrlSpec(cvs=0))
157+
assert bloq.controlled(control_values=[0]) == ControlledViaAnd(bloq, CtrlSpec(cvs=0))
156158

157159

158160
@pytest.mark.notebook

qualtran/bloqs/basic_gates/identity_test.py

+1-39
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,14 @@
1515
import numpy as np
1616
import pytest
1717
import sympy
18-
from attrs import frozen
1918

20-
from qualtran import Bloq, BloqBuilder, CtrlSpec, QInt, QUInt, Signature, Soquet, SoquetT
19+
from qualtran import BloqBuilder
2120
from qualtran.bloqs.basic_gates import OneState
2221
from qualtran.bloqs.basic_gates.identity import _identity, _identity_n, _identity_symb, Identity
2322
from qualtran.simulation.classical_sim import (
2423
format_classical_truth_table,
2524
get_classical_truth_table,
2625
)
27-
from qualtran.symbolics import SymbolicInt
2826
from qualtran.testing import execute_notebook
2927

3028

@@ -95,42 +93,6 @@ def test_identity_controlled():
9593
assert Identity(n).controlled() == Identity(n + 1)
9694

9795

98-
@frozen
99-
class TestIdentityDecomposition(Bloq):
100-
"""helper to test Identity.get_ctrl_system"""
101-
102-
bitsize: SymbolicInt
103-
104-
@property
105-
def signature(self) -> 'Signature':
106-
return Signature.build(q=self.bitsize)
107-
108-
def build_composite_bloq(self, bb: 'BloqBuilder', q: Soquet) -> dict[str, 'SoquetT']:
109-
q = bb.add(Identity(self.bitsize), q=q)
110-
q = bb.add(Identity(self.bitsize), q=q)
111-
return {'q': q}
112-
113-
114-
@pytest.mark.parametrize("n", [4, sympy.Symbol("n")])
115-
@pytest.mark.parametrize(
116-
"ctrl_spec",
117-
[
118-
CtrlSpec(cvs=(np.array([1, 0, 1]),)),
119-
CtrlSpec(qdtypes=(QUInt(3), QInt(3)), cvs=(np.array(0b010), np.array(0b001))),
120-
],
121-
)
122-
def test_identity_get_ctrl_system(n: SymbolicInt, ctrl_spec: CtrlSpec):
123-
m = ctrl_spec.num_qubits
124-
125-
bloq = TestIdentityDecomposition(n)
126-
ctrl_bloq = bloq.controlled(ctrl_spec)
127-
128-
_ = ctrl_bloq.decompose_bloq()
129-
130-
_, sigma = ctrl_bloq.call_graph()
131-
assert sigma == {Identity(n + m): 2}
132-
133-
13496
@pytest.mark.notebook
13597
def test_notebook():
13698
execute_notebook('identity')

qualtran/bloqs/basic_gates/x_basis_test.py

+14
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,17 @@ def test_x_truth_table():
9292
0 -> 1
9393
1 -> 0"""
9494
)
95+
96+
97+
def test_controlled_x():
98+
from qualtran import CtrlSpec, QUInt
99+
from qualtran.bloqs.basic_gates import CNOT
100+
from qualtran.bloqs.mcmt import And
101+
102+
def _keep_and(b):
103+
return isinstance(b, And)
104+
105+
n = 8
106+
bloq = XGate().controlled(CtrlSpec(qdtypes=QUInt(n), cvs=1))
107+
_, sigma = bloq.call_graph(keep=_keep_and)
108+
assert sigma == {And(): n - 1, CNOT(): 1, And().adjoint(): n - 1, XGate(): 4 * (n - 1)}

qualtran/bloqs/qsp/generalized_qsp_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def catch_rotations(bloq: Bloq) -> Bloq:
201201

202202
expected_sigma: dict[Bloq, int] = {arbitrary_rotation: degree + 1}
203203
if degree > negative_power:
204-
expected_sigma[Controlled(U, CtrlSpec(cvs=0))] = degree - negative_power
204+
expected_sigma[U.controlled(ctrl_spec=CtrlSpec(cvs=0))] = degree - negative_power
205205
if negative_power > 0:
206206
expected_sigma[Controlled(U.adjoint(), CtrlSpec())] = min(degree, negative_power)
207207
if negative_power > degree:

0 commit comments

Comments
 (0)