Skip to content

Commit

Permalink
Default Bloq.get_ctrl_system: Use And ladder to reduce multiple c…
Browse files Browse the repository at this point in the history
…ontrols 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 <[email protected]>
  • Loading branch information
anurudhp and mpharrigan authored Oct 17, 2024
1 parent 0220df2 commit 3117a84
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 42 deletions.
7 changes: 6 additions & 1 deletion qualtran/_infra/bloq.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,12 @@ def _my_add_controlled(
add_controlled: A function with the signature documented above that the system
can use to automatically wire up the new control registers.
"""
from qualtran import Controlled
from qualtran import Controlled, CtrlSpec
from qualtran.bloqs.mcmt.controlled_via_and import ControlledViaAnd

if ctrl_spec != CtrlSpec():
# reduce controls to a single qubit
return ControlledViaAnd.make_ctrl_system(self, ctrl_spec=ctrl_spec)

return Controlled.make_ctrl_system(self, ctrl_spec=ctrl_spec)

Expand Down
4 changes: 3 additions & 1 deletion qualtran/_infra/gate_with_registers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,10 @@ def test_gate_with_registers_decompose_from_context_auto_generated():


def test_non_unitary_controlled():
from qualtran.bloqs.mcmt.controlled_via_and import ControlledViaAnd

bloq = BloqWithDecompose()
assert bloq.controlled(control_values=[0]) == Controlled(bloq, CtrlSpec(cvs=0))
assert bloq.controlled(control_values=[0]) == ControlledViaAnd(bloq, CtrlSpec(cvs=0))


@pytest.mark.notebook
Expand Down
40 changes: 1 addition & 39 deletions qualtran/bloqs/basic_gates/identity_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@
import numpy as np
import pytest
import sympy
from attrs import frozen

from qualtran import Bloq, BloqBuilder, CtrlSpec, QInt, QUInt, Signature, Soquet, SoquetT
from qualtran import BloqBuilder
from qualtran.bloqs.basic_gates import OneState
from qualtran.bloqs.basic_gates.identity import _identity, _identity_n, _identity_symb, Identity
from qualtran.simulation.classical_sim import (
format_classical_truth_table,
get_classical_truth_table,
)
from qualtran.symbolics import SymbolicInt
from qualtran.testing import execute_notebook


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


@frozen
class TestIdentityDecomposition(Bloq):
"""helper to test Identity.get_ctrl_system"""

bitsize: SymbolicInt

@property
def signature(self) -> 'Signature':
return Signature.build(q=self.bitsize)

def build_composite_bloq(self, bb: 'BloqBuilder', q: Soquet) -> dict[str, 'SoquetT']:
q = bb.add(Identity(self.bitsize), q=q)
q = bb.add(Identity(self.bitsize), q=q)
return {'q': q}


@pytest.mark.parametrize("n", [4, sympy.Symbol("n")])
@pytest.mark.parametrize(
"ctrl_spec",
[
CtrlSpec(cvs=(np.array([1, 0, 1]),)),
CtrlSpec(qdtypes=(QUInt(3), QInt(3)), cvs=(np.array(0b010), np.array(0b001))),
],
)
def test_identity_get_ctrl_system(n: SymbolicInt, ctrl_spec: CtrlSpec):
m = ctrl_spec.num_qubits

bloq = TestIdentityDecomposition(n)
ctrl_bloq = bloq.controlled(ctrl_spec)

_ = ctrl_bloq.decompose_bloq()

_, sigma = ctrl_bloq.call_graph()
assert sigma == {Identity(n + m): 2}


@pytest.mark.notebook
def test_notebook():
execute_notebook('identity')
14 changes: 14 additions & 0 deletions qualtran/bloqs/basic_gates/x_basis_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,17 @@ def test_x_truth_table():
0 -> 1
1 -> 0"""
)


def test_controlled_x():
from qualtran import CtrlSpec, QUInt
from qualtran.bloqs.basic_gates import CNOT
from qualtran.bloqs.mcmt import And

def _keep_and(b):
return isinstance(b, And)

n = 8
bloq = XGate().controlled(CtrlSpec(qdtypes=QUInt(n), cvs=1))
_, sigma = bloq.call_graph(keep=_keep_and)
assert sigma == {And(): n - 1, CNOT(): 1, And().adjoint(): n - 1, XGate(): 4 * (n - 1)}
2 changes: 1 addition & 1 deletion qualtran/bloqs/qsp/generalized_qsp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def catch_rotations(bloq: Bloq) -> Bloq:

expected_sigma: dict[Bloq, int] = {arbitrary_rotation: degree + 1}
if degree > negative_power:
expected_sigma[Controlled(U, CtrlSpec(cvs=0))] = degree - negative_power
expected_sigma[U.controlled(ctrl_spec=CtrlSpec(cvs=0))] = degree - negative_power
if negative_power > 0:
expected_sigma[Controlled(U.adjoint(), CtrlSpec())] = min(degree, negative_power)
if negative_power > degree:
Expand Down

0 comments on commit 3117a84

Please sign in to comment.