cirq-core 1.6.0.dev20250416035400__py3-none-any.whl → 1.6.0.dev20250417204649__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/devices/noise_model_test.py +3 -1
- cirq/devices/noise_properties.py +6 -4
- cirq/devices/noise_utils.py +8 -6
- cirq/devices/superconducting_qubits_noise_properties.py +10 -9
- cirq/devices/thermal_noise_model.py +12 -12
- cirq/devices/unconstrained_device.py +3 -1
- cirq/experiments/n_qubit_tomography.py +15 -12
- cirq/experiments/qubit_characterizations.py +34 -39
- cirq/experiments/random_quantum_circuit_generation.py +38 -38
- cirq/experiments/random_quantum_circuit_generation_test.py +7 -4
- cirq/experiments/readout_confusion_matrix.py +17 -15
- cirq/experiments/single_qubit_readout_calibration.py +9 -5
- cirq/experiments/single_qubit_readout_calibration_test.py +5 -2
- cirq/experiments/t1_decay_experiment.py +7 -5
- cirq/experiments/t2_decay_experiment.py +10 -7
- cirq/experiments/two_qubit_xeb.py +42 -43
- cirq/experiments/two_qubit_xeb_test.py +1 -1
- cirq/experiments/xeb_fitting.py +25 -21
- cirq/experiments/xeb_sampling.py +18 -14
- cirq/experiments/xeb_simulation.py +11 -7
- cirq/experiments/xeb_simulation_test.py +3 -3
- cirq/experiments/z_phase_calibration.py +27 -24
- cirq/experiments/z_phase_calibration_test.py +1 -4
- cirq/interop/quirk/cells/arithmetic_cells.py +11 -10
- cirq/interop/quirk/cells/cell.py +18 -15
- cirq/interop/quirk/cells/composite_cell.py +8 -8
- cirq/interop/quirk/cells/control_cells.py +14 -14
- cirq/interop/quirk/cells/frequency_space_cells.py +4 -3
- cirq/interop/quirk/cells/input_cells.py +6 -4
- cirq/interop/quirk/cells/input_rotation_cells.py +14 -12
- cirq/interop/quirk/cells/measurement_cells.py +4 -1
- cirq/interop/quirk/cells/qubit_permutation_cells.py +3 -1
- cirq/interop/quirk/cells/scalar_cells.py +4 -1
- cirq/interop/quirk/cells/single_qubit_rotation_cells.py +5 -2
- cirq/interop/quirk/cells/swap_cell.py +7 -5
- cirq/interop/quirk/cells/testing.py +1 -1
- cirq/interop/quirk/url_to_circuit.py +11 -8
- cirq/json_resolver_cache.py +5 -3
- cirq/linalg/decompositions.py +5 -4
- cirq/linalg/decompositions_test.py +1 -1
- cirq/linalg/operator_spaces.py +8 -8
- cirq/ops/arithmetic_operation.py +4 -2
- cirq/ops/boolean_hamiltonian.py +7 -6
- cirq/ops/classically_controlled_operation.py +23 -20
- cirq/ops/clifford_gate.py +43 -47
- cirq/ops/common_channels.py +16 -14
- cirq/ops/common_gates.py +49 -67
- cirq/ops/control_values.py +12 -15
- cirq/ops/controlled_gate.py +15 -17
- cirq/ops/controlled_operation.py +17 -15
- cirq/study/resolver.py +1 -1
- {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/RECORD +58 -58
- {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""Provides functions for running and analyzing two-qubit XEB experiments."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
16
19
|
import functools
|
|
17
20
|
import itertools
|
|
18
21
|
from dataclasses import dataclass
|
|
@@ -45,22 +48,22 @@ if TYPE_CHECKING:
|
|
|
45
48
|
import cirq
|
|
46
49
|
|
|
47
50
|
|
|
48
|
-
def _grid_qubits_for_sampler(sampler:
|
|
51
|
+
def _grid_qubits_for_sampler(sampler: cirq.Sampler) -> Optional[Sequence[cirq.GridQubit]]:
|
|
49
52
|
if hasattr(sampler, 'processor'):
|
|
50
53
|
device = sampler.processor.get_device()
|
|
51
54
|
return sorted(device.metadata.qubit_set)
|
|
52
55
|
return None
|
|
53
56
|
|
|
54
57
|
|
|
55
|
-
def _manhattan_distance(qubit1:
|
|
58
|
+
def _manhattan_distance(qubit1: cirq.GridQubit, qubit2: cirq.GridQubit) -> int:
|
|
56
59
|
return abs(qubit1.row - qubit2.row) + abs(qubit1.col - qubit2.col)
|
|
57
60
|
|
|
58
61
|
|
|
59
62
|
def qubits_and_pairs(
|
|
60
|
-
sampler:
|
|
61
|
-
qubits: Optional[Sequence[
|
|
62
|
-
pairs: Optional[Sequence[tuple[
|
|
63
|
-
) -> Tuple[Sequence[
|
|
63
|
+
sampler: cirq.Sampler,
|
|
64
|
+
qubits: Optional[Sequence[cirq.GridQubit]] = None,
|
|
65
|
+
pairs: Optional[Sequence[tuple[cirq.GridQubit, cirq.GridQubit]]] = None,
|
|
66
|
+
) -> Tuple[Sequence[cirq.GridQubit], Sequence[tuple[cirq.GridQubit, cirq.GridQubit]]]:
|
|
64
67
|
"""Extract qubits and pairs from sampler.
|
|
65
68
|
|
|
66
69
|
|
|
@@ -103,14 +106,14 @@ class TwoQubitXEBResult:
|
|
|
103
106
|
fidelities: pd.DataFrame
|
|
104
107
|
|
|
105
108
|
@functools.cached_property
|
|
106
|
-
def _qubit_pair_map(self) -> Dict[Tuple[
|
|
109
|
+
def _qubit_pair_map(self) -> Dict[Tuple[cirq.GridQubit, cirq.GridQubit], int]:
|
|
107
110
|
return {
|
|
108
111
|
(min(q0, q1), max(q0, q1)): i
|
|
109
112
|
for i, (_, _, (q0, q1)) in enumerate(self.fidelities.index)
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
@functools.cached_property
|
|
113
|
-
def all_qubit_pairs(self) -> Tuple[Tuple[
|
|
116
|
+
def all_qubit_pairs(self) -> Tuple[Tuple[cirq.GridQubit, cirq.GridQubit], ...]:
|
|
114
117
|
return tuple(sorted(self._qubit_pair_map.keys()))
|
|
115
118
|
|
|
116
119
|
def plot_heatmap(self, ax: Optional[plt.Axes] = None, **plot_kwargs) -> plt.Axes:
|
|
@@ -127,7 +130,7 @@ class TwoQubitXEBResult:
|
|
|
127
130
|
show_plot = not ax
|
|
128
131
|
if not isinstance(ax, plt.Axes):
|
|
129
132
|
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
|
|
130
|
-
heatmap_data: Dict[Tuple[
|
|
133
|
+
heatmap_data: Dict[Tuple[cirq.GridQubit, ...], float] = {
|
|
131
134
|
pair: self.xeb_error(*pair) for pair in self.all_qubit_pairs
|
|
132
135
|
}
|
|
133
136
|
|
|
@@ -139,11 +142,7 @@ class TwoQubitXEBResult:
|
|
|
139
142
|
return ax
|
|
140
143
|
|
|
141
144
|
def plot_fitted_exponential(
|
|
142
|
-
self,
|
|
143
|
-
q0: 'cirq.GridQubit',
|
|
144
|
-
q1: 'cirq.GridQubit',
|
|
145
|
-
ax: Optional[plt.Axes] = None,
|
|
146
|
-
**plot_kwargs,
|
|
145
|
+
self, q0: cirq.GridQubit, q1: cirq.GridQubit, ax: Optional[plt.Axes] = None, **plot_kwargs
|
|
147
146
|
) -> plt.Axes:
|
|
148
147
|
"""plot the fitted model to for xeb error of a qubit pair.
|
|
149
148
|
|
|
@@ -185,17 +184,17 @@ class TwoQubitXEBResult:
|
|
|
185
184
|
q0, q1 = q1, q0
|
|
186
185
|
return self.fidelities.iloc[self._qubit_pair_map[(q0, q1)]]
|
|
187
186
|
|
|
188
|
-
def xeb_fidelity(self, q0:
|
|
187
|
+
def xeb_fidelity(self, q0: cirq.GridQubit, q1: cirq.GridQubit) -> float:
|
|
189
188
|
"""Return the XEB fidelity of a qubit pair."""
|
|
190
189
|
return noise_utils.decay_constant_to_xeb_fidelity(
|
|
191
190
|
self._record(q0, q1).layer_fid, num_qubits=2
|
|
192
191
|
)
|
|
193
192
|
|
|
194
|
-
def xeb_error(self, q0:
|
|
193
|
+
def xeb_error(self, q0: cirq.GridQubit, q1: cirq.GridQubit) -> float:
|
|
195
194
|
"""Return the XEB error of a qubit pair."""
|
|
196
195
|
return 1 - self.xeb_fidelity(q0, q1)
|
|
197
196
|
|
|
198
|
-
def all_errors(self) -> Dict[Tuple[
|
|
197
|
+
def all_errors(self) -> Dict[Tuple[cirq.GridQubit, cirq.GridQubit], float]:
|
|
199
198
|
"""Return the XEB error of all qubit pairs."""
|
|
200
199
|
return {(q0, q1): self.xeb_error(q0, q1) for q0, q1 in self.all_qubit_pairs}
|
|
201
200
|
|
|
@@ -219,7 +218,7 @@ class TwoQubitXEBResult:
|
|
|
219
218
|
return ax
|
|
220
219
|
|
|
221
220
|
@cached_method
|
|
222
|
-
def pauli_error(self) -> Dict[Tuple[
|
|
221
|
+
def pauli_error(self) -> Dict[Tuple[cirq.GridQubit, cirq.GridQubit], float]:
|
|
223
222
|
"""Return the Pauli error of all qubit pairs."""
|
|
224
223
|
return {
|
|
225
224
|
pair: noise_utils.decay_constant_to_pauli_error(
|
|
@@ -242,33 +241,33 @@ class InferredXEBResult:
|
|
|
242
241
|
xeb_result: TwoQubitXEBResult
|
|
243
242
|
|
|
244
243
|
@property
|
|
245
|
-
def all_qubit_pairs(self) -> Sequence[Tuple[
|
|
244
|
+
def all_qubit_pairs(self) -> Sequence[Tuple[cirq.GridQubit, cirq.GridQubit]]:
|
|
246
245
|
return self.xeb_result.all_qubit_pairs
|
|
247
246
|
|
|
248
247
|
@cached_method
|
|
249
|
-
def single_qubit_pauli_error(self) -> Mapping[
|
|
248
|
+
def single_qubit_pauli_error(self) -> Mapping[cirq.Qid, float]:
|
|
250
249
|
"""Return the single-qubit Pauli error for all qubits (RB results)."""
|
|
251
250
|
return self.rb_result.pauli_error()
|
|
252
251
|
|
|
253
252
|
@cached_method
|
|
254
|
-
def two_qubit_pauli_error(self) -> Mapping[Tuple[
|
|
253
|
+
def two_qubit_pauli_error(self) -> Mapping[Tuple[cirq.GridQubit, cirq.GridQubit], float]:
|
|
255
254
|
"""Return the two-qubit Pauli error for all pairs."""
|
|
256
255
|
return MappingProxyType(self.xeb_result.pauli_error())
|
|
257
256
|
|
|
258
257
|
@cached_method
|
|
259
|
-
def inferred_pauli_error(self) -> Mapping[Tuple[
|
|
258
|
+
def inferred_pauli_error(self) -> Mapping[Tuple[cirq.GridQubit, cirq.GridQubit], float]:
|
|
260
259
|
"""Return the inferred Pauli error for all pairs."""
|
|
261
260
|
single_q_paulis = self.rb_result.pauli_error()
|
|
262
261
|
xeb = self.xeb_result.pauli_error()
|
|
263
262
|
|
|
264
|
-
def _pauli_error(q0:
|
|
263
|
+
def _pauli_error(q0: cirq.GridQubit, q1: cirq.GridQubit) -> float:
|
|
265
264
|
q0, q1 = sorted([q0, q1])
|
|
266
265
|
return xeb[(q0, q1)] - single_q_paulis[q0] - single_q_paulis[q1]
|
|
267
266
|
|
|
268
267
|
return MappingProxyType({pair: _pauli_error(*pair) for pair in self.all_qubit_pairs})
|
|
269
268
|
|
|
270
269
|
@cached_method
|
|
271
|
-
def inferred_decay_constant(self) -> Mapping[Tuple[
|
|
270
|
+
def inferred_decay_constant(self) -> Mapping[Tuple[cirq.GridQubit, cirq.GridQubit], float]:
|
|
272
271
|
"""Return the inferred decay constant for all pairs."""
|
|
273
272
|
return MappingProxyType(
|
|
274
273
|
{
|
|
@@ -278,7 +277,7 @@ class InferredXEBResult:
|
|
|
278
277
|
)
|
|
279
278
|
|
|
280
279
|
@cached_method
|
|
281
|
-
def inferred_xeb_error(self) -> Mapping[Tuple[
|
|
280
|
+
def inferred_xeb_error(self) -> Mapping[Tuple[cirq.GridQubit, cirq.GridQubit], float]:
|
|
282
281
|
"""Return the inferred XEB error for all pairs."""
|
|
283
282
|
return MappingProxyType(
|
|
284
283
|
{
|
|
@@ -289,7 +288,7 @@ class InferredXEBResult:
|
|
|
289
288
|
|
|
290
289
|
def _target_errors(
|
|
291
290
|
self, target_error: str
|
|
292
|
-
) -> Mapping[Tuple[
|
|
291
|
+
) -> Mapping[Tuple[cirq.GridQubit, cirq.GridQubit], float]:
|
|
293
292
|
"""Returns requested error.
|
|
294
293
|
|
|
295
294
|
The requested error must be one of 'pauli', 'decay_constant', or 'xeb'.
|
|
@@ -393,21 +392,21 @@ class InferredXEBResult:
|
|
|
393
392
|
|
|
394
393
|
|
|
395
394
|
def parallel_xeb_workflow(
|
|
396
|
-
sampler:
|
|
397
|
-
qubits: Optional[Sequence[
|
|
398
|
-
entangling_gate:
|
|
395
|
+
sampler: cirq.Sampler,
|
|
396
|
+
qubits: Optional[Sequence[cirq.GridQubit]] = None,
|
|
397
|
+
entangling_gate: cirq.Gate = ops.CZ,
|
|
399
398
|
n_repetitions: int = 10**4,
|
|
400
399
|
n_combinations: int = 10,
|
|
401
400
|
n_circuits: int = 20,
|
|
402
401
|
cycle_depths: Sequence[int] = (5, 25, 50, 100, 200, 300),
|
|
403
|
-
random_state:
|
|
402
|
+
random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None,
|
|
404
403
|
ax: Optional[plt.Axes] = None,
|
|
405
|
-
pairs: Optional[Sequence[tuple[
|
|
406
|
-
pool: Optional[
|
|
404
|
+
pairs: Optional[Sequence[tuple[cirq.GridQubit, cirq.GridQubit]]] = None,
|
|
405
|
+
pool: Optional[multiprocessing.pool.Pool] = None,
|
|
407
406
|
batch_size: int = 9,
|
|
408
407
|
tags: Sequence[Any] = (),
|
|
409
408
|
**plot_kwargs,
|
|
410
|
-
) -> Tuple[pd.DataFrame, Sequence[
|
|
409
|
+
) -> Tuple[pd.DataFrame, Sequence[cirq.Circuit], pd.DataFrame]:
|
|
411
410
|
"""A utility method that runs the full XEB workflow.
|
|
412
411
|
|
|
413
412
|
Args:
|
|
@@ -483,16 +482,16 @@ def parallel_xeb_workflow(
|
|
|
483
482
|
|
|
484
483
|
|
|
485
484
|
def parallel_two_qubit_xeb(
|
|
486
|
-
sampler:
|
|
487
|
-
qubits: Optional[Sequence[
|
|
488
|
-
entangling_gate:
|
|
485
|
+
sampler: cirq.Sampler,
|
|
486
|
+
qubits: Optional[Sequence[cirq.GridQubit]] = None,
|
|
487
|
+
entangling_gate: cirq.Gate = ops.CZ,
|
|
489
488
|
n_repetitions: int = 10**4,
|
|
490
489
|
n_combinations: int = 10,
|
|
491
490
|
n_circuits: int = 20,
|
|
492
491
|
cycle_depths: Sequence[int] = (5, 25, 50, 100, 200, 300),
|
|
493
|
-
random_state:
|
|
492
|
+
random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None,
|
|
494
493
|
ax: Optional[plt.Axes] = None,
|
|
495
|
-
pairs: Optional[Sequence[tuple[
|
|
494
|
+
pairs: Optional[Sequence[tuple[cirq.GridQubit, cirq.GridQubit]]] = None,
|
|
496
495
|
batch_size: int = 9,
|
|
497
496
|
tags: Sequence[Any] = (),
|
|
498
497
|
**plot_kwargs,
|
|
@@ -540,18 +539,18 @@ def parallel_two_qubit_xeb(
|
|
|
540
539
|
|
|
541
540
|
|
|
542
541
|
def run_rb_and_xeb(
|
|
543
|
-
sampler:
|
|
544
|
-
qubits: Optional[Sequence[
|
|
542
|
+
sampler: cirq.Sampler,
|
|
543
|
+
qubits: Optional[Sequence[cirq.GridQubit]] = None,
|
|
545
544
|
repetitions: int = 10**3,
|
|
546
545
|
num_circuits: int = 20,
|
|
547
546
|
num_clifford_range: Sequence[int] = tuple(
|
|
548
547
|
np.logspace(np.log10(5), np.log10(1000), 5, dtype=int)
|
|
549
548
|
),
|
|
550
|
-
entangling_gate:
|
|
549
|
+
entangling_gate: cirq.Gate = ops.CZ,
|
|
551
550
|
depths_xeb: Sequence[int] = (5, 25, 50, 100, 200, 300),
|
|
552
551
|
xeb_combinations: int = 10,
|
|
553
|
-
random_state:
|
|
554
|
-
pairs: Optional[Sequence[tuple[
|
|
552
|
+
random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None,
|
|
553
|
+
pairs: Optional[Sequence[tuple[cirq.GridQubit, cirq.GridQubit]]] = None,
|
|
555
554
|
batch_size: int = 9,
|
|
556
555
|
tags: Sequence[Any] = (),
|
|
557
556
|
) -> InferredXEBResult:
|
|
@@ -26,7 +26,7 @@ import cirq
|
|
|
26
26
|
from cirq.experiments.qubit_characterizations import ParallelRandomizedBenchmarkingResult
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
def _manhattan_distance(qubit1:
|
|
29
|
+
def _manhattan_distance(qubit1: cirq.GridQubit, qubit2: cirq.GridQubit) -> int:
|
|
30
30
|
return abs(qubit1.row - qubit2.row) + abs(qubit1.col - qubit2.col)
|
|
31
31
|
|
|
32
32
|
|
cirq/experiments/xeb_fitting.py
CHANGED
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
|
|
14
15
|
"""Estimation of fidelity associated with experimental circuit executions."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
15
19
|
import dataclasses
|
|
16
20
|
from abc import ABC, abstractmethod
|
|
17
21
|
from typing import Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING
|
|
@@ -41,10 +45,10 @@ THETA_SYMBOL, ZETA_SYMBOL, CHI_SYMBOL, GAMMA_SYMBOL, PHI_SYMBOL = sympy.symbols(
|
|
|
41
45
|
|
|
42
46
|
def benchmark_2q_xeb_fidelities(
|
|
43
47
|
sampled_df: pd.DataFrame,
|
|
44
|
-
circuits: Sequence[
|
|
48
|
+
circuits: Sequence[cirq.Circuit],
|
|
45
49
|
cycle_depths: Optional[Sequence[int]] = None,
|
|
46
|
-
param_resolver:
|
|
47
|
-
pool: Optional[
|
|
50
|
+
param_resolver: cirq.ParamResolverOrSimilarType = None,
|
|
51
|
+
pool: Optional[multiprocessing.pool.Pool] = None,
|
|
48
52
|
) -> pd.DataFrame:
|
|
49
53
|
"""Simulate and benchmark two-qubit XEB circuits.
|
|
50
54
|
|
|
@@ -144,11 +148,11 @@ def benchmark_2q_xeb_fidelities(
|
|
|
144
148
|
class XEBCharacterizationOptions(ABC):
|
|
145
149
|
@staticmethod
|
|
146
150
|
@abstractmethod
|
|
147
|
-
def should_parameterize(op:
|
|
151
|
+
def should_parameterize(op: cirq.Operation) -> bool:
|
|
148
152
|
"""Whether to replace `op` with a parameterized version."""
|
|
149
153
|
|
|
150
154
|
@abstractmethod
|
|
151
|
-
def get_parameterized_gate(self) ->
|
|
155
|
+
def get_parameterized_gate(self) -> cirq.Gate:
|
|
152
156
|
"""The parameterized gate to use."""
|
|
153
157
|
|
|
154
158
|
@abstractmethod
|
|
@@ -158,7 +162,7 @@ class XEBCharacterizationOptions(ABC):
|
|
|
158
162
|
"""Return an initial Nelder-Mead simplex and the names for each parameter."""
|
|
159
163
|
|
|
160
164
|
|
|
161
|
-
def _try_defaults_from_unitary(gate:
|
|
165
|
+
def _try_defaults_from_unitary(gate: cirq.Gate) -> Optional[Dict[str, cirq.TParamVal]]:
|
|
162
166
|
r"""Try to figure out the PhasedFSim angles from the unitary of the gate.
|
|
163
167
|
|
|
164
168
|
The unitary of a PhasedFSimGate has the form:
|
|
@@ -221,10 +225,10 @@ def _try_defaults_from_unitary(gate: 'cirq.Gate') -> Optional[Dict[str, 'cirq.TP
|
|
|
221
225
|
return None
|
|
222
226
|
|
|
223
227
|
|
|
224
|
-
def phased_fsim_angles_from_gate(gate:
|
|
228
|
+
def phased_fsim_angles_from_gate(gate: cirq.Gate) -> Dict[str, cirq.TParamVal]:
|
|
225
229
|
"""For a given gate, return a dictionary mapping '{angle}_default' to its noiseless value
|
|
226
230
|
for the five PhasedFSim angles."""
|
|
227
|
-
defaults: Dict[str,
|
|
231
|
+
defaults: Dict[str, cirq.TParamVal] = {
|
|
228
232
|
'theta_default': 0.0,
|
|
229
233
|
'zeta_default': 0.0,
|
|
230
234
|
'chi_default': 0.0,
|
|
@@ -290,7 +294,7 @@ class XEBPhasedFSimCharacterizationOptions(XEBCharacterizationOptions):
|
|
|
290
294
|
gamma_default: Optional[float] = None
|
|
291
295
|
phi_default: Optional[float] = None
|
|
292
296
|
|
|
293
|
-
def _iter_angles(self) -> Iterable[Tuple[bool, Optional[float],
|
|
297
|
+
def _iter_angles(self) -> Iterable[Tuple[bool, Optional[float], sympy.Symbol]]:
|
|
294
298
|
yield from (
|
|
295
299
|
(self.characterize_theta, self.theta_default, THETA_SYMBOL),
|
|
296
300
|
(self.characterize_zeta, self.zeta_default, ZETA_SYMBOL),
|
|
@@ -299,7 +303,7 @@ class XEBPhasedFSimCharacterizationOptions(XEBCharacterizationOptions):
|
|
|
299
303
|
(self.characterize_phi, self.phi_default, PHI_SYMBOL),
|
|
300
304
|
)
|
|
301
305
|
|
|
302
|
-
def _iter_angles_for_characterization(self) -> Iterable[Tuple[Optional[float],
|
|
306
|
+
def _iter_angles_for_characterization(self) -> Iterable[Tuple[Optional[float], sympy.Symbol]]:
|
|
303
307
|
yield from (
|
|
304
308
|
(default, symbol)
|
|
305
309
|
for characterize, default, symbol in self._iter_angles()
|
|
@@ -347,7 +351,7 @@ class XEBPhasedFSimCharacterizationOptions(XEBCharacterizationOptions):
|
|
|
347
351
|
return ops.PhasedFSimGate(theta=theta, zeta=zeta, chi=chi, gamma=gamma, phi=phi)
|
|
348
352
|
|
|
349
353
|
@staticmethod
|
|
350
|
-
def should_parameterize(op:
|
|
354
|
+
def should_parameterize(op: cirq.Operation) -> bool:
|
|
351
355
|
return isinstance(op.gate, (ops.PhasedFSimGate, ops.ISwapPowGate, ops.FSimGate))
|
|
352
356
|
|
|
353
357
|
def defaults_set(self) -> bool:
|
|
@@ -369,7 +373,7 @@ class XEBPhasedFSimCharacterizationOptions(XEBCharacterizationOptions):
|
|
|
369
373
|
return False
|
|
370
374
|
|
|
371
375
|
def with_defaults_from_gate(
|
|
372
|
-
self, gate:
|
|
376
|
+
self, gate: cirq.Gate, gate_to_angles_func=phased_fsim_angles_from_gate
|
|
373
377
|
):
|
|
374
378
|
"""A new Options class with {angle}_defaults inferred from `gate`.
|
|
375
379
|
|
|
@@ -397,10 +401,10 @@ def SqrtISwapXEBOptions(*args, **kwargs):
|
|
|
397
401
|
|
|
398
402
|
|
|
399
403
|
def parameterize_circuit(
|
|
400
|
-
circuit:
|
|
404
|
+
circuit: cirq.Circuit,
|
|
401
405
|
options: XEBCharacterizationOptions,
|
|
402
406
|
target_gatefamily: Optional[ops.GateFamily] = None,
|
|
403
|
-
) ->
|
|
407
|
+
) -> cirq.Circuit:
|
|
404
408
|
"""Parameterize PhasedFSim-like gates in a given circuit according to
|
|
405
409
|
`phased_fsim_options`.
|
|
406
410
|
"""
|
|
@@ -432,21 +436,21 @@ class XEBCharacterizationResult:
|
|
|
432
436
|
fitting the characterization.
|
|
433
437
|
"""
|
|
434
438
|
|
|
435
|
-
optimization_results: Dict[QPair_T,
|
|
439
|
+
optimization_results: Dict[QPair_T, scipy.optimize.OptimizeResult]
|
|
436
440
|
final_params: Dict[QPair_T, Dict[str, float]]
|
|
437
441
|
fidelities_df: pd.DataFrame
|
|
438
442
|
|
|
439
443
|
|
|
440
444
|
def characterize_phased_fsim_parameters_with_xeb(
|
|
441
445
|
sampled_df: pd.DataFrame,
|
|
442
|
-
parameterized_circuits: List[
|
|
446
|
+
parameterized_circuits: List[cirq.Circuit],
|
|
443
447
|
cycle_depths: Sequence[int],
|
|
444
448
|
options: XEBCharacterizationOptions,
|
|
445
449
|
initial_simplex_step_size: float = 0.1,
|
|
446
450
|
xatol: float = 1e-3,
|
|
447
451
|
fatol: float = 1e-3,
|
|
448
452
|
verbose: bool = True,
|
|
449
|
-
pool: Optional[
|
|
453
|
+
pool: Optional[multiprocessing.pool.Pool] = None,
|
|
450
454
|
) -> XEBCharacterizationResult:
|
|
451
455
|
"""Run a classical optimization to fit phased fsim parameters to experimental data, and
|
|
452
456
|
thereby characterize PhasedFSim-like gates.
|
|
@@ -496,7 +500,7 @@ def characterize_phased_fsim_parameters_with_xeb(
|
|
|
496
500
|
method='nelder-mead',
|
|
497
501
|
)
|
|
498
502
|
|
|
499
|
-
final_params:
|
|
503
|
+
final_params: cirq.ParamDictType = dict(zip(names, optimization_result.x))
|
|
500
504
|
fidelities_df = benchmark_2q_xeb_fidelities(
|
|
501
505
|
sampled_df, parameterized_circuits, cycle_depths, param_resolver=final_params
|
|
502
506
|
)
|
|
@@ -512,7 +516,7 @@ class _CharacterizePhasedFsimParametersWithXebClosure:
|
|
|
512
516
|
"""A closure object to wrap `characterize_phased_fsim_parameters_with_xeb` for use in
|
|
513
517
|
multiprocessing."""
|
|
514
518
|
|
|
515
|
-
parameterized_circuits: List[
|
|
519
|
+
parameterized_circuits: List[cirq.Circuit]
|
|
516
520
|
cycle_depths: Sequence[int]
|
|
517
521
|
options: XEBCharacterizationOptions
|
|
518
522
|
initial_simplex_step_size: float = 0.1
|
|
@@ -535,13 +539,13 @@ class _CharacterizePhasedFsimParametersWithXebClosure:
|
|
|
535
539
|
|
|
536
540
|
def characterize_phased_fsim_parameters_with_xeb_by_pair(
|
|
537
541
|
sampled_df: pd.DataFrame,
|
|
538
|
-
parameterized_circuits: List[
|
|
542
|
+
parameterized_circuits: List[cirq.Circuit],
|
|
539
543
|
cycle_depths: Sequence[int],
|
|
540
544
|
options: XEBCharacterizationOptions,
|
|
541
545
|
initial_simplex_step_size: float = 0.1,
|
|
542
546
|
xatol: float = 1e-3,
|
|
543
547
|
fatol: float = 1e-3,
|
|
544
|
-
pool: Optional[
|
|
548
|
+
pool: Optional[multiprocessing.pool.Pool] = None,
|
|
545
549
|
) -> XEBCharacterizationResult:
|
|
546
550
|
"""Run a classical optimization to fit phased fsim parameters to experimental data, and
|
|
547
551
|
thereby characterize PhasedFSim-like gates grouped by pairs.
|
cirq/experiments/xeb_sampling.py
CHANGED
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
|
|
14
15
|
"""Estimation of fidelity associated with experimental circuit executions."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
15
19
|
import os
|
|
16
20
|
import time
|
|
17
21
|
import uuid
|
|
@@ -52,14 +56,14 @@ class _Sample2qXEBTask:
|
|
|
52
56
|
cycle_depth: int
|
|
53
57
|
layer_i: int
|
|
54
58
|
combination_i: int
|
|
55
|
-
prepared_circuit:
|
|
59
|
+
prepared_circuit: cirq.AbstractCircuit
|
|
56
60
|
combination: List[int]
|
|
57
61
|
|
|
58
62
|
|
|
59
63
|
class _SampleInBatches:
|
|
60
64
|
def __init__(
|
|
61
65
|
self,
|
|
62
|
-
sampler:
|
|
66
|
+
sampler: cirq.Sampler,
|
|
63
67
|
repetitions: int,
|
|
64
68
|
combinations_by_layer: List[CircuitLibraryCombination],
|
|
65
69
|
):
|
|
@@ -107,9 +111,9 @@ class _SampleInBatches:
|
|
|
107
111
|
return records
|
|
108
112
|
|
|
109
113
|
|
|
110
|
-
def _verify_and_get_two_qubits_from_circuits(circuits: Sequence[
|
|
114
|
+
def _verify_and_get_two_qubits_from_circuits(circuits: Sequence[cirq.Circuit]):
|
|
111
115
|
"""Make sure each of the provided circuits uses the same two qubits and return them."""
|
|
112
|
-
all_qubits_set: Set[
|
|
116
|
+
all_qubits_set: Set[cirq.Qid] = set()
|
|
113
117
|
all_qubits_set = all_qubits_set.union(*(circuit.all_qubits() for circuit in circuits))
|
|
114
118
|
all_qubits_list = sorted(all_qubits_set)
|
|
115
119
|
if len(all_qubits_list) != 2:
|
|
@@ -119,7 +123,7 @@ def _verify_and_get_two_qubits_from_circuits(circuits: Sequence['cirq.Circuit'])
|
|
|
119
123
|
return all_qubits_list
|
|
120
124
|
|
|
121
125
|
|
|
122
|
-
def _verify_two_line_qubits_from_circuits(circuits: Sequence[
|
|
126
|
+
def _verify_two_line_qubits_from_circuits(circuits: Sequence[cirq.Circuit]):
|
|
123
127
|
if _verify_and_get_two_qubits_from_circuits(circuits) != devices.LineQubit.range(2):
|
|
124
128
|
raise ValueError(
|
|
125
129
|
"`circuits` should be a sequence of circuits each operating "
|
|
@@ -165,16 +169,16 @@ class _ZippedCircuit:
|
|
|
165
169
|
any behavior. It is propagated to the output result object.
|
|
166
170
|
"""
|
|
167
171
|
|
|
168
|
-
wide_circuit:
|
|
169
|
-
pairs: List[Tuple[
|
|
172
|
+
wide_circuit: cirq.Circuit
|
|
173
|
+
pairs: List[Tuple[cirq.Qid, cirq.Qid]]
|
|
170
174
|
combination: List[int]
|
|
171
175
|
layer_i: int
|
|
172
176
|
combination_i: int
|
|
173
177
|
|
|
174
178
|
|
|
175
179
|
def _get_combinations_by_layer_for_isolated_xeb(
|
|
176
|
-
circuits: Sequence[
|
|
177
|
-
) -> Tuple[List[CircuitLibraryCombination], List[
|
|
180
|
+
circuits: Sequence[cirq.Circuit],
|
|
181
|
+
) -> Tuple[List[CircuitLibraryCombination], List[cirq.Circuit]]:
|
|
178
182
|
"""Helper function used in `sample_2q_xeb_circuits`.
|
|
179
183
|
|
|
180
184
|
This creates a CircuitLibraryCombination object for isolated XEB. First, the qubits
|
|
@@ -195,7 +199,7 @@ def _get_combinations_by_layer_for_isolated_xeb(
|
|
|
195
199
|
|
|
196
200
|
|
|
197
201
|
def _zip_circuits(
|
|
198
|
-
circuits: Sequence[
|
|
202
|
+
circuits: Sequence[cirq.Circuit], combinations_by_layer: List[CircuitLibraryCombination]
|
|
199
203
|
) -> List[_ZippedCircuit]:
|
|
200
204
|
"""Helper function used in `sample_2q_xeb_circuits` to zip together circuits.
|
|
201
205
|
|
|
@@ -260,7 +264,7 @@ def _generate_sample_2q_xeb_tasks(
|
|
|
260
264
|
|
|
261
265
|
def _execute_sample_2q_xeb_tasks_in_batches(
|
|
262
266
|
tasks: List[_Sample2qXEBTask],
|
|
263
|
-
sampler:
|
|
267
|
+
sampler: cirq.Sampler,
|
|
264
268
|
combinations_by_layer: List[CircuitLibraryCombination],
|
|
265
269
|
repetitions: int,
|
|
266
270
|
batch_size: int,
|
|
@@ -288,15 +292,15 @@ def _execute_sample_2q_xeb_tasks_in_batches(
|
|
|
288
292
|
|
|
289
293
|
|
|
290
294
|
def sample_2q_xeb_circuits(
|
|
291
|
-
sampler:
|
|
292
|
-
circuits: Sequence[
|
|
295
|
+
sampler: cirq.Sampler,
|
|
296
|
+
circuits: Sequence[cirq.Circuit],
|
|
293
297
|
cycle_depths: Sequence[int],
|
|
294
298
|
*,
|
|
295
299
|
repetitions: int = 10_000,
|
|
296
300
|
batch_size: int = 9,
|
|
297
301
|
progress_bar: Optional[Callable[..., ContextManager]] = tqdm.tqdm,
|
|
298
302
|
combinations_by_layer: Optional[List[CircuitLibraryCombination]] = None,
|
|
299
|
-
shuffle: Optional[
|
|
303
|
+
shuffle: Optional[cirq.RANDOM_STATE_OR_SEED_LIKE] = None,
|
|
300
304
|
dataset_directory: Optional[str] = None,
|
|
301
305
|
):
|
|
302
306
|
"""Sample two-qubit XEB circuits given a sampler.
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
|
|
14
15
|
"""Estimation of fidelity associated with experimental circuit executions."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
15
19
|
from dataclasses import dataclass
|
|
16
20
|
from typing import Any, Dict, List, Optional, Sequence, TYPE_CHECKING
|
|
17
21
|
|
|
@@ -32,14 +36,14 @@ class _Simulate2qXEBTask:
|
|
|
32
36
|
|
|
33
37
|
circuit_i: int
|
|
34
38
|
cycle_depths: Sequence[int]
|
|
35
|
-
circuit:
|
|
36
|
-
param_resolver:
|
|
39
|
+
circuit: cirq.Circuit
|
|
40
|
+
param_resolver: cirq.ParamResolverOrSimilarType
|
|
37
41
|
|
|
38
42
|
|
|
39
43
|
class _Simulate_2q_XEB_Circuit:
|
|
40
44
|
"""Closure used in `simulate_2q_xeb_circuits` so it works with multiprocessing."""
|
|
41
45
|
|
|
42
|
-
def __init__(self, simulator:
|
|
46
|
+
def __init__(self, simulator: cirq.SimulatesIntermediateState):
|
|
43
47
|
self.simulator = simulator
|
|
44
48
|
|
|
45
49
|
def __call__(self, task: _Simulate2qXEBTask) -> List[Dict[str, Any]]:
|
|
@@ -77,11 +81,11 @@ class _Simulate_2q_XEB_Circuit:
|
|
|
77
81
|
|
|
78
82
|
|
|
79
83
|
def simulate_2q_xeb_circuits(
|
|
80
|
-
circuits: Sequence[
|
|
84
|
+
circuits: Sequence[cirq.Circuit],
|
|
81
85
|
cycle_depths: Sequence[int],
|
|
82
|
-
param_resolver:
|
|
83
|
-
pool: Optional[
|
|
84
|
-
simulator: Optional[
|
|
86
|
+
param_resolver: cirq.ParamResolverOrSimilarType = None,
|
|
87
|
+
pool: Optional[multiprocessing.pool.Pool] = None,
|
|
88
|
+
simulator: Optional[cirq.SimulatesIntermediateState] = None,
|
|
85
89
|
):
|
|
86
90
|
"""Simulate two-qubit XEB circuits.
|
|
87
91
|
|
|
@@ -95,10 +95,10 @@ def _ref_simulate_2q_xeb_circuit(task: Dict[str, Any]):
|
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
def _ref_simulate_2q_xeb_circuits(
|
|
98
|
-
circuits: Sequence[
|
|
98
|
+
circuits: Sequence[cirq.Circuit],
|
|
99
99
|
cycle_depths: Sequence[int],
|
|
100
|
-
param_resolver:
|
|
101
|
-
pool: Optional[
|
|
100
|
+
param_resolver: cirq.ParamResolverOrSimilarType = None,
|
|
101
|
+
pool: Optional[multiprocessing.pool.Pool] = None,
|
|
102
102
|
):
|
|
103
103
|
"""Reference implementation for `simulate_2q_xeb_circuits` that
|
|
104
104
|
does each circuit independently instead of using intermediate states.
|