Skip to content

Commit

Permalink
finale
Browse files Browse the repository at this point in the history
  • Loading branch information
mpharrigan committed Apr 30, 2024
1 parent 1d2ba85 commit f4713fb
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 40 deletions.
4 changes: 3 additions & 1 deletion qualtran/_infra/registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,11 @@ def n_qubits(self) -> int:
is taken to be the greater of the number of left or right qubits. A bloq with this
signature uses at least this many qubits.
"""
from qualtran.resource_counting.symbolic_counting_utils import smax

left_size = sum(reg.total_bits() for reg in self.lefts())
right_size = sum(reg.total_bits() for reg in self.rights())
return max(left_size, right_size)
return smax(left_size, right_size)

def __repr__(self):
return f'Signature({repr(self._registers)})'
Expand Down
10 changes: 10 additions & 0 deletions qualtran/_infra/registers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import cirq
import numpy as np
import pytest
import sympy

from qualtran import BoundedQUInt, QAny, QBit, QInt, Register, Side, Signature
from qualtran._infra.gate_with_registers import get_named_qubits
Expand Down Expand Up @@ -196,3 +197,12 @@ def test_dtypes_converter():
r2 = Register("my_reg", QAny(5))
r2 = Register("my_reg", QInt(5))
assert r1 != r2


def test_symbolic_reg():
n = sympy.Symbol('n', positive=True, integer=True)
sig = Signature(
[Register('x', QAny(n), side=Side.LEFT), Register('y', QAny(2 * n), side=Side.RIGHT)]
)

assert sig.n_qubits() == 2 * n
3 changes: 3 additions & 0 deletions qualtran/bloqs/basic_gates/hadamard.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ def short_name(self) -> 'str':
def wire_symbol(self, soq: 'Soquet') -> 'WireSymbol':
return TextBox('H')

def __str__(self):
return 'H'


@bloq_example
def _hadamard() -> Hadamard:
Expand Down
3 changes: 1 addition & 2 deletions qualtran/bloqs/basic_gates/on_each_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ def test_classical_simulation():
h_on_each = OnEach(10, Hadamard())
with pytest.raises(
NotImplementedError,
match=r'.*does not support classical simulation: '
r'Hadamard\(\) is not classically simulable\.',
match=r'.*does not support classical simulation: ' r'H is not classically simulable\.',
):
h_on_each.call_classically(q=0)

Expand Down
4 changes: 2 additions & 2 deletions qualtran/bloqs/basic_gates/t_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ def pretty_name(self) -> str:
return f'T{maybe_dag}'

def __str__(self):
maybe_dag = 'is_adjoint=True' if self.is_adjoint else ''
return f'TGate({maybe_dag})'
maybe_dag = '' if self.is_adjoint else ''
return f'T{maybe_dag}'

def wire_symbol(self, soq: 'Soquet') -> 'WireSymbol':
return TextBox(self.pretty_name())
Expand Down
3 changes: 3 additions & 0 deletions qualtran/bloqs/basic_gates/toffoli.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ def wire_symbol(self, soq: 'Soquet') -> 'WireSymbol':
return ModPlus()
raise ValueError(f'Bad wire symbol soquet: {soq}')

def __str__(self):
return 'Toffoli'


@bloq_example
def _toffoli() -> Toffoli:
Expand Down
42 changes: 41 additions & 1 deletion qualtran/bloqs/chemistry/resource_estimation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@
"from qualtran.drawing.musical_score import get_musical_score_data, draw_musical_score\n",
"msd = get_musical_score_data(block_encoding_bloq.decompose_bloq())\n",
"fig, ax = draw_musical_score(msd)\n",
"plt.tick_params(left=False, right=False, labelleft=False, labelbottom=False, bottom=False)\n",
"fig.set_size_inches(8, 4)"
]
},
Expand Down Expand Up @@ -185,6 +184,47 @@
"print(f'qualtran = {num_toff} vs. ref = 10880, delta = {num_toff - 10880}')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e79d3c99-cd23-4333-a177-6d6ab3dca72a",
"metadata": {},
"outputs": [],
"source": [
"# qualtran = 26749.0 vs. ref = 10880, delta = 15869.0"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c61a4b30-b875-4414-b198-e08774df0c4a",
"metadata": {},
"outputs": [],
"source": [
"from qualtran.resource_counting import BloqCount, query_costs, get_cost_value, QECGatesCost\n",
"from qualtran.resource_counting.generalizers import ignore_alloc_free, ignore_split_join, generalize_rotation_angle"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a126c934-1528-425a-aa4d-93a4bb880236",
"metadata": {},
"outputs": [],
"source": [
"get_cost_value(block_encoding_bloq, BloqCount.for_gateset(\"t+tof+cswap\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e68450ff-d582-400f-abd1-f3d24dd43979",
"metadata": {},
"outputs": [],
"source": [
"46976/4 + 30480/4 + 7105 + 280"
]
},
{
"cell_type": "markdown",
"id": "dbd1615f",
Expand Down
12 changes: 10 additions & 2 deletions qualtran/bloqs/data_loading/qrom.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"""Quantum read-only memory."""

from functools import cached_property
from typing import Callable, Dict, Iterable, Sequence, Set, Tuple
from typing import Any, Callable, Dict, Iterable, Sequence, Set, Tuple, Union

import attrs
import cirq
Expand All @@ -28,7 +28,7 @@
from qualtran.bloqs.mcmt.and_bloq import And, MultiAnd
from qualtran.bloqs.multiplexers.unary_iteration_bloq import UnaryIterationGate
from qualtran.drawing import Circle, TextBox, WireSymbol
from qualtran.resource_counting import BloqCountT
from qualtran.resource_counting import BloqCountT, CostKey, QubitCount
from qualtran.simulation.classical_sim import ClassicalValT


Expand Down Expand Up @@ -203,6 +203,11 @@ def on_classical_vals(self, **vals: 'ClassicalValT') -> Dict[str, 'ClassicalValT
targets = {k: v ^ vals[k] for k, v in targets.items()}
return controls | selections | targets

def my_static_costs(self, cost_key: 'CostKey') -> Union[Any, NotImplemented]:
if cost_key == QubitCount():
return self.num_controls + 2 * sum(self.selection_bitsizes) + sum(self.target_bitsizes)
return super().my_static_costs(cost_key)

def _circuit_diagram_info_(self, _) -> cirq.CircuitDiagramInfo:
wire_symbols = ["@"] * self.num_controls
wire_symbols += ["In"] * total_bits(self.selection_registers)
Expand Down Expand Up @@ -240,6 +245,9 @@ def nth_operation_callgraph(self, **kwargs: int) -> Set['BloqCountT']:
selection_idx = tuple(kwargs[reg.name] for reg in self.selection_registers)
return {(CNOT(), sum(int(d[selection_idx]).bit_count() for d in self.data))}

def __str__(self):
return 'QROM'


@bloq_example
def _qrom_small() -> QROM:
Expand Down
3 changes: 3 additions & 0 deletions qualtran/bloqs/data_loading/select_swap_qrom.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,6 @@ def short_name(self) -> str:

def _value_equality_values_(self):
return self.block_size, self._target_bitsizes, self.data

def __str__(self):
return 'SelectSwapQROM'
10 changes: 5 additions & 5 deletions qualtran/bloqs/for_testing/costing_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def test_costing_bloqs():
== """\
Algo -- 1 -> Func1
Algo -- 1 -> Func2
Func1 -- 10 -> Hadamard()
Func1 -- 10 -> TGate()
Func1 -- 10 -> TGate(is_adjoint=True)
Func2 -- 100 -> Toffoli()
Toffoli() -- 4 -> TGate()"""
Func1 -- 10 -> H
Func1 -- 10 -> T
Func1 -- 10 -> T†
Func2 -- 100 -> Toffoli
Toffoli -- 4 -> T"""
)
7 changes: 7 additions & 0 deletions qualtran/bloqs/mcmt/and_bloq.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ def _t_complexity_(self) -> TComplexity:
else:
return TComplexity(t=4 * 1, clifford=9 + 2 * pre_post_cliffords)

