cirq-core 1.6.0.dev20250416221104__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_core-1.6.0.dev20250416221104.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250416221104.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/RECORD +57 -57
- {cirq_core-1.6.0.dev20250416221104.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250416221104.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250416221104.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
cirq/devices/noise_model_test.py
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
from typing import Sequence
|
|
16
18
|
|
|
17
19
|
import numpy as np
|
|
@@ -77,7 +79,7 @@ def test_infers_other_methods():
|
|
|
77
79
|
)
|
|
78
80
|
|
|
79
81
|
class NoiseModelWithNoisyOperationMethod(cirq.NoiseModel):
|
|
80
|
-
def noisy_operation(self, operation:
|
|
82
|
+
def noisy_operation(self, operation: cirq.Operation):
|
|
81
83
|
return cirq.Z(operation.qubits[0]).with_tags(ops.VirtualTag())
|
|
82
84
|
|
|
83
85
|
c = NoiseModelWithNoisyOperationMethod()
|
cirq/devices/noise_properties.py
CHANGED
|
@@ -19,6 +19,8 @@ be translated into noise models. NoiseModelFromNoiseProperties consumes those
|
|
|
19
19
|
noise models to produce a single noise model which replicates device noise.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
22
24
|
import abc
|
|
23
25
|
from typing import Iterable, List, Sequence, TYPE_CHECKING
|
|
24
26
|
|
|
@@ -35,7 +37,7 @@ class NoiseProperties(abc.ABC):
|
|
|
35
37
|
"""Noise-defining properties for a quantum device."""
|
|
36
38
|
|
|
37
39
|
@abc.abstractmethod
|
|
38
|
-
def build_noise_models(self) -> List[
|
|
40
|
+
def build_noise_models(self) -> List[cirq.NoiseModel]:
|
|
39
41
|
"""Construct all NoiseModels associated with this NoiseProperties."""
|
|
40
42
|
|
|
41
43
|
|
|
@@ -52,7 +54,7 @@ class NoiseModelFromNoiseProperties(devices.NoiseModel):
|
|
|
52
54
|
self._noise_properties = noise_properties
|
|
53
55
|
self.noise_models = self._noise_properties.build_noise_models()
|
|
54
56
|
|
|
55
|
-
def is_virtual(self, op:
|
|
57
|
+
def is_virtual(self, op: cirq.Operation) -> bool:
|
|
56
58
|
"""Returns True if an operation is virtual.
|
|
57
59
|
|
|
58
60
|
Device-specific subclasses should implement this method to mark any
|
|
@@ -67,8 +69,8 @@ class NoiseModelFromNoiseProperties(devices.NoiseModel):
|
|
|
67
69
|
return False
|
|
68
70
|
|
|
69
71
|
def noisy_moments(
|
|
70
|
-
self, moments: Iterable[
|
|
71
|
-
) -> Sequence[
|
|
72
|
+
self, moments: Iterable[cirq.Moment], system_qubits: Sequence[cirq.Qid]
|
|
73
|
+
) -> Sequence[cirq.OP_TREE]:
|
|
72
74
|
# Split multi-qubit measurements into single-qubit measurements.
|
|
73
75
|
# These will be recombined after noise is applied.
|
|
74
76
|
split_measure_moments = []
|
cirq/devices/noise_utils.py
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
from typing import Any, Dict, Tuple, Type, TYPE_CHECKING, Union
|
|
16
18
|
|
|
17
19
|
from cirq import ops, protocols, qis, value
|
|
@@ -29,24 +31,24 @@ PHYSICAL_GATE_TAG = 'physical_gate'
|
|
|
29
31
|
class OpIdentifier:
|
|
30
32
|
"""Identifies an operation by gate and (optionally) target qubits."""
|
|
31
33
|
|
|
32
|
-
def __init__(self, gate_type: Type[
|
|
34
|
+
def __init__(self, gate_type: Type[cirq.Gate], *qubits: cirq.Qid):
|
|
33
35
|
self._gate_type = gate_type
|
|
34
36
|
self._gate_family = ops.GateFamily(gate_type)
|
|
35
|
-
self._qubits: Tuple[
|
|
37
|
+
self._qubits: Tuple[cirq.Qid, ...] = tuple(qubits)
|
|
36
38
|
|
|
37
39
|
@property
|
|
38
|
-
def gate_type(self) -> Type[
|
|
40
|
+
def gate_type(self) -> Type[cirq.Gate]:
|
|
39
41
|
# set to a type during initialization, never modified
|
|
40
42
|
return self._gate_type
|
|
41
43
|
|
|
42
44
|
@property
|
|
43
|
-
def qubits(self) -> Tuple[
|
|
45
|
+
def qubits(self) -> Tuple[cirq.Qid, ...]:
|
|
44
46
|
return self._qubits
|
|
45
47
|
|
|
46
48
|
def _predicate(self, *args, **kwargs):
|
|
47
49
|
return self._gate_family._predicate(*args, **kwargs)
|
|
48
50
|
|
|
49
|
-
def is_proper_subtype_of(self, op_id:
|
|
51
|
+
def is_proper_subtype_of(self, op_id: OpIdentifier):
|
|
50
52
|
"""Returns true if this is contained within op_id, but not equal to it.
|
|
51
53
|
|
|
52
54
|
If this returns true, (x in self) implies (x in op_id), but the reverse
|
|
@@ -90,7 +92,7 @@ class OpIdentifier:
|
|
|
90
92
|
return {'gate_type': self._gate_type, 'qubits': self._qubits}
|
|
91
93
|
|
|
92
94
|
@classmethod
|
|
93
|
-
def _from_json_dict_(cls, gate_type, qubits, **kwargs) ->
|
|
95
|
+
def _from_json_dict_(cls, gate_type, qubits, **kwargs) -> OpIdentifier:
|
|
94
96
|
if isinstance(gate_type, str):
|
|
95
97
|
gate_type = protocols.cirq_type_from_json(gate_type)
|
|
96
98
|
return cls(gate_type, *qubits)
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
"""Class for representing noise on a superconducting qubit device."""
|
|
17
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
18
19
|
import abc
|
|
19
20
|
from dataclasses import dataclass, field
|
|
20
21
|
from functools import cached_property
|
|
@@ -49,13 +50,13 @@ class SuperconductingQubitsNoiseProperties(devices.NoiseProperties, abc.ABC):
|
|
|
49
50
|
"""
|
|
50
51
|
|
|
51
52
|
gate_times_ns: Dict[type, float]
|
|
52
|
-
t1_ns: Dict[
|
|
53
|
-
tphi_ns: Dict[
|
|
54
|
-
readout_errors: Dict[
|
|
53
|
+
t1_ns: Dict[cirq.Qid, float]
|
|
54
|
+
tphi_ns: Dict[cirq.Qid, float]
|
|
55
|
+
readout_errors: Dict[cirq.Qid, List[float]]
|
|
55
56
|
gate_pauli_errors: Dict[noise_utils.OpIdentifier, float]
|
|
56
57
|
|
|
57
58
|
validate: bool = True
|
|
58
|
-
_qubits: List[
|
|
59
|
+
_qubits: List[cirq.Qid] = field(init=False, default_factory=list)
|
|
59
60
|
|
|
60
61
|
def __post_init__(self):
|
|
61
62
|
if not self.validate:
|
|
@@ -95,7 +96,7 @@ class SuperconductingQubitsNoiseProperties(devices.NoiseProperties, abc.ABC):
|
|
|
95
96
|
)
|
|
96
97
|
|
|
97
98
|
@property
|
|
98
|
-
def qubits(self) -> List[
|
|
99
|
+
def qubits(self) -> List[cirq.Qid]:
|
|
99
100
|
"""Qubits for which we have data"""
|
|
100
101
|
if not self._qubits:
|
|
101
102
|
self._qubits = sorted(self.t1_ns)
|
|
@@ -150,8 +151,8 @@ class SuperconductingQubitsNoiseProperties(devices.NoiseProperties, abc.ABC):
|
|
|
150
151
|
depol_errors[op_id] = self._get_pauli_error(p_error, op_id)
|
|
151
152
|
return depol_errors
|
|
152
153
|
|
|
153
|
-
def build_noise_models(self) -> List[
|
|
154
|
-
noise_models: List[
|
|
154
|
+
def build_noise_models(self) -> List[cirq.NoiseModel]:
|
|
155
|
+
noise_models: List[cirq.NoiseModel] = []
|
|
155
156
|
|
|
156
157
|
if self.t1_ns:
|
|
157
158
|
noise_models.append(
|
|
@@ -175,7 +176,7 @@ class SuperconductingQubitsNoiseProperties(devices.NoiseProperties, abc.ABC):
|
|
|
175
176
|
|
|
176
177
|
# This adds per-qubit measurement error BEFORE measurement on those qubits.
|
|
177
178
|
if self.readout_errors:
|
|
178
|
-
added_measure_errors: Dict[noise_utils.OpIdentifier,
|
|
179
|
+
added_measure_errors: Dict[noise_utils.OpIdentifier, cirq.Operation] = {}
|
|
179
180
|
for qubit in self.readout_errors:
|
|
180
181
|
p_00, p_11 = self.readout_errors[qubit]
|
|
181
182
|
p = p_11 / (p_00 + p_11)
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
import dataclasses
|
|
16
18
|
import functools
|
|
17
19
|
from typing import Dict, List, Optional, Sequence, Set, Tuple, TYPE_CHECKING, Union
|
|
@@ -129,8 +131,8 @@ def _decoherence_matrix(
|
|
|
129
131
|
|
|
130
132
|
|
|
131
133
|
def _as_rate_dict(
|
|
132
|
-
rate_or_dict: Optional[Union[float, Dict[
|
|
133
|
-
) -> Dict[
|
|
134
|
+
rate_or_dict: Optional[Union[float, Dict[cirq.Qid, float]]], qubits: Set[cirq.Qid]
|
|
135
|
+
) -> Dict[cirq.Qid, float]:
|
|
134
136
|
"""Convert float or None input into dictionary form.
|
|
135
137
|
|
|
136
138
|
This method also ensures that no qubits are missing from dictionary keys.
|
|
@@ -143,7 +145,7 @@ def _as_rate_dict(
|
|
|
143
145
|
return {q: rate_or_dict for q in qubits}
|
|
144
146
|
|
|
145
147
|
|
|
146
|
-
def _validate_rates(qubits: Set[
|
|
148
|
+
def _validate_rates(qubits: Set[cirq.Qid], rates: Dict[cirq.Qid, np.ndarray]) -> None:
|
|
147
149
|
"""Check all rate matrices are square and of appropriate dimension.
|
|
148
150
|
|
|
149
151
|
We check rates are positive in the class validator.
|
|
@@ -169,11 +171,11 @@ class ThermalNoiseModel(devices.NoiseModel):
|
|
|
169
171
|
|
|
170
172
|
def __init__(
|
|
171
173
|
self,
|
|
172
|
-
qubits: Set[
|
|
174
|
+
qubits: Set[cirq.Qid],
|
|
173
175
|
gate_durations_ns: Dict[type, float],
|
|
174
|
-
heat_rate_GHz: Union[float, Dict[
|
|
175
|
-
cool_rate_GHz: Union[float, Dict[
|
|
176
|
-
dephase_rate_GHz: Union[float, Dict[
|
|
176
|
+
heat_rate_GHz: Union[float, Dict[cirq.Qid, float], None] = None,
|
|
177
|
+
cool_rate_GHz: Union[float, Dict[cirq.Qid, float], None] = None,
|
|
178
|
+
dephase_rate_GHz: Union[float, Dict[cirq.Qid, float], None] = None,
|
|
177
179
|
require_physical_tag: bool = True,
|
|
178
180
|
skip_measurements: bool = True,
|
|
179
181
|
prepend: bool = False,
|
|
@@ -225,14 +227,12 @@ class ThermalNoiseModel(devices.NoiseModel):
|
|
|
225
227
|
|
|
226
228
|
_validate_rates(qubits, rate_dict)
|
|
227
229
|
self.gate_durations_ns: Dict[type, float] = gate_durations_ns
|
|
228
|
-
self.rate_matrix_GHz: Dict[
|
|
230
|
+
self.rate_matrix_GHz: Dict[cirq.Qid, np.ndarray] = rate_dict
|
|
229
231
|
self.require_physical_tag: bool = require_physical_tag
|
|
230
232
|
self.skip_measurements: bool = skip_measurements
|
|
231
233
|
self._prepend = prepend
|
|
232
234
|
|
|
233
|
-
def noisy_moment(
|
|
234
|
-
self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']
|
|
235
|
-
) -> 'cirq.OP_TREE':
|
|
235
|
+
def noisy_moment(self, moment: cirq.Moment, system_qubits: Sequence[cirq.Qid]) -> cirq.OP_TREE:
|
|
236
236
|
if not moment.operations:
|
|
237
237
|
return [moment]
|
|
238
238
|
if self.require_physical_tag:
|
|
@@ -247,7 +247,7 @@ class ThermalNoiseModel(devices.NoiseModel):
|
|
|
247
247
|
# Only moments with physical operations should have noise.
|
|
248
248
|
return [moment]
|
|
249
249
|
|
|
250
|
-
noise_ops: List[
|
|
250
|
+
noise_ops: List[cirq.Operation] = []
|
|
251
251
|
# Some devices (including Google hardware) require that all gates have
|
|
252
252
|
# the same duration, but this does not. Instead, each moment is assumed
|
|
253
253
|
# to be as long as the longest gate it contains.
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
from typing import Any, Dict, TYPE_CHECKING
|
|
16
18
|
|
|
17
19
|
from cirq import protocols, value
|
|
@@ -26,7 +28,7 @@ if TYPE_CHECKING:
|
|
|
26
28
|
class _UnconstrainedDevice(device.Device):
|
|
27
29
|
"""A device that allows everything, infinitely fast."""
|
|
28
30
|
|
|
29
|
-
def duration_of(self, operation:
|
|
31
|
+
def duration_of(self, operation: cirq.Operation) -> cirq.Duration:
|
|
30
32
|
return value.Duration(picos=0)
|
|
31
33
|
|
|
32
34
|
def validate_moment(self, moment) -> None:
|
|
@@ -17,6 +17,9 @@ different pre-measurement rotations.
|
|
|
17
17
|
The code is designed to be modular with regards to data collection
|
|
18
18
|
so that occurs outside of the StateTomographyExperiment class.
|
|
19
19
|
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
20
23
|
from typing import List, Optional, Sequence, Tuple, TYPE_CHECKING
|
|
21
24
|
|
|
22
25
|
import numpy as np
|
|
@@ -49,7 +52,7 @@ class StateTomographyExperiment:
|
|
|
49
52
|
|
|
50
53
|
def __init__(
|
|
51
54
|
self,
|
|
52
|
-
qubits: Sequence[
|
|
55
|
+
qubits: Sequence[cirq.Qid],
|
|
53
56
|
prerotations: Optional[Sequence[Tuple[float, float]]] = None,
|
|
54
57
|
):
|
|
55
58
|
"""Initializes the rotation protocol and matrix for system.
|
|
@@ -69,8 +72,8 @@ class StateTomographyExperiment:
|
|
|
69
72
|
|
|
70
73
|
phase_exp_vals, exp_vals = zip(*prerotations)
|
|
71
74
|
|
|
72
|
-
operations: List[
|
|
73
|
-
sweeps: List[
|
|
75
|
+
operations: List[cirq.Operation] = []
|
|
76
|
+
sweeps: List[cirq.Sweep] = []
|
|
74
77
|
for i, qubit in enumerate(qubits):
|
|
75
78
|
phase_exp = sympy.Symbol(f'phase_exp_{i}')
|
|
76
79
|
exp = sympy.Symbol(f'exp_{i}')
|
|
@@ -82,7 +85,7 @@ class StateTomographyExperiment:
|
|
|
82
85
|
self.rot_sweep = study.Product(*sweeps)
|
|
83
86
|
self.mat = self._make_state_tomography_matrix(qubits)
|
|
84
87
|
|
|
85
|
-
def _make_state_tomography_matrix(self, qubits: Sequence[
|
|
88
|
+
def _make_state_tomography_matrix(self, qubits: Sequence[cirq.Qid]) -> np.ndarray:
|
|
86
89
|
"""Gets the matrix used for solving the linear system of the tomography.
|
|
87
90
|
|
|
88
91
|
Args:
|
|
@@ -130,9 +133,9 @@ class StateTomographyExperiment:
|
|
|
130
133
|
|
|
131
134
|
|
|
132
135
|
def state_tomography(
|
|
133
|
-
sampler:
|
|
134
|
-
qubits: Sequence[
|
|
135
|
-
circuit:
|
|
136
|
+
sampler: cirq.Sampler,
|
|
137
|
+
qubits: Sequence[cirq.Qid],
|
|
138
|
+
circuit: cirq.Circuit,
|
|
136
139
|
repetitions: int = 1000,
|
|
137
140
|
prerotations: Optional[Sequence[Tuple[float, float]]] = None,
|
|
138
141
|
) -> TomographyResult:
|
|
@@ -166,11 +169,11 @@ def state_tomography(
|
|
|
166
169
|
|
|
167
170
|
|
|
168
171
|
def get_state_tomography_data(
|
|
169
|
-
sampler:
|
|
170
|
-
qubits: Sequence[
|
|
171
|
-
circuit:
|
|
172
|
-
rot_circuit:
|
|
173
|
-
rot_sweep:
|
|
172
|
+
sampler: cirq.Sampler,
|
|
173
|
+
qubits: Sequence[cirq.Qid],
|
|
174
|
+
circuit: cirq.Circuit,
|
|
175
|
+
rot_circuit: cirq.Circuit,
|
|
176
|
+
rot_sweep: cirq.Sweep,
|
|
174
177
|
repetitions: int = 1000,
|
|
175
178
|
) -> np.ndarray:
|
|
176
179
|
"""Gets the data for each rotation string added to the circuit.
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
import dataclasses
|
|
16
18
|
import functools
|
|
17
19
|
import itertools
|
|
@@ -150,10 +152,10 @@ class RandomizedBenchMarkResult:
|
|
|
150
152
|
class ParallelRandomizedBenchmarkingResult:
|
|
151
153
|
"""Results from a parallel randomized benchmarking experiment."""
|
|
152
154
|
|
|
153
|
-
results_dictionary: Mapping[
|
|
155
|
+
results_dictionary: Mapping[cirq.Qid, RandomizedBenchMarkResult]
|
|
154
156
|
|
|
155
157
|
def plot_single_qubit(
|
|
156
|
-
self, qubit:
|
|
158
|
+
self, qubit: cirq.Qid, ax: Optional[plt.Axes] = None, **plot_kwargs: Any
|
|
157
159
|
) -> plt.Axes:
|
|
158
160
|
"""Plot the raw data for the specified qubit.
|
|
159
161
|
|
|
@@ -168,7 +170,7 @@ class ParallelRandomizedBenchmarkingResult:
|
|
|
168
170
|
|
|
169
171
|
return self.results_dictionary[qubit].plot(ax, **plot_kwargs)
|
|
170
172
|
|
|
171
|
-
def pauli_error(self) -> Mapping[
|
|
173
|
+
def pauli_error(self) -> Mapping[cirq.Qid, float]:
|
|
172
174
|
"""Return a dictionary of Pauli errors.
|
|
173
175
|
Returns:
|
|
174
176
|
A dictionary containing the Pauli errors for all qubits.
|
|
@@ -342,8 +344,8 @@ class TomographyResult:
|
|
|
342
344
|
|
|
343
345
|
|
|
344
346
|
def single_qubit_randomized_benchmarking(
|
|
345
|
-
sampler:
|
|
346
|
-
qubit:
|
|
347
|
+
sampler: cirq.Sampler,
|
|
348
|
+
qubit: cirq.Qid,
|
|
347
349
|
use_xy_basis: bool = True,
|
|
348
350
|
*,
|
|
349
351
|
num_clifford_range: Sequence[int] = tuple(np.logspace(np.log10(5), 3, 5, dtype=int)),
|
|
@@ -396,8 +398,8 @@ def single_qubit_randomized_benchmarking(
|
|
|
396
398
|
|
|
397
399
|
|
|
398
400
|
def parallel_single_qubit_randomized_benchmarking(
|
|
399
|
-
sampler:
|
|
400
|
-
qubits: Sequence[
|
|
401
|
+
sampler: cirq.Sampler,
|
|
402
|
+
qubits: Sequence[cirq.Qid],
|
|
401
403
|
use_xy_basis: bool = True,
|
|
402
404
|
*,
|
|
403
405
|
num_clifford_range: Sequence[int] = tuple(
|
|
@@ -405,7 +407,7 @@ def parallel_single_qubit_randomized_benchmarking(
|
|
|
405
407
|
),
|
|
406
408
|
num_circuits: int = 10,
|
|
407
409
|
repetitions: int = 1000,
|
|
408
|
-
) ->
|
|
410
|
+
) -> ParallelRandomizedBenchmarkingResult:
|
|
409
411
|
"""Clifford-based randomized benchmarking (RB) single qubits in parallel.
|
|
410
412
|
|
|
411
413
|
This is the same as `single_qubit_randomized_benchmarking` except on all
|
|
@@ -430,7 +432,7 @@ def parallel_single_qubit_randomized_benchmarking(
|
|
|
430
432
|
c1 = clifford_group.c1_in_xy if use_xy_basis else clifford_group.c1_in_xz
|
|
431
433
|
|
|
432
434
|
# create circuits
|
|
433
|
-
circuits_all: List[
|
|
435
|
+
circuits_all: List[cirq.AbstractCircuit] = []
|
|
434
436
|
for num_cliffords in num_clifford_range:
|
|
435
437
|
for _ in range(num_circuits):
|
|
436
438
|
circuits_all.append(_create_parallel_rb_circuit(qubits, num_cliffords, c1))
|
|
@@ -440,7 +442,7 @@ def parallel_single_qubit_randomized_benchmarking(
|
|
|
440
442
|
gnd_probs: dict = {q: [] for q in qubits}
|
|
441
443
|
idx = 0
|
|
442
444
|
for num_cliffords in num_clifford_range:
|
|
443
|
-
excited_probs: Dict[
|
|
445
|
+
excited_probs: Dict[cirq.Qid, List[float]] = {q: [] for q in qubits}
|
|
444
446
|
for _ in range(num_circuits):
|
|
445
447
|
result = results[idx][0]
|
|
446
448
|
for qubit in qubits:
|
|
@@ -454,9 +456,9 @@ def parallel_single_qubit_randomized_benchmarking(
|
|
|
454
456
|
|
|
455
457
|
|
|
456
458
|
def two_qubit_randomized_benchmarking(
|
|
457
|
-
sampler:
|
|
458
|
-
first_qubit:
|
|
459
|
-
second_qubit:
|
|
459
|
+
sampler: cirq.Sampler,
|
|
460
|
+
first_qubit: cirq.Qid,
|
|
461
|
+
second_qubit: cirq.Qid,
|
|
460
462
|
*,
|
|
461
463
|
num_clifford_range: Sequence[int] = range(5, 50, 5),
|
|
462
464
|
num_circuits: int = 20,
|
|
@@ -514,10 +516,7 @@ def two_qubit_randomized_benchmarking(
|
|
|
514
516
|
|
|
515
517
|
|
|
516
518
|
def single_qubit_state_tomography(
|
|
517
|
-
sampler:
|
|
518
|
-
qubit: 'cirq.Qid',
|
|
519
|
-
circuit: 'cirq.AbstractCircuit',
|
|
520
|
-
repetitions: int = 1000,
|
|
519
|
+
sampler: cirq.Sampler, qubit: cirq.Qid, circuit: cirq.AbstractCircuit, repetitions: int = 1000
|
|
521
520
|
) -> TomographyResult:
|
|
522
521
|
"""Single-qubit state tomography.
|
|
523
522
|
|
|
@@ -560,10 +559,10 @@ def single_qubit_state_tomography(
|
|
|
560
559
|
|
|
561
560
|
|
|
562
561
|
def two_qubit_state_tomography(
|
|
563
|
-
sampler:
|
|
564
|
-
first_qubit:
|
|
565
|
-
second_qubit:
|
|
566
|
-
circuit:
|
|
562
|
+
sampler: cirq.Sampler,
|
|
563
|
+
first_qubit: cirq.Qid,
|
|
564
|
+
second_qubit: cirq.Qid,
|
|
565
|
+
circuit: cirq.AbstractCircuit,
|
|
567
566
|
repetitions: int = 1000,
|
|
568
567
|
) -> TomographyResult:
|
|
569
568
|
r"""Two-qubit state tomography.
|
|
@@ -688,8 +687,8 @@ def two_qubit_state_tomography(
|
|
|
688
687
|
|
|
689
688
|
|
|
690
689
|
def _create_parallel_rb_circuit(
|
|
691
|
-
qubits: Sequence[
|
|
692
|
-
) ->
|
|
690
|
+
qubits: Sequence[cirq.Qid], num_cliffords: int, c1: list
|
|
691
|
+
) -> cirq.Circuit:
|
|
693
692
|
sequences_to_zip = [_random_single_q_clifford(qubit, num_cliffords, c1) for qubit in qubits]
|
|
694
693
|
# Ensure each sequence has the same number of moments.
|
|
695
694
|
num_moments = max(len(sequence) for sequence in sequences_to_zip)
|
|
@@ -711,9 +710,7 @@ def _indices_after_basis_rot(i: int, j: int) -> Tuple[int, Sequence[int], Sequen
|
|
|
711
710
|
return mat_idx, indices, signs
|
|
712
711
|
|
|
713
712
|
|
|
714
|
-
def _two_qubit_clifford_matrices(
|
|
715
|
-
q_0: 'cirq.Qid', q_1: 'cirq.Qid', cliffords: Cliffords
|
|
716
|
-
) -> np.ndarray:
|
|
713
|
+
def _two_qubit_clifford_matrices(q_0: cirq.Qid, q_1: cirq.Qid, cliffords: Cliffords) -> np.ndarray:
|
|
717
714
|
mats = []
|
|
718
715
|
|
|
719
716
|
# Total number of different gates in the two-qubit Clifford group.
|
|
@@ -743,8 +740,8 @@ def _two_qubit_clifford_matrices(
|
|
|
743
740
|
|
|
744
741
|
|
|
745
742
|
def _random_single_q_clifford(
|
|
746
|
-
qubit:
|
|
747
|
-
) -> List[
|
|
743
|
+
qubit: cirq.Qid, num_cfds: int, cfds: Sequence[Sequence[cirq.ops.SingleQubitCliffordGate]]
|
|
744
|
+
) -> List[cirq.Operation]:
|
|
748
745
|
clifford_group_size = 24
|
|
749
746
|
operations = [[gate.to_phased_xz_gate()(qubit) for gate in gates] for gates in cfds]
|
|
750
747
|
gate_ids = list(np.random.choice(clifford_group_size, num_cfds))
|
|
@@ -755,8 +752,8 @@ def _random_single_q_clifford(
|
|
|
755
752
|
|
|
756
753
|
|
|
757
754
|
def _random_two_q_clifford(
|
|
758
|
-
q_0:
|
|
759
|
-
) ->
|
|
755
|
+
q_0: cirq.Qid, q_1: cirq.Qid, num_cfds: int, cfd_matrices: np.ndarray, cliffords: Cliffords
|
|
756
|
+
) -> cirq.Circuit:
|
|
760
757
|
clifford_group_size = 11520
|
|
761
758
|
idx_list = list(np.random.choice(clifford_group_size, num_cfds))
|
|
762
759
|
circuit = circuits.Circuit()
|
|
@@ -819,8 +816,8 @@ def _reduce_gate_seq(
|
|
|
819
816
|
|
|
820
817
|
|
|
821
818
|
def _two_qubit_clifford(
|
|
822
|
-
q_0:
|
|
823
|
-
) -> Iterator[
|
|
819
|
+
q_0: cirq.Qid, q_1: cirq.Qid, idx: int, cliffords: Cliffords
|
|
820
|
+
) -> Iterator[cirq.OP_TREE]:
|
|
824
821
|
"""Generates a two-qubit Clifford gate.
|
|
825
822
|
|
|
826
823
|
An integer (idx) from 0 to 11519 is used to generate a two-qubit Clifford
|
|
@@ -875,8 +872,8 @@ def _split_two_q_clifford_idx(idx: int):
|
|
|
875
872
|
|
|
876
873
|
|
|
877
874
|
def _two_qubit_clifford_starters(
|
|
878
|
-
q_0:
|
|
879
|
-
) -> Iterator[
|
|
875
|
+
q_0: cirq.Qid, q_1: cirq.Qid, idx_0: int, idx_1: int, cliffords: Cliffords
|
|
876
|
+
) -> Iterator[cirq.OP_TREE]:
|
|
880
877
|
"""Fulfills part (a) for two-qubit Cliffords."""
|
|
881
878
|
c1 = cliffords.c1_in_xy
|
|
882
879
|
yield _single_qubit_gates(c1[idx_0], q_0)
|
|
@@ -884,8 +881,8 @@ def _two_qubit_clifford_starters(
|
|
|
884
881
|
|
|
885
882
|
|
|
886
883
|
def _two_qubit_clifford_mixers(
|
|
887
|
-
q_0:
|
|
888
|
-
) -> Iterator[
|
|
884
|
+
q_0: cirq.Qid, q_1: cirq.Qid, idx_2: int, cliffords: Cliffords
|
|
885
|
+
) -> Iterator[cirq.OP_TREE]:
|
|
889
886
|
"""Fulfills parts (b-d) for two-qubit Cliffords."""
|
|
890
887
|
s1 = cliffords.s1
|
|
891
888
|
s1_x = cliffords.s1_x
|
|
@@ -916,9 +913,7 @@ def _two_qubit_clifford_mixers(
|
|
|
916
913
|
yield _single_qubit_gates(s1_x[idx_4], q_1)
|
|
917
914
|
|
|
918
915
|
|
|
919
|
-
def _single_qubit_gates(
|
|
920
|
-
gate_seq: Sequence['cirq.Gate'], qubit: 'cirq.Qid'
|
|
921
|
-
) -> Iterator['cirq.OP_TREE']:
|
|
916
|
+
def _single_qubit_gates(gate_seq: Sequence[cirq.Gate], qubit: cirq.Qid) -> Iterator[cirq.OP_TREE]:
|
|
922
917
|
for gate in gate_seq:
|
|
923
918
|
yield gate(qubit)
|
|
924
919
|
|