Skip to content

Commit d82ba06

Browse files
committed
finale
1 parent 234c020 commit d82ba06

16 files changed

+306
-37
lines changed

qualtran/_infra/registers.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,11 @@ def n_qubits(self) -> int:
203203
is taken to be the greater of the number of left or right qubits. A bloq with this
204204
signature uses at least this many qubits.
205205
"""
206+
from qualtran.resource_counting.symbolic_counting_utils import smax
207+
206208
left_size = sum(reg.total_bits() for reg in self.lefts())
207209
right_size = sum(reg.total_bits() for reg in self.rights())
208-
return max(left_size, right_size)
210+
return smax(left_size, right_size)
209211

210212
def __repr__(self):
211213
return f'Signature({repr(self._registers)})'

qualtran/_infra/registers_test.py

+9
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,12 @@ def test_is_symbolic():
205205
assert is_symbolic(r)
206206
r = Register("my_reg", QAny(2), shape=sympy.symbols("x y"))
207207
assert is_symbolic(r)
208+
209+
210+
def test_symbolic_reg():
211+
n = sympy.Symbol('n', positive=True, integer=True)
212+
sig = Signature(
213+
[Register('x', QAny(n), side=Side.LEFT), Register('y', QAny(2 * n), side=Side.RIGHT)]
214+
)
215+
216+
assert sig.n_qubits() == 2 * n

qualtran/bloqs/basic_gates/hadamard.py

+3
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
9393
return Text('')
9494
return TextBox('H')
9595

96+
def __str__(self):
97+
return 'H'
98+
9699

97100
@bloq_example
98101
def _hadamard() -> Hadamard:

qualtran/bloqs/basic_gates/on_each_test.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ def test_classical_simulation():
4242
h_on_each = OnEach(10, Hadamard())
4343
with pytest.raises(
4444
NotImplementedError,
45-
match=r'.*does not support classical simulation: '
46-
r'Hadamard\(\) is not classically simulable\.',
45+
match=r'.*does not support classical simulation: ' r'H is not classically simulable\.',
4746
):
4847
h_on_each.call_classically(q=0)
4948

qualtran/bloqs/basic_gates/t_gate.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ def pretty_name(self) -> str:
108108
return f'T{maybe_dag}'
109109

110110
def __str__(self):
111-
maybe_dag = 'is_adjoint=True' if self.is_adjoint else ''
112-
return f'TGate({maybe_dag})'
111+
maybe_dag = '' if self.is_adjoint else ''
112+
return f'T{maybe_dag}'
113113

114114
def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol':
115115
if reg is None:

qualtran/bloqs/basic_gates/toffoli.py

+3
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
125125
return ModPlus()
126126
raise ValueError(f'Unknown wire symbol register name: {reg.name}')
127127

128+
def __str__(self):
129+
return 'Toffoli'
130+
128131

129132
@bloq_example
130133
def _toffoli() -> Toffoli:

qualtran/bloqs/chemistry/resource_estimation.ipynb

+41-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@
133133
"from qualtran.drawing.musical_score import get_musical_score_data, draw_musical_score\n",
134134
"msd = get_musical_score_data(block_encoding_bloq.decompose_bloq())\n",
135135
"fig, ax = draw_musical_score(msd)\n",
136-
"plt.tick_params(left=False, right=False, labelleft=False, labelbottom=False, bottom=False)\n",
137136
"fig.set_size_inches(8, 4)"
138137
]
139138
},
@@ -185,6 +184,47 @@
185184
"print(f'qualtran = {num_toff} vs. ref = 10880, delta = {num_toff - 10880}')"
186185
]
187186
},
187+
{
188+
"cell_type": "code",
189+
"execution_count": null,
190+
"id": "e79d3c99-cd23-4333-a177-6d6ab3dca72a",
191+
"metadata": {},
192+
"outputs": [],
193+
"source": [
194+
"# qualtran = 26749.0 vs. ref = 10880, delta = 15869.0"
195+
]
196+
},
197+
{
198+
"cell_type": "code",
199+
"execution_count": null,
200+
"id": "c61a4b30-b875-4414-b198-e08774df0c4a",
201+
"metadata": {},
202+
"outputs": [],
203+
"source": [
204+
"from qualtran.resource_counting import BloqCount, query_costs, get_cost_value, QECGatesCost\n",
205+
"from qualtran.resource_counting.generalizers import ignore_alloc_free, ignore_split_join, generalize_rotation_angle"
206+
]
207+
},
208+
{
209+
"cell_type": "code",
210+
"execution_count": null,
211+
"id": "a126c934-1528-425a-aa4d-93a4bb880236",
212+
"metadata": {},
213+
"outputs": [],
214+
"source": [
215+
"get_cost_value(block_encoding_bloq, BloqCount.for_gateset(\"t+tof+cswap\"))"
216+
]
217+
},
218+
{
219+
"cell_type": "code",
220+
"execution_count": null,
221+
"id": "e68450ff-d582-400f-abd1-f3d24dd43979",
222+
"metadata": {},
223+
"outputs": [],
224+
"source": [
225+
"46976/4 + 30480/4 + 7105 + 280"
226+
]
227+
},
188228
{
189229
"cell_type": "markdown",
190230
"id": "dbd1615f",

qualtran/bloqs/data_loading/qrom.py

+8
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,11 @@ def on_classical_vals(self, **vals: 'ClassicalValT') -> Dict[str, 'ClassicalValT
327327
targets = {k: v ^ vals[k] for k, v in targets.items()}
328328
return controls | selections | targets
329329

330+
def my_static_costs(self, cost_key: 'CostKey') -> Union[Any, NotImplemented]:
331+
if cost_key == QubitCount():
332+
return self.num_controls + 2 * sum(self.selection_bitsizes) + sum(self.target_bitsizes)
333+
return super().my_static_costs(cost_key)
334+
330335
def _circuit_diagram_info_(self, args) -> cirq.CircuitDiagramInfo:
331336
from qualtran.cirq_interop._bloq_to_cirq import _wire_symbol_to_cirq_diagram_info
332337

@@ -374,6 +379,9 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
374379
n_cnot = prod(*self.target_bitsizes, *self.data_shape)
375380
return {(And(), n_and), (And().adjoint(), n_and), (CNOT(), n_cnot)}
376381

382+
def __str__(self):
383+
return 'QROM'
384+
377385

378386
@bloq_example
379387
def _qrom_small() -> QROM:

qualtran/bloqs/data_loading/select_swap_qrom.py

+3
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,6 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
259259

260260
def _value_equality_values_(self):
261261
return self.block_size, self._target_bitsizes, self.data
262+
263+
def __str__(self):
264+
return 'SelectSwapQROM'

qualtran/bloqs/for_testing/costing_test.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ def test_costing_bloqs():
2424
== """\
2525
Algo -- 1 -> Func1
2626
Algo -- 1 -> Func2
27-
Func1 -- 10 -> Hadamard()
28-
Func1 -- 10 -> TGate()
29-
Func1 -- 10 -> TGate(is_adjoint=True)
30-
Func2 -- 100 -> Toffoli()
31-
Toffoli() -- 4 -> TGate()"""
27+
Func1 -- 10 -> H
28+
Func1 -- 10 -> T
29+
Func1 -- 10 -> T†
30+
Func2 -- 100 -> Toffoli
31+
Toffoli -- 4 -> T"""
3232
)

