Skip to content

Commit 5b5a9ad

Browse files
authored
Support CompositeBloq in QubitCount() (#1379)
1 parent 6a2cb6d commit 5b5a9ad

5 files changed

Lines changed: 45 additions & 6 deletions

File tree

qualtran/_infra/composite_bloq.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,10 @@ def as_composite_bloq(self) -> 'CompositeBloq':
232232
return self
233233

234234
def decompose_bloq(self) -> 'CompositeBloq':
235-
raise DecomposeTypeError("CompositeBloq cannot be decomposed.")
235+
raise ValueError(
236+
"Calling `decompose_bloq` on a CompositeBloq is ill-defined. "
237+
"Consider using the composite bloq directly or using `.flatten()`."
238+
)
236239

237240
def build_call_graph(self, ssa: Optional['SympySymbolAllocator']) -> Set['BloqCountT']:
238241
"""Return the bloq counts by counting up all the subbloqs."""

qualtran/resource_counting/_bloq_counts_test.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from qualtran.bloqs.basic_gates import Hadamard, TGate, Toffoli
1919
from qualtran.bloqs.basic_gates._shims import Measure
2020
from qualtran.bloqs.for_testing.costing import make_example_costing_bloqs
21-
from qualtran.bloqs.mcmt import MultiTargetCNOT
21+
from qualtran.bloqs.mcmt import MultiAnd, MultiTargetCNOT
2222
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
2323
from qualtran.resource_counting import BloqCount, GateCounts, get_cost_value, QECGatesCost
2424

@@ -68,6 +68,12 @@ def test_qec_gates_cost():
6868
assert gc == GateCounts(toffoli=100, t=2 * 2 * 10, clifford=2 * 10)
6969

7070

71+
def test_qec_gates_cost_cbloq():
72+
bloq = MultiAnd(cvs=(1,) * 5)
73+
cbloq = bloq.decompose_bloq()
74+
assert get_cost_value(bloq, QECGatesCost()) == get_cost_value(cbloq, QECGatesCost())
75+
76+
7177
@pytest.mark.parametrize(
7278
['bloq', 'counts'],
7379
[

qualtran/resource_counting/_qubit_counts.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from attrs import frozen
2020

2121
from qualtran import Bloq, Connection, DanglingT, DecomposeNotImplementedError, DecomposeTypeError
22-
from qualtran._infra.composite_bloq import _binst_to_cxns
22+
from qualtran._infra.composite_bloq import _binst_to_cxns, CompositeBloq
2323
from qualtran.symbolics import smax, SymbolicInt
2424

2525
from ._call_graph import get_bloq_callee_counts
@@ -104,6 +104,9 @@ def compute(
104104
# Most accurate:
105105
# Compute the number of qubits ("width") from the bloq's decomposition. We forward
106106
# the `get_callee_cost` function so this can recurse into subbloqs.
107+
if isinstance(bloq, CompositeBloq):
108+
logger.info("Computing %s by the passed-in CompositeBloq", self)
109+
return _cbloq_max_width(bloq._binst_graph, get_callee_cost)
107110
try:
108111
cbloq = bloq.decompose_bloq()
109112
logger.info("Computing %s for %s from its decomposition", self, bloq)

qualtran/resource_counting/_qubit_counts_test.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,14 @@
2525
TestSerialCombo,
2626
)
2727
from qualtran.drawing import show_bloq
28-
from qualtran.resource_counting import get_cost_cache, QubitCount
28+
from qualtran.resource_counting import get_cost_cache, get_cost_value, QubitCount
2929
from qualtran.resource_counting._qubit_counts import _cbloq_max_width
3030
from qualtran.resource_counting.generalizers import ignore_split_join
3131

3232

3333
def test_max_width_interior_alloc_symb():
3434
n = sympy.Symbol('n', positive=True)
3535
bloq = InteriorAlloc(n=n)
36-
show_bloq(bloq.decompose_bloq())
3736

3837
binst_graph = bloq.decompose_bloq()._binst_graph
3938
max_width = _cbloq_max_width(binst_graph)
@@ -43,7 +42,6 @@ def test_max_width_interior_alloc_symb():
4342
def test_max_width_interior_alloc_nums():
4443
n = 10
4544
bloq = InteriorAlloc(n=n)
46-
show_bloq(bloq.decompose_bloq())
4745

4846
binst_graph = bloq.decompose_bloq()._binst_graph
4947
max_width = _cbloq_max_width(binst_graph)
@@ -75,6 +73,14 @@ def test_qubit_count_cost():
7573
}
7674

7775

76+
def test_on_cbloq():
77+
n = sympy.Symbol('n', positive=True, integer=True)
78+
bloq = InteriorAlloc(n=n)
79+
cbloq = bloq.decompose_bloq()
80+
n_qubits = get_cost_value(cbloq, QubitCount())
81+
assert n_qubits == 3 * n
82+
83+
7884
@pytest.mark.notebook
7985
def test_notebook():
8086
qlt_testing.execute_notebook("qubit_counts")

qualtran/resource_counting/qubit_counts.ipynb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
"id": "58f0823f-f76f-4adb-8f2a-a25d1e2ee070",
5353
"metadata": {},
5454
"source": [
55+
"## Example: a bloq with an interior allocation\n",
56+
"\n",
5557
"For illustrative purposes, we use a bloq that has two $n$ bit registers, but allocates an additional $n$ bit register as part of its decomposition. Looking purely at the signature, you would conclude that the bloq uses $2n$ qubits; but by looking at the decomposition we can see that at its maximum circuit width it uses $3n$ qubits. "
5658
]
5759
},
@@ -91,6 +93,25 @@
9193
"costs = query_costs(bloq, [QubitCount()])\n",
9294
"GraphvizCallGraph(g, costs).get_svg()"
9395
]
96+
},
97+
{
98+
"cell_type": "markdown",
99+
"id": "e421621b-cbb4-4603-acab-2b65f8cbf08c",
100+
"metadata": {},
101+
"source": [
102+
"You can call `get_cost_value` on a composite bloq directly."
103+
]
104+
},
105+
{
106+
"cell_type": "code",
107+
"execution_count": null,
108+
"id": "a7666cc8-4023-4c15-a946-acbaae3443d0",
109+
"metadata": {},
110+
"outputs": [],
111+
"source": [
112+
"cbloq = bloq.decompose_bloq()\n",
113+
"get_cost_value(cbloq, QubitCount())"
114+
]
94115
}
95116
],
96117
"metadata": {

0 commit comments

Comments
 (0)