Skip to content

Costs #899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed

Costs #899

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion qualtran/_infra/registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,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
9 changes: 9 additions & 0 deletions qualtran/_infra/registers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,12 @@ def test_is_symbolic():
assert is_symbolic(r)
r = Register("my_reg", QAny(2), shape=sympy.symbols("x y"))
assert is_symbolic(r)


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 @@ -93,6 +93,9 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
return Text('')
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, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol':
if reg is None:
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 @@ -125,6 +125,9 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -
return ModPlus()
raise ValueError(f'Unknown wire symbol register name: {reg.name}')

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
8 changes: 8 additions & 0 deletions qualtran/bloqs/data_loading/qrom.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,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, args) -> cirq.CircuitDiagramInfo:
from qualtran.cirq_interop._bloq_to_cirq import _wire_symbol_to_cirq_diagram_info

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

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 @@ -259,3 +259,6 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -

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 @@ -235,6 +235,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
8 changes: 8 additions & 0 deletions qualtran/bloqs/multiplexers/selected_majorana_fermion.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,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 @@ -134,3 +135,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
4 changes: 4 additions & 0 deletions qualtran/resource_counting/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@

from ._costing import GeneralizerT, get_cost_value, get_cost_cache, query_costs, CostKey, CostValT

from ._bloq_counts import BloqCount, QECGatesCost
from ._qubit_counts import QubitCount
from ._success_prob import SuccessProb

from . import generalizers
Loading
Loading