def __str__(self):
dag = '†' if self.uncompute else ''

if self.cv1 == 0 or self.cv2 == 0:
return f'And{dag}_{self.cv1}{self.cv2}'
return f'And{dag}'


@bloq_example(
generalizer=[cirq_to_bloqs, ignore_cliffords, ignore_alloc_free, generalize_rotation_angle]
Expand Down
10 changes: 9 additions & 1 deletion qualtran/bloqs/multiplexers/selected_majorana_fermion.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

from functools import cached_property
from typing import Sequence, Tuple, Union
from typing import Any, Sequence, Tuple, Union

import attrs
import cirq
Expand All @@ -24,6 +24,7 @@
from qualtran._infra.data_types import BoundedQUInt
from qualtran._infra.gate_with_registers import total_bits
from qualtran.bloqs.multiplexers.unary_iteration_bloq import UnaryIterationGate
from qualtran.resource_counting import CostKey


@attrs.frozen
Expand Down Expand Up @@ -120,3 +121,10 @@ def nth_operation( # type: ignore[override]
yield cirq.CNOT(control, *accumulator)
yield self.target_gate(target[target_idx]).controlled_by(control)
yield cirq.CZ(*accumulator, target[target_idx])

def my_static_costs(self, cost_key: 'CostKey') -> Union[Any, NotImplemented]:
from qualtran.resource_counting import QubitCount

if isinstance(cost_key, QubitCount):
return self.signature.n_qubits()
return super().my_static_costs(cost_key)
8 changes: 4 additions & 4 deletions qualtran/drawing/bloq_counts_graph_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def test_format_counts_sigma():
== """\
#### Counts totals:
- `ArbitraryClifford(n=2)`: 45
- `TGate()`: 20"""
- `T`: 20"""
)


Expand All @@ -46,10 +46,10 @@ def test_format_counts_graph_markdown():
ret
== """\
- `MultiAnd(cvs=(1, 1, 1, 1, 1, 1))`
- `And(cv1=1, cv2=1, uncompute=False)`: $\\displaystyle 5$
- `And(cv1=1, cv2=1, uncompute=False)`
- `And`: $\\displaystyle 5$
- `And`
- `ArbitraryClifford(n=2)`: $\\displaystyle 9$
- `TGate()`: $\\displaystyle 4$
- `T`: $\\displaystyle 4$
"""
)

Expand Down
2 changes: 1 addition & 1 deletion qualtran/drawing/flame_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def _pretty_name(bloq: Bloq) -> str:

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


Expand Down
29 changes: 8 additions & 21 deletions qualtran/resource_counting/_call_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,27 +168,14 @@ def _build_call_graph(
g.add_edge(bloq, callee, n=n)


def _compute_sigma(root_bloq: Bloq, g: nx.DiGraph) -> Dict[Bloq, Union[int, sympy.Expr]]:
"""Iterate over nodes to sum up the counts of leaf bloqs."""
bloq_sigmas: Dict[Bloq, Dict[Bloq, Union[int, sympy.Expr]]] = defaultdict(
lambda: defaultdict(lambda: 0)
)
for bloq in reversed(list(nx.topological_sort(g))):
callees = list(g.successors(bloq))
sigma = bloq_sigmas[bloq]
if not callees:
# 1. `bloq` is a leaf node. Its count is one of itself.
sigma[bloq] = 1
continue

for callee in callees:
callee_sigma = bloq_sigmas[callee]
# 2. Otherwise, sigma of the caller is sum(n * sigma of callee) for all the callees.
n = g.edges[bloq, callee]['n']
for k in callee_sigma.keys():
sigma[k] += callee_sigma[k] * n
def _compute_sigma(
root_bloq: Bloq, g: nx.DiGraph, generalizer: 'GeneralizerT'
) -> Dict[Bloq, Union[int, sympy.Expr]]:
"""Shim for compatibility with old 'sigma' that used the call graph to count leaf bloqs."""
from qualtran.resource_counting import BloqCount, get_cost_value

return dict(bloq_sigmas[root_bloq])
leaf_counts = BloqCount.for_call_graph_leaf_bloqs(g)
return get_cost_value(root_bloq, leaf_counts, generalizer=generalizer)


def get_bloq_call_graph(
Expand Down Expand Up @@ -236,7 +223,7 @@ def get_bloq_call_graph(
if bloq is None:
raise ValueError("You can't generalize away the root bloq.")
_build_call_graph(bloq, generalizer, ssa, keep, max_depth, g=g, depth=0)
sigma = _compute_sigma(bloq, g)
sigma = _compute_sigma(bloq, g, generalizer)
return g, sigma


Expand Down
Loading

0 comments on commit f4713fb

Please sign in to comment.