qualtran/bloqs/mcmt/and_bloq.py

+7
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ def _t_complexity_(self) -> TComplexity:
235235
else:
236236
return TComplexity(t=4 * 1, clifford=9 + 2 * pre_post_cliffords)
237237

238+
def __str__(self):
239+
dag = '†' if self.uncompute else ''
240+
241+
if self.cv1 == 0 or self.cv2 == 0:
242+
return f'And{dag}_{self.cv1}{self.cv2}'
243+
return f'And{dag}'
244+
238245

239246
@bloq_example(
240247
generalizer=[cirq_to_bloqs, ignore_cliffords, ignore_alloc_free, generalize_rotation_angle]

qualtran/bloqs/multiplexers/selected_majorana_fermion.py

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from qualtran._infra.data_types import BoundedQUInt
2626
from qualtran._infra.gate_with_registers import total_bits
2727
from qualtran.bloqs.multiplexers.unary_iteration_bloq import UnaryIterationGate
28+
from qualtran.resource_counting import CostKey
2829

2930

3031
@attrs.frozen
@@ -134,3 +135,10 @@ def nth_operation( # type: ignore[override]
134135
yield cirq.CNOT(control, *accumulator)
135136
yield self.target_gate(target[target_idx]).controlled_by(control)
136137
yield cirq.CZ(*accumulator, target[target_idx])
138+
139+
def my_static_costs(self, cost_key: 'CostKey') -> Union[Any, NotImplemented]:
140+
from qualtran.resource_counting import QubitCount
141+
142+
if isinstance(cost_key, QubitCount):
143+
return self.signature.n_qubits()
144+
return super().my_static_costs(cost_key)

qualtran/drawing/bloq_counts_graph_test.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_format_counts_sigma():
3535
== """\
3636
#### Counts totals:
3737
- `ArbitraryClifford(n=2)`: 45
38-
- `TGate()`: 20"""
38+
- `T`: 20"""
3939
)
4040

4141

@@ -46,10 +46,10 @@ def test_format_counts_graph_markdown():
4646
ret
4747
== """\
4848
- `MultiAnd(cvs=(1, 1, 1, 1, 1, 1))`
49-
- `And(cv1=1, cv2=1, uncompute=False)`: $\\displaystyle 5$
50-
- `And(cv1=1, cv2=1, uncompute=False)`
49+
- `And`: $\\displaystyle 5$
50+
- `And`
5151
- `ArbitraryClifford(n=2)`: $\\displaystyle 9$
52-
- `TGate()`: $\\displaystyle 4$
52+
- `T`: $\\displaystyle 4$
5353
"""
5454
)
5555

qualtran/drawing/flame_graph.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def _pretty_name(bloq: Bloq) -> str:
5858

5959
@functools.lru_cache(maxsize=1024)
6060
def _t_counts_for_bloq(bloq: Bloq, graph: nx.DiGraph) -> Union[int, sympy.Expr]:
61-
sigma = _compute_sigma(bloq, graph)
61+
sigma = _compute_sigma(bloq, graph, generalizer=lambda b: b)
6262
return t_counts_from_sigma(sigma)
6363

6464

qualtran/resource_counting/_call_graph.py

+8-21
Original file line numberDiff line numberDiff line change
@@ -171,27 +171,14 @@ def _build_call_graph(
171171
g.add_edge(bloq, callee, n=n)
172172

173173

174-
def _compute_sigma(root_bloq: Bloq, g: nx.DiGraph) -> Dict[Bloq, Union[int, sympy.Expr]]:
175-
"""Iterate over nodes to sum up the counts of leaf bloqs."""
176-
bloq_sigmas: Dict[Bloq, Dict[Bloq, Union[int, sympy.Expr]]] = defaultdict(
177-
lambda: defaultdict(lambda: 0)
178-
)
179-
for bloq in reversed(list(nx.topological_sort(g))):
180-
callees = list(g.successors(bloq))
181-
sigma = bloq_sigmas[bloq]
182-
if not callees:
183-
# 1. `bloq` is a leaf node. Its count is one of itself.
184-
sigma[bloq] = 1
185-
continue
186-
187-
for callee in callees:
188-
callee_sigma = bloq_sigmas[callee]
189-
# 2. Otherwise, sigma of the caller is sum(n * sigma of callee) for all the callees.
190-
n = g.edges[bloq, callee]['n']
191-
for k in callee_sigma.keys():
192-
sigma[k] += callee_sigma[k] * n
174+
def _compute_sigma(
175+
root_bloq: Bloq, g: nx.DiGraph, generalizer: 'GeneralizerT'
176+
) -> Dict[Bloq, Union[int, sympy.Expr]]:
177+
"""Shim for compatibility with old 'sigma' that used the call graph to count leaf bloqs."""
178+
from qualtran.resource_counting import BloqCount, get_cost_value
193179

194-
return dict(bloq_sigmas[root_bloq])
180+
leaf_counts = BloqCount.for_call_graph_leaf_bloqs(g)
181+
return get_cost_value(root_bloq, leaf_counts, generalizer=generalizer)
195182

196183

197184
def get_bloq_call_graph(
@@ -239,7 +226,7 @@ def get_bloq_call_graph(
239226
if bloq is None:
240227
raise ValueError("You can't generalize away the root bloq.")
241228
_build_call_graph(bloq, generalizer, ssa, keep, max_depth, g=g, depth=0)
242-
sigma = _compute_sigma(bloq, g)
229+
sigma = _compute_sigma(bloq, g, generalizer)
243230
return g, sigma
244231

245232

0 commit comments

Comments
 (0)