cirq-core 1.6.0.dev20250505203257__py3-none-any.whl → 1.6.0.dev20250505215959__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cirq-core might be problematic. Click here for more details.
- cirq/_version.py +1 -1
- cirq/_version_test.py +1 -1
- cirq/experiments/benchmarking/__init__.py +17 -0
- cirq/experiments/benchmarking/parallel_xeb.py +679 -0
- cirq/experiments/benchmarking/parallel_xeb_test.py +445 -0
- cirq/experiments/two_qubit_xeb.py +4 -0
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/RECORD +11 -8
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright 2025 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Tools for branchmarking NISQ circuits."""
|
|
16
|
+
|
|
17
|
+
from cirq.experiments.benchmarking.parallel_xeb import parallel_two_qubit_xeb
|
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
# Copyright 2025 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""A module for performing and analysing parallel XEB."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from concurrent import futures
|
|
20
|
+
from typing import Dict, Optional, overload, Sequence, TYPE_CHECKING, Union
|
|
21
|
+
|
|
22
|
+
import attrs
|
|
23
|
+
import networkx as nx
|
|
24
|
+
import numpy as np
|
|
25
|
+
import pandas as pd
|
|
26
|
+
|
|
27
|
+
import cirq.experiments.random_quantum_circuit_generation as rqcg
|
|
28
|
+
import cirq.experiments.two_qubit_xeb as tqxeb
|
|
29
|
+
import cirq.experiments.xeb_fitting as xeb_fitting
|
|
30
|
+
from cirq import circuits, devices, ops, protocols, sim, value
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
import cirq
|
|
34
|
+
|
|
35
|
+
_TARGET_T = Union['cirq.Gate', 'cirq.Operation', 'cirq.AbstractCircuit']
|
|
36
|
+
_QUBIT_PAIR_T = tuple['cirq.GridQubit', 'cirq.GridQubit']
|
|
37
|
+
_CANONICAL_TARGET_T = Union['cirq.Operation', Dict[_QUBIT_PAIR_T, 'cirq.Operation']]
|
|
38
|
+
_PROBABILITIES_DICT_T = dict[_QUBIT_PAIR_T, list[list[np.ndarray]]]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _canonize_pair(pair: _QUBIT_PAIR_T) -> _QUBIT_PAIR_T:
|
|
42
|
+
return min(pair), max(pair)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@attrs.frozen
|
|
46
|
+
class XEBParameters:
|
|
47
|
+
"""A frozen dataclass that holds the parameter of an XEB experiment.
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
n_repetitions: The number of repetitions to use.
|
|
51
|
+
n_combinations: The number of combinations to generate.
|
|
52
|
+
n_circuits: The number of circuits to generate.
|
|
53
|
+
cycle_depths: The cycle depths to use.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
n_repetitions: int = 10**4
|
|
57
|
+
n_combinations: int = 10
|
|
58
|
+
n_circuits: int = 20
|
|
59
|
+
cycle_depths: tuple[int, ...] = attrs.field(default=(5, 25, 50, 100, 200, 300), converter=tuple)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@attrs.frozen
|
|
63
|
+
class XEBWideCircuitInfo:
|
|
64
|
+
"""Represents an XEB circuit expanded to the given cycle depth.
|
|
65
|
+
|
|
66
|
+
Attributes:
|
|
67
|
+
wide_circuit: The expanded circuit.
|
|
68
|
+
pairs: A list of the pairs benchmarked by the given circuit.
|
|
69
|
+
narrow_template_indices: Integer indices of the circuits in the narrow circuit library
|
|
70
|
+
used to build the given wide circuit.
|
|
71
|
+
cycle_depth: Optional, the depth of the cycle forming the wide circuit.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
wide_circuit: circuits.Circuit
|
|
75
|
+
pairs: Sequence[_QUBIT_PAIR_T] = attrs.field(
|
|
76
|
+
converter=lambda seq: [_canonize_pair(pair) for pair in seq]
|
|
77
|
+
)
|
|
78
|
+
narrow_template_indices: tuple[int, ...] = attrs.field(converter=tuple)
|
|
79
|
+
cycle_depth: Optional[int] = None
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def from_narrow_circuits(
|
|
83
|
+
circuit_templates: Sequence[cirq.Circuit],
|
|
84
|
+
permutation: np.ndarray,
|
|
85
|
+
pairs: Sequence[_QUBIT_PAIR_T],
|
|
86
|
+
target: _CANONICAL_TARGET_T,
|
|
87
|
+
) -> XEBWideCircuitInfo:
|
|
88
|
+
"""A static method that merges a sequence of narrow circuits into a wide circuit.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
circuit_templates: A sequence of 2Q (i.e. narrow) circuits.
|
|
92
|
+
permutation: A permutation that maps a qubit-pair to a narrow circuit.
|
|
93
|
+
pairs: The list of qubit-pairs to benchmark.
|
|
94
|
+
target: The target 2Q operation to benchmark.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
An XEBWideCircuitInfo instance representing the glued circuits.
|
|
98
|
+
"""
|
|
99
|
+
transformed_circuits = []
|
|
100
|
+
has_circuit_operations = False
|
|
101
|
+
for i, pair in zip(permutation, pairs, strict=True):
|
|
102
|
+
circuit = circuit_templates[i].transform_qubits(lambda q: pair[q.x])
|
|
103
|
+
if isinstance(target, ops.Operation):
|
|
104
|
+
xeb_op = target.with_qubits(*pair)
|
|
105
|
+
else:
|
|
106
|
+
if pair not in target:
|
|
107
|
+
continue
|
|
108
|
+
xeb_op = target[pair]
|
|
109
|
+
xeb_op = xeb_op.with_qubits(*pair)
|
|
110
|
+
|
|
111
|
+
if isinstance(xeb_op, circuits.CircuitOperation):
|
|
112
|
+
xeb_op = xeb_op.mapped_op()
|
|
113
|
+
has_circuit_operations = True
|
|
114
|
+
|
|
115
|
+
def _map_operation(op):
|
|
116
|
+
num_qubits = protocols.num_qubits(op)
|
|
117
|
+
if num_qubits <= 1:
|
|
118
|
+
return op
|
|
119
|
+
assert num_qubits == 2
|
|
120
|
+
return xeb_op
|
|
121
|
+
|
|
122
|
+
circuit = circuit.map_operations(_map_operation)
|
|
123
|
+
transformed_circuits.append(circuit)
|
|
124
|
+
|
|
125
|
+
zipped_circuit = circuits.Circuit.zip(*transformed_circuits)
|
|
126
|
+
if has_circuit_operations and len(circuit_templates) > 1:
|
|
127
|
+
# Each moment must have at most one circuit operation.
|
|
128
|
+
new_moments = []
|
|
129
|
+
for moment in zipped_circuit:
|
|
130
|
+
if any(isinstance(op, circuits.CircuitOperation) for op in moment):
|
|
131
|
+
new_moments.append(
|
|
132
|
+
_transform_moment_with_circuit_ops_to_moment_with_single_op(moment)
|
|
133
|
+
)
|
|
134
|
+
else:
|
|
135
|
+
new_moments.append(moment)
|
|
136
|
+
zipped_circuit = circuits.Circuit.from_moments(*new_moments)
|
|
137
|
+
return XEBWideCircuitInfo(zipped_circuit, pairs, narrow_template_indices=permutation)
|
|
138
|
+
|
|
139
|
+
def sliced_circuits(self, cycle_depths: Sequence[int]) -> Sequence[XEBWideCircuitInfo]:
|
|
140
|
+
"""Slices the wide circuit into the given cycle depths and appends necessary measurements.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
cycle_depths: the cycle depths to cut the wide circuit into.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
A sequence of XEBWideCircuitInfo representing the sliced circuits.
|
|
147
|
+
"""
|
|
148
|
+
xeb_circuits = []
|
|
149
|
+
for cycle_depth in cycle_depths:
|
|
150
|
+
circuit_depth = 2 * cycle_depth + 1
|
|
151
|
+
xeb_circuit = self.wide_circuit[:circuit_depth]
|
|
152
|
+
xeb_circuit.append(
|
|
153
|
+
circuits.Moment(ops.measure(pair, key=str(pair)) for pair in self.pairs)
|
|
154
|
+
)
|
|
155
|
+
xeb_circuits.append(
|
|
156
|
+
attrs.evolve(self, wide_circuit=xeb_circuit, cycle_depth=cycle_depth)
|
|
157
|
+
)
|
|
158
|
+
return xeb_circuits
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _target_to_operation(target: _TARGET_T) -> cirq.Operation:
|
|
162
|
+
if isinstance(target, ops.Gate):
|
|
163
|
+
return target(*devices.LineQid.for_gate(target))
|
|
164
|
+
elif isinstance(target, circuits.AbstractCircuit):
|
|
165
|
+
return circuits.CircuitOperation(target.freeze())
|
|
166
|
+
return target
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _canonize_target(
|
|
170
|
+
target: Union[_TARGET_T, Dict[_QUBIT_PAIR_T, _TARGET_T]],
|
|
171
|
+
) -> _CANONICAL_TARGET_T:
|
|
172
|
+
if isinstance(target, (ops.Gate, ops.Operation, circuits.AbstractCircuit)):
|
|
173
|
+
return _target_to_operation(target)
|
|
174
|
+
return {k: _target_to_operation(v) for k, v in target.items()}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _transform_moment_with_circuit_ops_to_moment_with_single_op(
|
|
178
|
+
moment: circuits.Moment,
|
|
179
|
+
) -> circuits.Moment:
|
|
180
|
+
"""Merges all circuit operations in a moment into a single circuit operation.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
moment: A cirq moment composed of single and two qubit operations.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
A Moment with at most one CircuitOperation.
|
|
187
|
+
"""
|
|
188
|
+
circuit_ops = [
|
|
189
|
+
op.mapped_circuit() for op in moment if isinstance(op, circuits.CircuitOperation)
|
|
190
|
+
]
|
|
191
|
+
not_circuit_ops = [op for op in moment if not isinstance(op, circuits.CircuitOperation)]
|
|
192
|
+
all_subcircuits = circuit_ops
|
|
193
|
+
if not_circuit_ops:
|
|
194
|
+
all_subcircuits.append(circuits.Circuit(circuits.Moment(not_circuit_ops)))
|
|
195
|
+
return circuits.Moment(circuits.CircuitOperation(circuits.FrozenCircuit.zip(*all_subcircuits)))
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def create_combination_circuits(
|
|
199
|
+
circuit_templates: Sequence[cirq.Circuit],
|
|
200
|
+
combinations_by_layer: Sequence[rqcg.CircuitLibraryCombination],
|
|
201
|
+
target: _CANONICAL_TARGET_T,
|
|
202
|
+
) -> Sequence[XEBWideCircuitInfo]:
|
|
203
|
+
"""Zips two-qubit circuits into a single wide circuit for each of the given combinations.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
circuit_templates: A sequence of narrow circuits.
|
|
207
|
+
combinations_by_layer: A sequence of combinations.
|
|
208
|
+
target: The target 2Q operation.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
A sequence of XEBWideCircuitInfo representing the wide circuits.
|
|
212
|
+
"""
|
|
213
|
+
wide_circuits_info = []
|
|
214
|
+
for layer_comb in combinations_by_layer:
|
|
215
|
+
pairs = layer_comb.pairs
|
|
216
|
+
if isinstance(target, dict):
|
|
217
|
+
pairs = [pair for pair in pairs if pair in target]
|
|
218
|
+
assert pairs
|
|
219
|
+
for comb in layer_comb.combinations:
|
|
220
|
+
wide_circuits_info.append(
|
|
221
|
+
XEBWideCircuitInfo.from_narrow_circuits(
|
|
222
|
+
circuit_templates,
|
|
223
|
+
permutation=comb,
|
|
224
|
+
pairs=layer_comb.pairs, # type: ignore[arg-type]
|
|
225
|
+
target=target,
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
return wide_circuits_info
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def simulate_circuit(
|
|
232
|
+
simulator: cirq.Simulator, circuit: cirq.Circuit, cycle_depths: Sequence[int]
|
|
233
|
+
) -> Sequence[np.ndarray]:
|
|
234
|
+
"""Simulates the given circuit and returns the state probabilities for each cycle depth.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
simulator: A cirq simulator.
|
|
238
|
+
circuit: The circuit to simulate.
|
|
239
|
+
cycle_depths: A sequence of integers representing the depths for which we need the
|
|
240
|
+
state probabilities.
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
- The cuircuit_id, same as given in input.
|
|
244
|
+
- The state probabilities for each cycle depth.
|
|
245
|
+
"""
|
|
246
|
+
cycle_depths_set = frozenset(cycle_depths)
|
|
247
|
+
result = []
|
|
248
|
+
for moment_i, step_result in enumerate(simulator.simulate_moment_steps(circuit=circuit)):
|
|
249
|
+
# Translate from moment_i to cycle_depth:
|
|
250
|
+
# We know circuit_depth = cycle_depth * 2 + 1, and step_result is the result *after*
|
|
251
|
+
# moment_i, so circuit_depth = moment_i + 1 and moment_i = cycle_depth * 2.
|
|
252
|
+
if moment_i % 2 == 1:
|
|
253
|
+
continue
|
|
254
|
+
cycle_depth = moment_i // 2
|
|
255
|
+
if cycle_depth not in cycle_depths_set:
|
|
256
|
+
continue
|
|
257
|
+
|
|
258
|
+
psi = step_result.state_vector()
|
|
259
|
+
pure_probs = value.state_vector_to_probabilities(psi)
|
|
260
|
+
|
|
261
|
+
result.append(pure_probs)
|
|
262
|
+
return result
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@overload
|
|
266
|
+
def simulate_circuit_library(
|
|
267
|
+
circuit_templates: Sequence[cirq.Circuit],
|
|
268
|
+
target_or_dict: ops.Operation,
|
|
269
|
+
cycle_depths: Sequence[int],
|
|
270
|
+
pool: Optional[futures.Executor] = None,
|
|
271
|
+
) -> Sequence[Sequence[np.ndarray]]: ...
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@overload
|
|
275
|
+
def simulate_circuit_library(
|
|
276
|
+
circuit_templates: Sequence[cirq.Circuit],
|
|
277
|
+
target_or_dict: dict[_QUBIT_PAIR_T, ops.Operation],
|
|
278
|
+
cycle_depths: Sequence[int],
|
|
279
|
+
pool: Optional[futures.Executor] = None,
|
|
280
|
+
) -> dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]: ...
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def simulate_circuit_library(
|
|
284
|
+
circuit_templates: Sequence[cirq.Circuit],
|
|
285
|
+
target_or_dict: _CANONICAL_TARGET_T,
|
|
286
|
+
cycle_depths: Sequence[int],
|
|
287
|
+
pool: Optional[futures.Executor] = None,
|
|
288
|
+
) -> Union[Sequence[Sequence[np.ndarray]], dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]]:
|
|
289
|
+
"""Simulate the given sequence of circuits.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
circuit_templates: A sequence of circuits to simulate.
|
|
293
|
+
target_or_dict: The target operation or dictionary mapping qubit-pairs to operations.
|
|
294
|
+
cycle_depths: A list of integers giving the cycle depths to use in benchmarking.
|
|
295
|
+
pool: An optional concurrent.futures.Executor pool (e.g. ThreadPoolExecutor).
|
|
296
|
+
If given, the simulations are performed asynchronously.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
If target_or_dict is an operation:
|
|
300
|
+
A sequence of the result of simulate_circuit for each circuit_templates.
|
|
301
|
+
Else:
|
|
302
|
+
A dictionary mapping the keys of the map to a sequence of the result of
|
|
303
|
+
simulate_circuit for each circuit_templates.
|
|
304
|
+
"""
|
|
305
|
+
two_qubit_ops = []
|
|
306
|
+
keys = None
|
|
307
|
+
if isinstance(target_or_dict, dict):
|
|
308
|
+
keys = tuple(target_or_dict.keys())
|
|
309
|
+
two_qubit_ops = list(target_or_dict[k] for k in keys)
|
|
310
|
+
else:
|
|
311
|
+
two_qubit_ops = [target_or_dict]
|
|
312
|
+
|
|
313
|
+
all_circuits = []
|
|
314
|
+
for target_op in two_qubit_ops:
|
|
315
|
+
|
|
316
|
+
def _map_op(op: ops.Operation) -> ops.Operation:
|
|
317
|
+
num_qubits = protocols.num_qubits(op)
|
|
318
|
+
if num_qubits <= 1:
|
|
319
|
+
return op
|
|
320
|
+
assert num_qubits == 2
|
|
321
|
+
return target_op.with_qubits(*op.qubits)
|
|
322
|
+
|
|
323
|
+
for circuit in circuit_templates:
|
|
324
|
+
all_circuits.append(circuit.map_operations(_map_op))
|
|
325
|
+
|
|
326
|
+
if pool is None:
|
|
327
|
+
simulation_results = [
|
|
328
|
+
simulate_circuit(
|
|
329
|
+
sim.Simulator(seed=np.random.RandomState(), dtype=np.complex128),
|
|
330
|
+
circuit=circuit,
|
|
331
|
+
cycle_depths=cycle_depths,
|
|
332
|
+
)
|
|
333
|
+
for circuit in all_circuits
|
|
334
|
+
]
|
|
335
|
+
else:
|
|
336
|
+
simulation_results = [[np.empty(0)] for _ in range(len(all_circuits))]
|
|
337
|
+
tasks = [
|
|
338
|
+
pool.submit(
|
|
339
|
+
simulate_circuit,
|
|
340
|
+
simulator=sim.Simulator(seed=np.random.RandomState(), dtype=np.complex128),
|
|
341
|
+
circuit=circuit,
|
|
342
|
+
cycle_depths=cycle_depths,
|
|
343
|
+
)
|
|
344
|
+
for circuit in all_circuits
|
|
345
|
+
]
|
|
346
|
+
tasks_index = {t: i for i, t in enumerate(tasks)}
|
|
347
|
+
for task in futures.as_completed(tasks):
|
|
348
|
+
sim_result = task.result()
|
|
349
|
+
i = tasks_index[task]
|
|
350
|
+
simulation_results[i] = sim_result
|
|
351
|
+
|
|
352
|
+
if keys is None:
|
|
353
|
+
return simulation_results
|
|
354
|
+
|
|
355
|
+
num_templates = len(circuit_templates)
|
|
356
|
+
return {
|
|
357
|
+
keys[i]: simulation_results[i * num_templates : (i + 1) * num_templates]
|
|
358
|
+
for i in range(len(keys))
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def sample_all_circuits(
|
|
363
|
+
sampler: cirq.Sampler, circuits: Sequence[cirq.Circuit], repetitions: int
|
|
364
|
+
) -> Sequence[dict[str, np.ndarray]]:
|
|
365
|
+
"""Calls sampler.run_batch on the given circuits and estimates the state probabilities.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
sampler: A cirq sampler.
|
|
369
|
+
circuits: A sequence of circuits.
|
|
370
|
+
repetitions: An integer, the number of sampling repetitions.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
For each circuit, a dictionary mapping measurement keys to the estimated probabilities.
|
|
374
|
+
"""
|
|
375
|
+
sampling_results = []
|
|
376
|
+
for (result,) in sampler.run_batch(programs=circuits, repetitions=repetitions):
|
|
377
|
+
record = {}
|
|
378
|
+
for key in result.data.keys():
|
|
379
|
+
values = result.data[key]
|
|
380
|
+
sampled_probs = np.bincount(values, minlength=4) / len(values)
|
|
381
|
+
record[key] = sampled_probs
|
|
382
|
+
sampling_results.append(record)
|
|
383
|
+
return sampling_results
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _reshape_sampling_results(
|
|
387
|
+
sampling_results: Sequence[dict[str, np.ndarray]],
|
|
388
|
+
cycle_depths: Sequence[int],
|
|
389
|
+
wide_circuits_info: Sequence[XEBWideCircuitInfo],
|
|
390
|
+
pairs: Sequence[_QUBIT_PAIR_T],
|
|
391
|
+
num_templates: int,
|
|
392
|
+
) -> _PROBABILITIES_DICT_T:
|
|
393
|
+
cycle_depth_to_index = {d: i for i, d in enumerate(cycle_depths)}
|
|
394
|
+
sampled_probabilities = {
|
|
395
|
+
pair: [[np.empty(0)] * num_templates for _ in range(len(cycle_depths))] for pair in pairs
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
for sampling_result, info in zip(sampling_results, wide_circuits_info, strict=True):
|
|
399
|
+
cycle_depth = info.cycle_depth
|
|
400
|
+
assert cycle_depth is not None
|
|
401
|
+
cycle_idx = cycle_depth_to_index[cycle_depth]
|
|
402
|
+
for template_idx, pair in zip(info.narrow_template_indices, info.pairs, strict=True):
|
|
403
|
+
pair = _canonize_pair(pair)
|
|
404
|
+
key = str(pair)
|
|
405
|
+
sampled_prob = sampling_result.get(key, np.empty(0))
|
|
406
|
+
sampled_probabilities[pair][cycle_idx][template_idx] = sampled_prob
|
|
407
|
+
return sampled_probabilities
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def _reshape_simulation_results(
|
|
411
|
+
simulation_results: Union[
|
|
412
|
+
Sequence[Sequence[np.ndarray]], dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
|
|
413
|
+
],
|
|
414
|
+
cycle_depths: Sequence[int],
|
|
415
|
+
pairs: Sequence[_QUBIT_PAIR_T],
|
|
416
|
+
num_templates: int,
|
|
417
|
+
) -> _PROBABILITIES_DICT_T:
|
|
418
|
+
cycle_depth_to_index = {d: i for i, d in enumerate(cycle_depths)}
|
|
419
|
+
|
|
420
|
+
if isinstance(simulation_results, dict):
|
|
421
|
+
pure_probabilities = {
|
|
422
|
+
pair: [[np.empty(0)] * num_templates for _ in range(len(cycle_depths))]
|
|
423
|
+
for pair in pairs
|
|
424
|
+
}
|
|
425
|
+
for pair, simulation_result_for_pair in simulation_results.items():
|
|
426
|
+
for template_idx, template_simulation_result in enumerate(simulation_result_for_pair):
|
|
427
|
+
for cycle_depth, pure_probs in zip(
|
|
428
|
+
cycle_depths, template_simulation_result, strict=True
|
|
429
|
+
):
|
|
430
|
+
cycle_idx = cycle_depth_to_index[cycle_depth]
|
|
431
|
+
pure_probabilities[pair][cycle_idx][template_idx] = pure_probs
|
|
432
|
+
|
|
433
|
+
return pure_probabilities
|
|
434
|
+
else:
|
|
435
|
+
common_pure_probs = [[np.empty(0)] * num_templates for _ in range(len(cycle_depths))]
|
|
436
|
+
for template_idx, template_simulation_result in enumerate(simulation_results):
|
|
437
|
+
for cycle_depth, pure_probs in zip(
|
|
438
|
+
cycle_depths, template_simulation_result, strict=True
|
|
439
|
+
):
|
|
440
|
+
cycle_idx = cycle_depth_to_index[cycle_depth]
|
|
441
|
+
common_pure_probs[cycle_idx][template_idx] = pure_probs
|
|
442
|
+
return {pair: common_pure_probs for pair in pairs}
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
@attrs.frozen
|
|
446
|
+
class XEBFidelity:
|
|
447
|
+
"""The estimated fidelity of a given pair at a give cycle depth.
|
|
448
|
+
|
|
449
|
+
Attributes:
|
|
450
|
+
pair: A qubit pair.
|
|
451
|
+
cycle_depth: The depth of the cycle.
|
|
452
|
+
fidelity: The estimated fidelity.
|
|
453
|
+
"""
|
|
454
|
+
|
|
455
|
+
pair: _QUBIT_PAIR_T
|
|
456
|
+
cycle_depth: int
|
|
457
|
+
fidelity: float
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def _cross_entropy(p: np.ndarray, q: np.ndarray, eps: float = 1e-60) -> float:
|
|
461
|
+
q[q <= 0] = eps # for numerical stability
|
|
462
|
+
return -np.dot(p, np.log2(q))
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def estimate_fidelities(
|
|
466
|
+
sampling_results: Sequence[dict[str, np.ndarray]],
|
|
467
|
+
simulation_results: Union[
|
|
468
|
+
Sequence[Sequence[np.ndarray]], dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
|
|
469
|
+
],
|
|
470
|
+
cycle_depths: Sequence[int],
|
|
471
|
+
wide_circuits_info: Sequence[XEBWideCircuitInfo],
|
|
472
|
+
pairs: Sequence[_QUBIT_PAIR_T],
|
|
473
|
+
num_templates: int,
|
|
474
|
+
) -> Sequence[XEBFidelity]:
|
|
475
|
+
"""Estimates the fidelities from the given sampling and simulation results.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
sampling_results: The result of `sample_all_circuits`.
|
|
479
|
+
simulation_results: The result of `simulate_circuit_library`,
|
|
480
|
+
cycle_depths: The sequence of cycle depths,
|
|
481
|
+
wide_circuits_info: Sequence of XEBWideCircuitInfo detailing describing
|
|
482
|
+
the sampled circuits.
|
|
483
|
+
pairs: The qubit pairs being tests,
|
|
484
|
+
num_templates: The number of circuit templates used for benchmarking,
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
A sequence of XEBFidelity objects.
|
|
488
|
+
"""
|
|
489
|
+
|
|
490
|
+
sampled_probabilities = _reshape_sampling_results(
|
|
491
|
+
sampling_results, cycle_depths, wide_circuits_info, pairs, num_templates
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
pure_probabilities = _reshape_simulation_results(
|
|
495
|
+
simulation_results, cycle_depths, pairs, num_templates
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
records = []
|
|
499
|
+
for pair in pairs:
|
|
500
|
+
for depth_idx, cycle_depth in enumerate(cycle_depths):
|
|
501
|
+
numerator = 0.0
|
|
502
|
+
denominator = 0.0
|
|
503
|
+
for template_idx in range(num_templates):
|
|
504
|
+
pure_probs = pure_probabilities[pair][depth_idx][template_idx]
|
|
505
|
+
sampled_probs = sampled_probabilities[pair][depth_idx][template_idx]
|
|
506
|
+
if len(sampled_probs) == 0:
|
|
507
|
+
continue
|
|
508
|
+
assert (
|
|
509
|
+
len(sampled_probs) == 4
|
|
510
|
+
), f'{pair=} {cycle_depth=} {template_idx=}: {sampled_probs=}'
|
|
511
|
+
p_uniform = np.ones_like(pure_probs) / len(pure_probs)
|
|
512
|
+
pure_probs /= pure_probs.sum()
|
|
513
|
+
sampled_probs /= sampled_probs.sum()
|
|
514
|
+
|
|
515
|
+
h_up = _cross_entropy(p_uniform, pure_probs) # H[uniform, pure probs]
|
|
516
|
+
h_sp = _cross_entropy(sampled_probs, pure_probs) # H[sampled probs, pure probs]
|
|
517
|
+
h_pp = _cross_entropy(pure_probs, pure_probs) # H[pure probs]
|
|
518
|
+
|
|
519
|
+
y = h_up - h_sp
|
|
520
|
+
x = h_up - h_pp
|
|
521
|
+
numerator += x * y
|
|
522
|
+
denominator += x**2
|
|
523
|
+
fidelity = numerator / denominator
|
|
524
|
+
records.append(XEBFidelity(pair=pair, cycle_depth=cycle_depth, fidelity=fidelity))
|
|
525
|
+
return records
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def _extract_pairs(
|
|
529
|
+
sampler: cirq.Sampler,
|
|
530
|
+
target: Union[_TARGET_T, Dict[_QUBIT_PAIR_T, _TARGET_T]],
|
|
531
|
+
qubits: Optional[Sequence[cirq.GridQubit]],
|
|
532
|
+
pairs: Optional[Sequence[_QUBIT_PAIR_T]],
|
|
533
|
+
) -> Sequence[_QUBIT_PAIR_T]:
|
|
534
|
+
if isinstance(target, dict):
|
|
535
|
+
if pairs is None:
|
|
536
|
+
pairs = tuple(target.keys())
|
|
537
|
+
else:
|
|
538
|
+
assert target.keys() == set(pairs)
|
|
539
|
+
qubits, device_pairs = tqxeb.qubits_and_pairs(sampler, qubits, pairs)
|
|
540
|
+
device_pairs = [_canonize_pair(pair) for pair in device_pairs]
|
|
541
|
+
if pairs is None:
|
|
542
|
+
return device_pairs
|
|
543
|
+
else:
|
|
544
|
+
pairs = [_canonize_pair(p) for p in pairs]
|
|
545
|
+
return tuple(set(pairs) & set(device_pairs))
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def parallel_xeb_workflow(
|
|
549
|
+
sampler: cirq.Sampler,
|
|
550
|
+
target: Union[_TARGET_T, Dict[_QUBIT_PAIR_T, _TARGET_T]],
|
|
551
|
+
ideal_target: Optional[Union[_TARGET_T, Dict[_QUBIT_PAIR_T, _TARGET_T]]] = None,
|
|
552
|
+
qubits: Optional[Sequence[cirq.GridQubit]] = None,
|
|
553
|
+
pairs: Optional[Sequence[_QUBIT_PAIR_T]] = None,
|
|
554
|
+
parameters: XEBParameters = XEBParameters(),
|
|
555
|
+
rng: Optional[np.random.Generator] = None,
|
|
556
|
+
pool: Optional[futures.Executor] = None,
|
|
557
|
+
) -> Sequence[XEBFidelity]:
|
|
558
|
+
"""A utility method that runs the full XEB workflow.
|
|
559
|
+
|
|
560
|
+
Args:
|
|
561
|
+
sampler: The quantum engine or simulator to run the circuits.
|
|
562
|
+
target: The entangling gate, op, circuit or dict mapping pairs to ops.
|
|
563
|
+
ideal_target: The ideal target(s) to branch mark against. If None, use `target`.
|
|
564
|
+
qubits: Qubits under test. If None, uses all qubits on the sampler's device.
|
|
565
|
+
pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
|
|
566
|
+
parameters: An `XEBParameters` containing the parameters of the XEB experiment.
|
|
567
|
+
rng: The random number generator to use.
|
|
568
|
+
pool: An optional `concurrent.futures.Executor` pool.
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
A sequence of XEBFidelity listing the estimated fidelity for each qubit_pair per depth.
|
|
572
|
+
|
|
573
|
+
Raises:
|
|
574
|
+
ValueError: If qubits are not specified and the sampler has no device.
|
|
575
|
+
"""
|
|
576
|
+
if rng is None:
|
|
577
|
+
rng = np.random.default_rng()
|
|
578
|
+
rs = np.random.RandomState(rng.integers(0, 10**9))
|
|
579
|
+
|
|
580
|
+
pairs = _extract_pairs(sampler, target, qubits, pairs)
|
|
581
|
+
graph = nx.Graph(pairs)
|
|
582
|
+
|
|
583
|
+
circuit_templates = rqcg.generate_library_of_2q_circuits(
|
|
584
|
+
n_library_circuits=parameters.n_circuits,
|
|
585
|
+
random_state=rs,
|
|
586
|
+
# Any two qubit gate works here since we creating templates rather than the actual circuits.
|
|
587
|
+
two_qubit_gate=ops.CZ,
|
|
588
|
+
max_cycle_depth=max(parameters.cycle_depths),
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
combs_by_layer = rqcg.get_random_combinations_for_device(
|
|
592
|
+
n_library_circuits=len(circuit_templates),
|
|
593
|
+
n_combinations=parameters.n_combinations,
|
|
594
|
+
device_graph=graph,
|
|
595
|
+
random_state=rs,
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
canonical_target = _canonize_target(target)
|
|
599
|
+
if ideal_target is None:
|
|
600
|
+
canonical_ideal_target = canonical_target
|
|
601
|
+
else:
|
|
602
|
+
canonical_ideal_target = _canonize_target(ideal_target)
|
|
603
|
+
|
|
604
|
+
if isinstance(canonical_target, dict):
|
|
605
|
+
assert all(
|
|
606
|
+
all(pair in canonical_target for pair in layer_comb.pairs)
|
|
607
|
+
for layer_comb in combs_by_layer
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
if isinstance(canonical_ideal_target, dict):
|
|
611
|
+
assert all(
|
|
612
|
+
all(pair in canonical_ideal_target for pair in layer_comb.pairs)
|
|
613
|
+
for layer_comb in combs_by_layer
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
wide_circuits_info = create_combination_circuits(
|
|
617
|
+
circuit_templates, combs_by_layer, canonical_target
|
|
618
|
+
)
|
|
619
|
+
wide_circuits_info = [
|
|
620
|
+
info_with_depth
|
|
621
|
+
for info in wide_circuits_info
|
|
622
|
+
for info_with_depth in info.sliced_circuits(parameters.cycle_depths)
|
|
623
|
+
]
|
|
624
|
+
|
|
625
|
+
# A map {measurement_key: sampled_probs} for each wide circuit
|
|
626
|
+
sampling_results = sample_all_circuits(
|
|
627
|
+
sampler, [info.wide_circuit for info in wide_circuits_info], parameters.n_repetitions
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
# Either of a pure_probability[circuit_template_idx][cycle_depth_index] or
|
|
631
|
+
# A map pure_probability[pair][circuit_template_idx][cycle_depth_index]
|
|
632
|
+
simulation_results = simulate_circuit_library(
|
|
633
|
+
circuit_templates, canonical_ideal_target, parameters.cycle_depths, pool
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
estimated_fidelities = estimate_fidelities(
|
|
637
|
+
sampling_results,
|
|
638
|
+
simulation_results,
|
|
639
|
+
parameters.cycle_depths,
|
|
640
|
+
wide_circuits_info,
|
|
641
|
+
pairs,
|
|
642
|
+
parameters.n_circuits,
|
|
643
|
+
)
|
|
644
|
+
return estimated_fidelities
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
def parallel_two_qubit_xeb(
|
|
648
|
+
sampler: cirq.Sampler,
|
|
649
|
+
target: Union[_TARGET_T, Dict[_QUBIT_PAIR_T, _TARGET_T]],
|
|
650
|
+
ideal_target: Optional[Union[_TARGET_T, Dict[_QUBIT_PAIR_T, _TARGET_T]]] = None,
|
|
651
|
+
qubits: Optional[Sequence[cirq.GridQubit]] = None,
|
|
652
|
+
pairs: Optional[Sequence[_QUBIT_PAIR_T]] = None,
|
|
653
|
+
parameters: XEBParameters = XEBParameters(),
|
|
654
|
+
rng: Optional[np.random.Generator] = None,
|
|
655
|
+
pool: Optional[futures.Executor] = None,
|
|
656
|
+
) -> tqxeb.TwoQubitXEBResult:
|
|
657
|
+
"""A convenience method that runs the full XEB workflow.
|
|
658
|
+
|
|
659
|
+
Args:
|
|
660
|
+
sampler: The quantum engine or simulator to run the circuits.
|
|
661
|
+
target: The entangling gate, op, circuit or dict mapping pairs to ops.
|
|
662
|
+
ideal_target: The ideal target(s) to branch mark against. If None, use `target`.
|
|
663
|
+
qubits: Qubits under test. If None, uses all qubits on the sampler's device.
|
|
664
|
+
pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
|
|
665
|
+
parameters: An `XEBParameters` containing the parameters of the XEB experiment.
|
|
666
|
+
rng: The random number generator to use.
|
|
667
|
+
pool: An optional `concurrent.futures.Executor` pool.
|
|
668
|
+
|
|
669
|
+
Returns:
|
|
670
|
+
A `TwoQubitXEBResult` object representing the result.
|
|
671
|
+
|
|
672
|
+
Raises:
|
|
673
|
+
ValueError: If qubits are not specified and the sampler has no device.
|
|
674
|
+
"""
|
|
675
|
+
estimated_fidelities = parallel_xeb_workflow(
|
|
676
|
+
sampler, target, ideal_target, qubits, pairs, parameters, rng, pool
|
|
677
|
+
)
|
|
678
|
+
df = pd.DataFrame.from_records([attrs.asdict(ef) for ef in estimated_fidelities])
|
|
679
|
+
return tqxeb.TwoQubitXEBResult(xeb_fitting.fit_exponential_decays(df))
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
# Copyright 2025 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import itertools
|
|
16
|
+
from concurrent import futures
|
|
17
|
+
from typing import Iterator
|
|
18
|
+
|
|
19
|
+
import networkx as nx
|
|
20
|
+
import numpy as np
|
|
21
|
+
import pytest
|
|
22
|
+
|
|
23
|
+
import cirq
|
|
24
|
+
import cirq.experiments.random_quantum_circuit_generation as rqcg
|
|
25
|
+
from cirq.experiments.benchmarking import parallel_xeb as xeb
|
|
26
|
+
|
|
27
|
+
_QUBITS = cirq.LineQubit.range(2)
|
|
28
|
+
_CIRCUIT_TEMPLATES = [
|
|
29
|
+
cirq.Circuit(cirq.X.on_each(_QUBITS), cirq.CZ(*_QUBITS), cirq.Y.on_each(_QUBITS)),
|
|
30
|
+
cirq.Circuit(cirq.Y.on_each(_QUBITS), cirq.CX(*_QUBITS), cirq.Z.on_each(_QUBITS)),
|
|
31
|
+
cirq.Circuit(cirq.Z.on_each(_QUBITS), cirq.CZ(*_QUBITS), cirq.X.on_each(_QUBITS)),
|
|
32
|
+
]
|
|
33
|
+
_PAIRS = ((cirq.q(0, 0), cirq.q(0, 1)), (cirq.q(0, 2), cirq.q(0, 3)), (cirq.q(0, 4), cirq.q(0, 5)))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TestXEBWideCircuitInfo:
|
|
37
|
+
|
|
38
|
+
def test_from_circuit(self):
|
|
39
|
+
permutation = [1, 2, 0]
|
|
40
|
+
target = cirq.CircuitOperation(cirq.FrozenCircuit(cirq.CNOT(*_QUBITS)))
|
|
41
|
+
wide_circuit = xeb.XEBWideCircuitInfo.from_narrow_circuits(
|
|
42
|
+
_CIRCUIT_TEMPLATES, permutation=permutation, pairs=_PAIRS, target=target
|
|
43
|
+
)
|
|
44
|
+
assert wide_circuit == xeb.XEBWideCircuitInfo(
|
|
45
|
+
wide_circuit=cirq.Circuit.from_moments(
|
|
46
|
+
[
|
|
47
|
+
cirq.Y.on_each(*_PAIRS[0]),
|
|
48
|
+
cirq.Z.on_each(*_PAIRS[1]),
|
|
49
|
+
cirq.X.on_each(*_PAIRS[2]),
|
|
50
|
+
],
|
|
51
|
+
cirq.CircuitOperation(
|
|
52
|
+
cirq.FrozenCircuit(
|
|
53
|
+
cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
|
|
54
|
+
)
|
|
55
|
+
),
|
|
56
|
+
[
|
|
57
|
+
cirq.Z.on_each(*_PAIRS[0]),
|
|
58
|
+
cirq.X.on_each(*_PAIRS[1]),
|
|
59
|
+
cirq.Y.on_each(*_PAIRS[2]),
|
|
60
|
+
],
|
|
61
|
+
),
|
|
62
|
+
pairs=_PAIRS,
|
|
63
|
+
narrow_template_indices=permutation,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def test_sliced_circuit(self):
|
|
67
|
+
wid_circuit = xeb.XEBWideCircuitInfo(
|
|
68
|
+
wide_circuit=cirq.Circuit.from_moments(
|
|
69
|
+
[
|
|
70
|
+
cirq.Y.on_each(*_PAIRS[0]),
|
|
71
|
+
cirq.Z.on_each(*_PAIRS[1]),
|
|
72
|
+
cirq.X.on_each(*_PAIRS[2]),
|
|
73
|
+
],
|
|
74
|
+
cirq.CircuitOperation(
|
|
75
|
+
cirq.FrozenCircuit(
|
|
76
|
+
cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
|
|
77
|
+
)
|
|
78
|
+
),
|
|
79
|
+
[
|
|
80
|
+
cirq.Z.on_each(*_PAIRS[0]),
|
|
81
|
+
cirq.X.on_each(*_PAIRS[1]),
|
|
82
|
+
cirq.Y.on_each(*_PAIRS[2]),
|
|
83
|
+
],
|
|
84
|
+
),
|
|
85
|
+
pairs=_PAIRS,
|
|
86
|
+
narrow_template_indices=[1, 2, 0],
|
|
87
|
+
)
|
|
88
|
+
sliced_circuit = xeb.XEBWideCircuitInfo(
|
|
89
|
+
wide_circuit=cirq.Circuit.from_moments(
|
|
90
|
+
[
|
|
91
|
+
cirq.Y.on_each(*_PAIRS[0]),
|
|
92
|
+
cirq.Z.on_each(*_PAIRS[1]),
|
|
93
|
+
cirq.X.on_each(*_PAIRS[2]),
|
|
94
|
+
],
|
|
95
|
+
cirq.CircuitOperation(
|
|
96
|
+
cirq.FrozenCircuit(
|
|
97
|
+
cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
|
|
98
|
+
)
|
|
99
|
+
),
|
|
100
|
+
[
|
|
101
|
+
cirq.Z.on_each(*_PAIRS[0]),
|
|
102
|
+
cirq.X.on_each(*_PAIRS[1]),
|
|
103
|
+
cirq.Y.on_each(*_PAIRS[2]),
|
|
104
|
+
],
|
|
105
|
+
[cirq.measure(p, key=str(p)) for p in _PAIRS],
|
|
106
|
+
),
|
|
107
|
+
pairs=_PAIRS,
|
|
108
|
+
narrow_template_indices=[1, 2, 0],
|
|
109
|
+
cycle_depth=1,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
assert wid_circuit.sliced_circuits([1]) == [sliced_circuit]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_create_combination_circuits():
|
|
116
|
+
wide_circuits_info = xeb.create_combination_circuits(
|
|
117
|
+
_CIRCUIT_TEMPLATES,
|
|
118
|
+
[rqcg.CircuitLibraryCombination(layer=None, combinations=[[1, 2, 0]], pairs=_PAIRS)],
|
|
119
|
+
target=cirq.CNOT(*_QUBITS),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
assert wide_circuits_info == [
|
|
123
|
+
xeb.XEBWideCircuitInfo(
|
|
124
|
+
wide_circuit=cirq.Circuit.from_moments(
|
|
125
|
+
[
|
|
126
|
+
cirq.Y.on_each(*_PAIRS[0]),
|
|
127
|
+
cirq.Z.on_each(*_PAIRS[1]),
|
|
128
|
+
cirq.X.on_each(*_PAIRS[2]),
|
|
129
|
+
],
|
|
130
|
+
[cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])],
|
|
131
|
+
[
|
|
132
|
+
cirq.Z.on_each(*_PAIRS[0]),
|
|
133
|
+
cirq.X.on_each(*_PAIRS[1]),
|
|
134
|
+
cirq.Y.on_each(*_PAIRS[2]),
|
|
135
|
+
],
|
|
136
|
+
),
|
|
137
|
+
pairs=_PAIRS,
|
|
138
|
+
narrow_template_indices=[1, 2, 0],
|
|
139
|
+
)
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_create_combination_circuits_with_target_dict():
|
|
144
|
+
wide_circuits_info = xeb.create_combination_circuits(
|
|
145
|
+
_CIRCUIT_TEMPLATES,
|
|
146
|
+
[rqcg.CircuitLibraryCombination(layer=None, combinations=[[1, 2, 0]], pairs=_PAIRS)],
|
|
147
|
+
target={_PAIRS[0]: cirq.CNOT(*_QUBITS), _PAIRS[1]: cirq.CZ(*_QUBITS)},
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Wide circuit is created for the qubit pairs in the intersection between target.keys()
|
|
151
|
+
# and combination.pairs
|
|
152
|
+
assert wide_circuits_info == [
|
|
153
|
+
xeb.XEBWideCircuitInfo(
|
|
154
|
+
wide_circuit=cirq.Circuit.from_moments(
|
|
155
|
+
[cirq.Y.on_each(*_PAIRS[0]), cirq.Z.on_each(*_PAIRS[1])],
|
|
156
|
+
[cirq.CNOT(*_PAIRS[0]), cirq.CZ(*_PAIRS[1])],
|
|
157
|
+
[cirq.Z.on_each(*_PAIRS[0]), cirq.X.on_each(*_PAIRS[1])],
|
|
158
|
+
),
|
|
159
|
+
pairs=_PAIRS,
|
|
160
|
+
narrow_template_indices=[1, 2, 0],
|
|
161
|
+
)
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_simulate_circuit():
|
|
166
|
+
sim = cirq.Simulator(seed=0)
|
|
167
|
+
circuit = cirq.Circuit.from_moments(
|
|
168
|
+
cirq.X.on_each(_QUBITS),
|
|
169
|
+
cirq.CNOT(*_QUBITS),
|
|
170
|
+
cirq.X.on_each(_QUBITS),
|
|
171
|
+
cirq.CNOT(*_QUBITS),
|
|
172
|
+
cirq.X.on_each(_QUBITS),
|
|
173
|
+
cirq.CNOT(*_QUBITS),
|
|
174
|
+
cirq.X.on_each(_QUBITS),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
result = xeb.simulate_circuit(sim, circuit, [1, 3])
|
|
178
|
+
np.testing.assert_allclose(result, [[0, 1, 0, 0], [1, 0, 0, 0]]) # |01> # |00>
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_simulate_circuit_library():
|
|
182
|
+
circuit_templates = [
|
|
183
|
+
cirq.Circuit.from_moments(
|
|
184
|
+
cirq.X.on_each(_QUBITS),
|
|
185
|
+
cirq.CNOT(*_QUBITS),
|
|
186
|
+
cirq.X.on_each(_QUBITS),
|
|
187
|
+
cirq.CNOT(*_QUBITS),
|
|
188
|
+
cirq.X.on_each(_QUBITS),
|
|
189
|
+
cirq.CNOT(*_QUBITS),
|
|
190
|
+
cirq.X.on_each(_QUBITS),
|
|
191
|
+
)
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
result = xeb.simulate_circuit_library(
|
|
195
|
+
circuit_templates=circuit_templates, target_or_dict=cirq.CNOT(*_QUBITS), cycle_depths=(1, 3)
|
|
196
|
+
)
|
|
197
|
+
np.testing.assert_allclose(result, [[[0, 1, 0, 0], [1, 0, 0, 0]]]) # |01> # |00>
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_simulate_circuit_library_with_target_dict():
|
|
201
|
+
circuit_templates = [
|
|
202
|
+
cirq.Circuit.from_moments(
|
|
203
|
+
[cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
|
|
204
|
+
cirq.CNOT(*_QUBITS),
|
|
205
|
+
[cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
|
|
206
|
+
cirq.CNOT(*_QUBITS),
|
|
207
|
+
[cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
|
|
208
|
+
cirq.CNOT(*_QUBITS),
|
|
209
|
+
[cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
|
|
210
|
+
)
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
result = xeb.simulate_circuit_library(
|
|
214
|
+
circuit_templates=circuit_templates,
|
|
215
|
+
target_or_dict={_PAIRS[0]: cirq.CNOT(*_QUBITS), _PAIRS[1]: cirq.CZ(*_QUBITS)},
|
|
216
|
+
cycle_depths=(1, 3),
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# First pair result.
|
|
220
|
+
np.testing.assert_allclose(result[_PAIRS[0]], [[[0.25, 0.25, 0.25, 0.25], [0, 1, 0, 0]]])
|
|
221
|
+
|
|
222
|
+
# Second pair result.
|
|
223
|
+
np.testing.assert_allclose(result[_PAIRS[1]], [[[0, 0, 1, 0], [1, 0, 0, 0]]]) # |10> # |00>
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_sample_all_circuits():
|
|
227
|
+
wide_circuits = [
|
|
228
|
+
cirq.Circuit.from_moments(
|
|
229
|
+
[cirq.Y.on_each(*_PAIRS[0]), cirq.Z.on_each(*_PAIRS[1]), cirq.X.on_each(*_PAIRS[2])],
|
|
230
|
+
cirq.CircuitOperation(
|
|
231
|
+
cirq.FrozenCircuit(
|
|
232
|
+
cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
|
|
233
|
+
)
|
|
234
|
+
),
|
|
235
|
+
[cirq.Z.on_each(*_PAIRS[0]), cirq.X.on_each(*_PAIRS[1]), cirq.Y.on_each(*_PAIRS[2])],
|
|
236
|
+
[cirq.measure(p, key=str(p)) for p in _PAIRS],
|
|
237
|
+
)
|
|
238
|
+
]
|
|
239
|
+
result = xeb.sample_all_circuits(cirq.Simulator(seed=0), circuits=wide_circuits, repetitions=10)
|
|
240
|
+
assert len(result) == len(wide_circuits)
|
|
241
|
+
assert result[0].keys() == {str(p) for p in _PAIRS}
|
|
242
|
+
np.testing.assert_allclose(
|
|
243
|
+
result[0]['(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1))'], [0, 0, 1, 0]
|
|
244
|
+
) # |10>
|
|
245
|
+
np.testing.assert_allclose(
|
|
246
|
+
result[0]['(cirq.GridQubit(0, 2), cirq.GridQubit(0, 3))'], [0, 0, 0, 1]
|
|
247
|
+
) # |11>
|
|
248
|
+
np.testing.assert_allclose(
|
|
249
|
+
result[0]['(cirq.GridQubit(0, 4), cirq.GridQubit(0, 5))'], [0, 1, 0, 0]
|
|
250
|
+
) # |01>
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_estimate_fidelities():
|
|
254
|
+
sampling_result = [{str(_PAIRS[0]): np.array([0.15, 0.15, 0.35, 0.35])}]
|
|
255
|
+
|
|
256
|
+
simulation_results = [[np.array([0.1, 0.2, 0.3, 0.4])]]
|
|
257
|
+
|
|
258
|
+
result = xeb.estimate_fidelities(
|
|
259
|
+
sampling_results=sampling_result,
|
|
260
|
+
simulation_results=simulation_results,
|
|
261
|
+
cycle_depths=(1,),
|
|
262
|
+
num_templates=1,
|
|
263
|
+
pairs=_PAIRS[:1],
|
|
264
|
+
wide_circuits_info=[
|
|
265
|
+
xeb.XEBWideCircuitInfo(
|
|
266
|
+
wide_circuit=cirq.Circuit.from_moments(
|
|
267
|
+
[cirq.Y.on_each(*_PAIRS[0])],
|
|
268
|
+
cirq.CNOT(*_PAIRS[0]),
|
|
269
|
+
[cirq.Z.on_each(*_PAIRS[0])],
|
|
270
|
+
cirq.measure(_PAIRS[0], key=str(_PAIRS[0])),
|
|
271
|
+
),
|
|
272
|
+
cycle_depth=1,
|
|
273
|
+
narrow_template_indices=(0,),
|
|
274
|
+
pairs=_PAIRS[:1],
|
|
275
|
+
)
|
|
276
|
+
],
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
assert result == [
|
|
280
|
+
xeb.XEBFidelity(pair=_PAIRS[0], cycle_depth=1, fidelity=pytest.approx(0.785, abs=2e-4))
|
|
281
|
+
]
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def test_estimate_fidelities_with_dict_target():
|
|
285
|
+
sampling_result = [{str(_PAIRS[0]): np.array([0.15, 0.15, 0.35, 0.35])}]
|
|
286
|
+
|
|
287
|
+
simulation_results = {_PAIRS[0]: [[np.array([0.1, 0.2, 0.3, 0.4])]]}
|
|
288
|
+
|
|
289
|
+
result = xeb.estimate_fidelities(
|
|
290
|
+
sampling_results=sampling_result,
|
|
291
|
+
simulation_results=simulation_results,
|
|
292
|
+
cycle_depths=(1,),
|
|
293
|
+
num_templates=1,
|
|
294
|
+
pairs=_PAIRS[:1],
|
|
295
|
+
wide_circuits_info=[
|
|
296
|
+
xeb.XEBWideCircuitInfo(
|
|
297
|
+
wide_circuit=cirq.Circuit.from_moments(
|
|
298
|
+
[cirq.Y.on_each(*_PAIRS[0])],
|
|
299
|
+
cirq.CNOT(*_PAIRS[0]),
|
|
300
|
+
[cirq.Z.on_each(*_PAIRS[0])],
|
|
301
|
+
cirq.measure(_PAIRS[0], key=str(_PAIRS[0])),
|
|
302
|
+
),
|
|
303
|
+
cycle_depth=1,
|
|
304
|
+
narrow_template_indices=(0,),
|
|
305
|
+
pairs=_PAIRS[:1],
|
|
306
|
+
)
|
|
307
|
+
],
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
assert result == [
|
|
311
|
+
xeb.XEBFidelity(pair=_PAIRS[0], cycle_depth=1, fidelity=pytest.approx(0.785, abs=2e-4))
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _assert_fidelities_approx_equal(fids, expected: float, atol: float):
|
|
316
|
+
fids = np.asarray(fids).tolist()
|
|
317
|
+
fids.sort(reverse=True)
|
|
318
|
+
fids.pop() # discard smallest to make the test robust to randomness
|
|
319
|
+
np.testing.assert_allclose(fids, expected, atol=atol)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@pytest.mark.parametrize('target', [cirq.CZ, cirq.Circuit(cirq.CZ(*_QUBITS)), cirq.CZ(*_QUBITS)])
|
|
323
|
+
@pytest.mark.parametrize('pairs', [_PAIRS[:1], _PAIRS[:2]])
|
|
324
|
+
def test_parallel_two_qubit_xeb(target, pairs):
|
|
325
|
+
sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
|
|
326
|
+
result = xeb.parallel_two_qubit_xeb(
|
|
327
|
+
sampler=sampler,
|
|
328
|
+
target=target,
|
|
329
|
+
pairs=pairs,
|
|
330
|
+
parameters=xeb.XEBParameters(
|
|
331
|
+
n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
|
|
332
|
+
),
|
|
333
|
+
)
|
|
334
|
+
_assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class ExampleDevice(cirq.Device):
|
|
338
|
+
@property
|
|
339
|
+
def metadata(self) -> cirq.DeviceMetadata:
|
|
340
|
+
qubits = cirq.GridQubit.rect(3, 2, 4, 3)
|
|
341
|
+
graph = nx.Graph(
|
|
342
|
+
pair
|
|
343
|
+
for pair in itertools.combinations(qubits, 2)
|
|
344
|
+
if abs(pair[0].row - pair[1].row) + abs(pair[0].col - pair[1].col) == 1
|
|
345
|
+
)
|
|
346
|
+
return cirq.DeviceMetadata(qubits, graph)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class ExampleProcessor:
|
|
350
|
+
def get_device(self):
|
|
351
|
+
return ExampleDevice()
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class DensityMatrixSimulatorWithProcessor(cirq.DensityMatrixSimulator):
|
|
355
|
+
@property
|
|
356
|
+
def processor(self):
|
|
357
|
+
return ExampleProcessor()
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def test_parallel_two_qubit_xeb_with_device():
|
|
361
|
+
target = cirq.CZ
|
|
362
|
+
sampler = DensityMatrixSimulatorWithProcessor(noise=cirq.depolarize(0.03), seed=0)
|
|
363
|
+
result = xeb.parallel_two_qubit_xeb(
|
|
364
|
+
sampler=sampler,
|
|
365
|
+
target=target,
|
|
366
|
+
parameters=xeb.XEBParameters(
|
|
367
|
+
n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
|
|
368
|
+
),
|
|
369
|
+
)
|
|
370
|
+
_assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
|
|
371
|
+
qubits = cirq.GridQubit.rect(3, 2, 4, 3)
|
|
372
|
+
pairs = tuple(
|
|
373
|
+
pair
|
|
374
|
+
for pair in itertools.combinations(qubits, 2)
|
|
375
|
+
if abs(pair[0].row - pair[1].row) + abs(pair[0].col - pair[1].col) == 1
|
|
376
|
+
and pair[0] < pair[1]
|
|
377
|
+
)
|
|
378
|
+
assert result.all_qubit_pairs == pairs
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def test_parallel_two_qubit_xeb_with_dict_target():
|
|
382
|
+
target = {p: cirq.Circuit(cirq.CZ(*_QUBITS)) for p in _PAIRS[:2]}
|
|
383
|
+
target[_PAIRS[2]] = cirq.CZ(*_QUBITS)
|
|
384
|
+
sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
|
|
385
|
+
result = xeb.parallel_two_qubit_xeb(
|
|
386
|
+
sampler=sampler,
|
|
387
|
+
target=target,
|
|
388
|
+
parameters=xeb.XEBParameters(
|
|
389
|
+
n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
|
|
390
|
+
),
|
|
391
|
+
)
|
|
392
|
+
_assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
|
|
393
|
+
assert result.all_qubit_pairs == _PAIRS
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def test_parallel_two_qubit_xeb_with_ideal_target():
|
|
397
|
+
target = {p: cirq.Circuit(cirq.CZ(*_QUBITS)) for p in _PAIRS[:2]}
|
|
398
|
+
target[_PAIRS[2]] = cirq.CZ(*_QUBITS)
|
|
399
|
+
sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
|
|
400
|
+
result = xeb.parallel_two_qubit_xeb(
|
|
401
|
+
sampler=sampler,
|
|
402
|
+
target=target,
|
|
403
|
+
ideal_target=cirq.CZ,
|
|
404
|
+
parameters=xeb.XEBParameters(
|
|
405
|
+
n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
|
|
406
|
+
),
|
|
407
|
+
)
|
|
408
|
+
_assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
|
|
409
|
+
assert result.all_qubit_pairs == _PAIRS
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
@pytest.fixture
|
|
413
|
+
def threading_pool() -> Iterator[futures.Executor]:
|
|
414
|
+
with futures.ThreadPoolExecutor(1) as pool:
|
|
415
|
+
yield pool
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def test_parallel_two_qubit_xeb_with_dict_target_and_pool(threading_pool):
|
|
419
|
+
target = {p: cirq.Circuit(cirq.CZ(*_QUBITS)) for p in _PAIRS}
|
|
420
|
+
sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
|
|
421
|
+
result = xeb.parallel_two_qubit_xeb(
|
|
422
|
+
sampler=sampler,
|
|
423
|
+
target=target,
|
|
424
|
+
parameters=xeb.XEBParameters(
|
|
425
|
+
n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
|
|
426
|
+
),
|
|
427
|
+
pool=threading_pool,
|
|
428
|
+
)
|
|
429
|
+
_assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
|
|
430
|
+
assert result.all_qubit_pairs == _PAIRS
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def test_parallel_two_qubit_xeb_with_invalid_input_raises():
|
|
434
|
+
with pytest.raises(AssertionError):
|
|
435
|
+
_ = xeb.parallel_two_qubit_xeb(
|
|
436
|
+
sampler=cirq.Simulator(seed=0), target={_PAIRS[0]: cirq.CZ}, pairs=_PAIRS
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
with pytest.raises(AssertionError):
|
|
440
|
+
_ = xeb.parallel_two_qubit_xeb(
|
|
441
|
+
sampler=cirq.Simulator(seed=0),
|
|
442
|
+
target=cirq.CZ,
|
|
443
|
+
ideal_target={_PAIRS[0]: cirq.CZ},
|
|
444
|
+
pairs=_PAIRS,
|
|
445
|
+
)
|
|
@@ -107,6 +107,10 @@ class TwoQubitXEBResult:
|
|
|
107
107
|
|
|
108
108
|
@functools.cached_property
|
|
109
109
|
def _qubit_pair_map(self) -> Dict[Tuple[cirq.GridQubit, cirq.GridQubit], int]:
|
|
110
|
+
if isinstance(self.fidelities.index[0][0], ops.Qid):
|
|
111
|
+
return {
|
|
112
|
+
(min(q0, q1), max(q0, q1)): i for i, (q0, q1) in enumerate(self.fidelities.index)
|
|
113
|
+
}
|
|
110
114
|
return {
|
|
111
115
|
(min(q0, q1), max(q0, q1)): i
|
|
112
116
|
for i, (_, _, (q0, q1)) in enumerate(self.fidelities.index)
|
{cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cirq-core
|
|
3
|
-
Version: 1.6.0.
|
|
3
|
+
Version: 1.6.0.dev20250505215959
|
|
4
4
|
Summary: A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
|
|
5
5
|
Home-page: http://github.com/quantumlib/cirq
|
|
6
6
|
Author: The Cirq Developers
|
{cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/RECORD
RENAMED
|
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=0m3sYIyxRNv9jvAo6rzJ-cnbpny3KGnAByrbU7bApgQ,34720
|
|
|
4
4
|
cirq/_doc.py,sha256=yDyWUD_2JDS0gShfGRb-rdqRt9-WeL7DhkqX7np0Nko,2879
|
|
5
5
|
cirq/_import.py,sha256=cfocxtT1BJ4HkfZ-VO8YyIhPP-xfqHDkLrzz6eeO5U0,8421
|
|
6
6
|
cirq/_import_test.py,sha256=6K_v0riZJXOXUphHNkGA8MY-JcmGlezFaGmvrNhm3OQ,1015
|
|
7
|
-
cirq/_version.py,sha256=
|
|
8
|
-
cirq/_version_test.py,sha256=
|
|
7
|
+
cirq/_version.py,sha256=fyp0MSaaj4W0ioi69LzAGW42XMYSl0Qpl1zS_dI0_zM,1206
|
|
8
|
+
cirq/_version_test.py,sha256=9i8iz1L6DT_KAgYd2kflJzvQW3ZEQwx7a783BQbCW5A,147
|
|
9
9
|
cirq/conftest.py,sha256=X7yLFL8GLhg2CjPw0hp5e_dGASfvHx1-QT03aUbhKJw,1168
|
|
10
10
|
cirq/json_resolver_cache.py,sha256=-4KqEEYb6aps-seafnFTHTp3SZc0D8mr4O-pCKIajn8,13653
|
|
11
11
|
cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
|
|
@@ -199,7 +199,7 @@ cirq/experiments/t1_decay_experiment.py,sha256=IA108IQ9KEcZilEwu_famESZmdMaxJAUK
|
|
|
199
199
|
cirq/experiments/t1_decay_experiment_test.py,sha256=LauXCkcLNxrmM5gNCT5RSWaRQ8OnlV8sCZZ3CBrLjpI,9138
|
|
200
200
|
cirq/experiments/t2_decay_experiment.py,sha256=RM8KbXmEWfLu865QksIZPCL9h37VQLUKoSTb1Uq_QnI,19176
|
|
201
201
|
cirq/experiments/t2_decay_experiment_test.py,sha256=dJhtdqgH2majCQ-sstyjog75wkzkzHrHVsQrGpuYXfE,15030
|
|
202
|
-
cirq/experiments/two_qubit_xeb.py,sha256=
|
|
202
|
+
cirq/experiments/two_qubit_xeb.py,sha256=loImf3M7UDPyAhWsVwYn7xNSumBCXZ5LRsgCy6IaaWE,22840
|
|
203
203
|
cirq/experiments/two_qubit_xeb_test.py,sha256=Enf11AZ91lr8Z4-A32xp8wkqU8TnhK0NXind5_ALMwA,10676
|
|
204
204
|
cirq/experiments/xeb_fitting.py,sha256=UEPNyjpjoGUNTdQfdRUnPe_Yvdc18GewYN1FdJjWoYg,30401
|
|
205
205
|
cirq/experiments/xeb_fitting_test.py,sha256=q4d-6dPnnN_E9Qw9laip-opsfhdftJuY3QZfEh_u7Wo,15483
|
|
@@ -209,6 +209,9 @@ cirq/experiments/xeb_simulation.py,sha256=w-4TI8KexpI6zJTS8PHmcWWWHfyRcbJYC4Ifin
|
|
|
209
209
|
cirq/experiments/xeb_simulation_test.py,sha256=2ETf99fb0b76w9NjH8pGHTVLLmQE6CIv0yzlCB6WbQ8,5646
|
|
210
210
|
cirq/experiments/z_phase_calibration.py,sha256=EPblzpLl3JXRkmXgD9GS0R7RKf4zVVYAHhGW0c-HZ6E,15128
|
|
211
211
|
cirq/experiments/z_phase_calibration_test.py,sha256=gyZgldzM0G8bRHp33Jk_eYaYqO2WsfFky_GDtElRpzo,9012
|
|
212
|
+
cirq/experiments/benchmarking/__init__.py,sha256=2jMiP2dmQrH9Z2eKC8koaQqZcOi_-ziuer-aHkLm_bU,709
|
|
213
|
+
cirq/experiments/benchmarking/parallel_xeb.py,sha256=3RyTTnHpqV-8B-TmDS7jBnaLu6GFLKPUFDtOOnMUlwQ,26015
|
|
214
|
+
cirq/experiments/benchmarking/parallel_xeb_test.py,sha256=_puxm9O-OMVMraVJuS2ai3elWrgMObIXR8wV3DnqLJs,15831
|
|
212
215
|
cirq/interop/__init__.py,sha256=Xt1xU9UegP_jBNa9xaeOFSgtC0lYb_HNHq4hQQ0J20k,784
|
|
213
216
|
cirq/interop/quirk/__init__.py,sha256=W11jqaExSgvoUkjM_d0Kik4R8bqETF9Ezo27CDEB3iw,1237
|
|
214
217
|
cirq/interop/quirk/url_to_circuit.py,sha256=VYFm_QSkpgug568oyF6LerZbFDkes3e5dR6YSREvuSQ,14226
|
|
@@ -1209,8 +1212,8 @@ cirq/work/sampler.py,sha256=sW0RhIelGABAKbqTM58shwyyCPgf86JIv9IGdJe__js,19186
|
|
|
1209
1212
|
cirq/work/sampler_test.py,sha256=mdk1J-WrvbPUYhY41VhWf9_te4DnXr_XMPcugWwc4-I,13281
|
|
1210
1213
|
cirq/work/zeros_sampler.py,sha256=8_Ne6dBkDANtTZuql7Eb0Qg_E_P3-_gu-ybFzxTbKAQ,2356
|
|
1211
1214
|
cirq/work/zeros_sampler_test.py,sha256=JIkpBBFPJe5Ba4142vzogyWyboG1Q1ZAm0UVGgOoZn8,3279
|
|
1212
|
-
cirq_core-1.6.0.
|
|
1213
|
-
cirq_core-1.6.0.
|
|
1214
|
-
cirq_core-1.6.0.
|
|
1215
|
-
cirq_core-1.6.0.
|
|
1216
|
-
cirq_core-1.6.0.
|
|
1215
|
+
cirq_core-1.6.0.dev20250505215959.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
1216
|
+
cirq_core-1.6.0.dev20250505215959.dist-info/METADATA,sha256=Yl8UG4YVGZ3QJLGvWwC5zvMnSXtK5tpS-ChJlB-TJOU,4908
|
|
1217
|
+
cirq_core-1.6.0.dev20250505215959.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
|
1218
|
+
cirq_core-1.6.0.dev20250505215959.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
|
|
1219
|
+
cirq_core-1.6.0.dev20250505215959.dist-info/RECORD,,
|
{cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250505215959.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|