Skip to content

Commit 3e542af

Browse files
committed
prototype: use rotation eps in GateCounts
1 parent 6a4b920 commit 3e542af

File tree

7 files changed

+71
-29
lines changed

7 files changed

+71
-29
lines changed

qualtran/resource_counting/_bloq_counts.py

+30-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
import logging
15-
from collections import defaultdict
16-
from typing import Callable, Dict, Sequence, Tuple, TYPE_CHECKING
15+
from collections import Counter, defaultdict
16+
from typing import Callable, Dict, Mapping, Sequence, Tuple, TYPE_CHECKING
1717

1818
import attrs
1919
import networkx as nx
@@ -112,6 +112,12 @@ def __str__(self):
112112
return f'{self.gateset_name} counts'
113113

114114

115+
def _mapping_to_counter(mapping: Mapping[float, int]) -> Counter[float]:
116+
if isinstance(mapping, Counter):
117+
return mapping
118+
return Counter(mapping)
119+
120+
115121
@frozen(kw_only=True)
116122
class GateCounts:
117123
"""A data class of counts of the typical target gates in a compilation.
@@ -125,8 +131,17 @@ class GateCounts:
125131
cswap: int = 0
126132
and_bloq: int = 0
127133
clifford: int = 0
128-
rotation: int = 0
129134
measurement: int = 0
135+
rotation_epsilons: Counter[float] = field(factory=Counter, converter=_mapping_to_counter)
136+
137+
@property
138+
def rotation(self):
139+
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
140+
141+
return sum(
142+
n_rotations * int(TComplexity.rotation_cost(eps))
143+
for eps, n_rotations in self.rotation_epsilons.items()
144+
)
130145

131146
def __add__(self, other):
132147
if not isinstance(other, GateCounts):
@@ -138,8 +153,8 @@ def __add__(self, other):
138153
cswap=self.cswap + other.cswap,
139154
and_bloq=self.and_bloq + other.and_bloq,
140155
clifford=self.clifford + other.clifford,
141-
rotation=self.rotation + other.rotation,
142156
measurement=self.measurement + other.measurement,
157+
rotation_epsilons=self.rotation_epsilons + other.rotation_epsilons,
143158
)
144159

145160
def __mul__(self, other):
@@ -149,8 +164,8 @@ def __mul__(self, other):
149164
cswap=other * self.cswap,
150165
and_bloq=other * self.and_bloq,
151166
clifford=other * self.clifford,
152-
rotation=other * self.rotation,
153167
measurement=other * self.measurement,
168+
rotation_epsilons=Counter({k: other * v for k, v in self.rotation_epsilons.items()}),
154169
)
155170

156171
def __rmul__(self, other):
@@ -167,7 +182,13 @@ def __str__(self):
167182

168183
def asdict(self):
169184
d = attrs.asdict(self)
170-
return {k: v for k, v in d.items() if v > 0}
185+
186+
def _keep(key, value) -> bool:
187+
if key == 'rotation_epsilons':
188+
return value
189+
return value > 0
190+
191+
return {k: v for k, v in d.items() if _keep(k, v)}
171192

172193
def total_t_count(
173194
self,
@@ -232,6 +253,7 @@ class QECGatesCost(CostKey[GateCounts]):
232253

233254
def compute(self, bloq: 'Bloq', get_callee_cost: Callable[['Bloq'], GateCounts]) -> GateCounts:
234255
from qualtran.bloqs.basic_gates import TGate, Toffoli, TwoBitCSwap
256+
from qualtran.bloqs.basic_gates.rotation import _HasEps
235257
from qualtran.bloqs.mcmt.and_bloq import And
236258

237259
# T gates
@@ -257,7 +279,8 @@ def compute(self, bloq: 'Bloq', get_callee_cost: Callable[['Bloq'], GateCounts])
257279
return GateCounts(clifford=1)
258280

259281
if bloq_is_rotation(bloq):
260-
return GateCounts(rotation=1)
282+
assert isinstance(bloq, _HasEps)
283+
return GateCounts(rotation_epsilons={bloq.eps: 1})
261284

262285
# Recursive case
263286
totals = GateCounts()

qualtran/resource_counting/_bloq_counts_test.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,15 @@ def test_qec_gates_cost():
7474
# And
7575
[mcmt.And(), GateCounts(and_bloq=1)],
7676
# Rotations
77-
[basic_gates.ZPowGate(exponent=0.1, global_shift=0.0, eps=1e-11), GateCounts(rotation=1)],
77+
[
78+
basic_gates.ZPowGate(exponent=0.1, global_shift=0.0, eps=1e-11),
79+
GateCounts(rotation_epsilons={1e-11: 1}),
80+
],
7881
[
7982
rotations.phase_gradient.PhaseGradientUnitary(
8083
bitsize=10, exponent=1, is_controlled=False, eps=1e-10
8184
),
82-
GateCounts(rotation=10),
85+
GateCounts(rotation_epsilons={1e-10: 10}),
8386
],
8487
# Recursive
8588
[

qualtran/surface_code/algorithm_summary_test.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,17 @@
3838
[mcmt.And(), AlgorithmSummary(n_algo_qubits=3, n_logical_gates=GateCounts(and_bloq=1))],
3939
[
4040
basic_gates.ZPowGate(exponent=0.1, global_shift=0.0, eps=1e-11),
41-
AlgorithmSummary(n_algo_qubits=1, n_logical_gates=GateCounts(rotation=1)),
41+
AlgorithmSummary(
42+
n_algo_qubits=1, n_logical_gates=GateCounts(rotation_epsilons={1e-11: 1})
43+
),
4244
],
4345
[
4446
rotations.phase_gradient.PhaseGradientUnitary(
4547
bitsize=10, exponent=1, is_controlled=False, eps=1e-10
4648
),
47-
AlgorithmSummary(n_algo_qubits=10, n_logical_gates=GateCounts(rotation=10)),
49+
AlgorithmSummary(
50+
n_algo_qubits=10, n_logical_gates=GateCounts(rotation_epsilons={1e-10: 10})
51+
),
4852
],
4953
[
5054
mcmt.MultiControlPauli(cvs=(1, 1, 1), target_gate=cirq.X),

qualtran/surface_code/beverland_et_al_model.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,12 @@ def n_discrete_logical_gates(
116116
rotation_model: Cost model used to compute the number of T gates
117117
needed to approximate rotations.
118118
"""
119-
n_rotations: int = alg.n_logical_gates.rotation
120-
ret = attrs.evolve(alg.n_logical_gates, rotation=0)
121-
if n_rotations > 0:
122-
ret = (
123-
ret
124-
+ rotation_model.preparation_overhead(eps_syn)
125-
+ n_rotations * rotation_model.rotation_cost(eps_syn / n_rotations)
126-
)
119+
rotation_epsilons: dict[float, int] = alg.n_logical_gates.rotation_epsilons
120+
ret = attrs.evolve(alg.n_logical_gates, rotation_epsilons={})
121+
if rotation_epsilons:
122+
rotation_model.preparation_overhead(min(eps for eps in rotation_epsilons.values()))
123+
for eps, n_rotations in rotation_epsilons.items():
124+
ret += n_rotations * rotation_model.rotation_cost(eps)
127125
return ret
128126

129127

qualtran/surface_code/beverland_et_al_model_test.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ class Test:
3838
Test(
3939
alg=AlgorithmSummary(
4040
n_algo_qubits=100,
41-
n_logical_gates=GateCounts(rotation=30_100, measurement=int(1.4e6)),
41+
n_logical_gates=GateCounts(
42+
rotation_epsilons={1e-3 / 30_000: 30_000}, measurement=int(1.4e6)
43+
),
4244
n_rotation_layers=501,
4345
),
4446
error_budget=1e-3,
45-
c_min=1.5e6,
47+
c_min=2.5e6,
4648
time_steps=1.5e5,
4749
code_distance=9,
4850
t_states=602000,
@@ -51,7 +53,10 @@ class Test:
5153
alg=AlgorithmSummary(
5254
n_algo_qubits=1318,
5355
n_logical_gates=GateCounts(
54-
t=int(5.53e7), rotation=int(2.06e8), toffoli=int(1.35e11), measurement=int(1.37e9)
56+
t=int(5.53e7),
57+
rotation_epsilons={1e-2 / 2.06e8: int(2.06e8)},
58+
toffoli=int(1.35e11),
59+
measurement=int(1.37e9),
5560
),
5661
n_rotation_layers=int(2.05e8),
5762
),
@@ -65,7 +70,10 @@ class Test:
6570
alg=AlgorithmSummary(
6671
n_algo_qubits=12581,
6772
n_logical_gates=GateCounts(
68-
t=12, rotation=12, toffoli=int(3.73e9), measurement=int(1.08e9)
73+
t=12,
74+
rotation_epsilons={1 / 3 / 12: 12},
75+
toffoli=int(3.73e9),
76+
measurement=int(1.08e9),
6977
),
7078
n_rotation_layers=12,
7179
),

qualtran/surface_code/ui.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -522,24 +522,30 @@ def update(
522522
qec_name: str,
523523
magic_name: str,
524524
magic_count: int,
525-
rotaion_model_name: str,
525+
rotation_model_name: str,
526526
):
527527
"""Updates the visualization."""
528528
if any(x is None for x in [physical_error_rate, error_budget, *algorithm_data, magic_count]):
529529
raise PreventUpdate
530530

531531
# TODO: We implicitly rely on the order of the input components
532532
qubits, measurements, ts, toffolis, rotations, n_rotation_layers = algorithm_data
533+
534+
rotation_eps = 1e-3 / rotations # TODO this should not be a magic number
535+
533536
algorithm = AlgorithmSummary(
534537
n_algo_qubits=qubits,
535538
n_logical_gates=GateCounts(
536-
measurement=measurements, t=ts, toffoli=toffolis, rotation=rotations
539+
measurement=measurements,
540+
t=ts,
541+
toffoli=toffolis,
542+
rotation_epsilons={rotation_eps: rotations},
537543
),
538544
n_rotation_layers=n_rotation_layers,
539545
)
540546
qec = _QEC_SCHEMES[qec_name]
541547
magic_factory = _MAGIC_FACTORIES[magic_name]
542-
rotation_model = _ROTATION_MODELS[rotaion_model_name]
548+
rotation_model = _ROTATION_MODELS[rotation_model_name]
543549
n_logical_gates = beverland_et_al_model.n_discrete_logical_gates(
544550
eps_syn=error_budget / 3, alg=algorithm, rotation_model=rotation_model
545551
)

qualtran/surface_code/ui_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_ensure_support_for_all_supported_models(estimation_model: str):
2929
qec_name='GidneyFowler',
3030
magic_name='FifteenToOne733',
3131
magic_count=1,
32-
rotaion_model_name='BeverlandEtAlRotationCost',
32+
rotation_model_name='BeverlandEtAlRotationCost',
3333
)
3434

3535

@@ -81,7 +81,7 @@ def test_update(estimation_model: str, desired):
8181
qec_name='GidneyFowler',
8282
magic_name='FifteenToOne733',
8383
magic_count=1,
84-
rotaion_model_name='BeverlandEtAlRotationCost',
84+
rotation_model_name='BeverlandEtAlRotationCost',
8585
)
8686
assert (
8787
display_runtime,
@@ -104,7 +104,7 @@ def test_update_bad_input():
104104
qec_name='GidneyFowler',
105105
magic_name='FifteenToOne733',
106106
magic_count=1,
107-
rotaion_model_name='BeverlandEtAlRotationCost',
107+
rotation_model_name='BeverlandEtAlRotationCost',
108108
)
109109

110110

0 commit comments

Comments
 (0)