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.

Files changed (58) hide show
  1. cirq/_version.py +1 -1
  2. cirq/_version_test.py +1 -1
  3. cirq/devices/noise_model_test.py +3 -1
  4. cirq/devices/noise_properties.py +6 -4
  5. cirq/devices/noise_utils.py +8 -6
  6. cirq/devices/superconducting_qubits_noise_properties.py +10 -9
  7. cirq/devices/thermal_noise_model.py +12 -12
  8. cirq/devices/unconstrained_device.py +3 -1
  9. cirq/experiments/n_qubit_tomography.py +15 -12
  10. cirq/experiments/qubit_characterizations.py +34 -39
  11. cirq/experiments/random_quantum_circuit_generation.py +38 -38
  12. cirq/experiments/random_quantum_circuit_generation_test.py +7 -4
  13. cirq/experiments/readout_confusion_matrix.py +17 -15
  14. cirq/experiments/single_qubit_readout_calibration.py +9 -5
  15. cirq/experiments/single_qubit_readout_calibration_test.py +5 -2
  16. cirq/experiments/t1_decay_experiment.py +7 -5
  17. cirq/experiments/t2_decay_experiment.py +10 -7
  18. cirq/experiments/two_qubit_xeb.py +42 -43
  19. cirq/experiments/two_qubit_xeb_test.py +1 -1
  20. cirq/experiments/xeb_fitting.py +25 -21
  21. cirq/experiments/xeb_sampling.py +18 -14
  22. cirq/experiments/xeb_simulation.py +11 -7
  23. cirq/experiments/xeb_simulation_test.py +3 -3
  24. cirq/experiments/z_phase_calibration.py +27 -24
  25. cirq/experiments/z_phase_calibration_test.py +1 -4
  26. cirq/interop/quirk/cells/arithmetic_cells.py +11 -10
  27. cirq/interop/quirk/cells/cell.py +18 -15
  28. cirq/interop/quirk/cells/composite_cell.py +8 -8
  29. cirq/interop/quirk/cells/control_cells.py +14 -14
  30. cirq/interop/quirk/cells/frequency_space_cells.py +4 -3
  31. cirq/interop/quirk/cells/input_cells.py +6 -4
  32. cirq/interop/quirk/cells/input_rotation_cells.py +14 -12
  33. cirq/interop/quirk/cells/measurement_cells.py +4 -1
  34. cirq/interop/quirk/cells/qubit_permutation_cells.py +3 -1
  35. cirq/interop/quirk/cells/scalar_cells.py +4 -1
  36. cirq/interop/quirk/cells/single_qubit_rotation_cells.py +5 -2
  37. cirq/interop/quirk/cells/swap_cell.py +7 -5
  38. cirq/interop/quirk/cells/testing.py +1 -1
  39. cirq/interop/quirk/url_to_circuit.py +11 -8
  40. cirq/json_resolver_cache.py +5 -3
  41. cirq/linalg/decompositions.py +5 -4
  42. cirq/linalg/decompositions_test.py +1 -1
  43. cirq/linalg/operator_spaces.py +8 -8
  44. cirq/ops/arithmetic_operation.py +4 -2
  45. cirq/ops/boolean_hamiltonian.py +7 -6
  46. cirq/ops/classically_controlled_operation.py +23 -20
  47. cirq/ops/clifford_gate.py +43 -47
  48. cirq/ops/common_channels.py +16 -14
  49. cirq/ops/common_gates.py +49 -67
  50. cirq/ops/control_values.py +12 -15
  51. cirq/ops/controlled_gate.py +15 -17
  52. cirq/ops/controlled_operation.py +17 -15
  53. cirq/study/resolver.py +1 -1
  54. {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/METADATA +1 -1
  55. {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/RECORD +58 -58
  56. {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/WHEEL +0 -0
  57. {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/licenses/LICENSE +0 -0
  58. {cirq_core-1.6.0.dev20250416035400.dist-info → cirq_core-1.6.0.dev20250417204649.dist-info}/top_level.txt +0 -0
cirq/_version.py CHANGED
@@ -28,4 +28,4 @@ if sys.version_info < (3, 10, 0): # pragma: no cover
28
28
  'of cirq (e.g. "python -m pip install cirq==1.1.*")'
29
29
  )
30
30
 
31
- __version__ = "1.6.0.dev20250416035400"
31
+ __version__ = "1.6.0.dev20250417204649"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version():
6
- assert cirq.__version__ == "1.6.0.dev20250416035400"
6
+ assert cirq.__version__ == "1.6.0.dev20250417204649"
@@ -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: 'cirq.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()
@@ -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['cirq.NoiseModel']:
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: 'cirq.Operation') -> bool:
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['cirq.Moment'], system_qubits: Sequence['cirq.Qid']
71
- ) -> Sequence['cirq.OP_TREE']:
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 = []
@@ -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['cirq.Gate'], *qubits: 'cirq.Qid'):
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['cirq.Qid', ...] = tuple(qubits)
37
+ self._qubits: Tuple[cirq.Qid, ...] = tuple(qubits)
36
38
 
37
39
  @property
38
- def gate_type(self) -> Type['cirq.Gate']:
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['cirq.Qid', ...]:
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: 'OpIdentifier'):
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) -> 'OpIdentifier':
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['cirq.Qid', float]
53
- tphi_ns: Dict['cirq.Qid', float]
54
- readout_errors: Dict['cirq.Qid', List[float]]
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['cirq.Qid'] = field(init=False, default_factory=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['cirq.Qid']:
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['cirq.NoiseModel']:
154
- noise_models: List['cirq.NoiseModel'] = []
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, 'cirq.Operation'] = {}
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['cirq.Qid', float]]], qubits: Set['cirq.Qid']
133
- ) -> Dict['cirq.Qid', float]:
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['cirq.Qid'], rates: Dict['cirq.Qid', np.ndarray]) -> None:
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['cirq.Qid'],
174
+ qubits: Set[cirq.Qid],
173
175
  gate_durations_ns: Dict[type, float],
174
- heat_rate_GHz: Union[float, Dict['cirq.Qid', float], None] = None,
175
- cool_rate_GHz: Union[float, Dict['cirq.Qid', float], None] = None,
176
- dephase_rate_GHz: Union[float, Dict['cirq.Qid', float], None] = None,
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['cirq.Qid', np.ndarray] = rate_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['cirq.Operation'] = []
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: 'cirq.Operation') -> 'cirq.Duration':
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['cirq.Qid'],
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['cirq.Operation'] = []
73
- sweeps: List['cirq.Sweep'] = []
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['cirq.Qid']) -> np.ndarray:
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: 'cirq.Sampler',
134
- qubits: Sequence['cirq.Qid'],
135
- circuit: 'cirq.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: 'cirq.Sampler',
170
- qubits: Sequence['cirq.Qid'],
171
- circuit: 'cirq.Circuit',
172
- rot_circuit: 'cirq.Circuit',
173
- rot_sweep: 'cirq.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['cirq.Qid', 'RandomizedBenchMarkResult']
155
+ results_dictionary: Mapping[cirq.Qid, RandomizedBenchMarkResult]
154
156
 
155
157
  def plot_single_qubit(
156
- self, qubit: 'cirq.Qid', ax: Optional[plt.Axes] = None, **plot_kwargs: Any
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['cirq.Qid', float]:
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: 'cirq.Sampler',
346
- qubit: 'cirq.Qid',
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: 'cirq.Sampler',
400
- qubits: Sequence['cirq.Qid'],
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
- ) -> 'ParallelRandomizedBenchmarkingResult':
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['cirq.AbstractCircuit'] = []
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['cirq.Qid', List[float]] = {q: [] for q in qubits}
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: 'cirq.Sampler',
458
- first_qubit: 'cirq.Qid',
459
- second_qubit: 'cirq.Qid',
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: 'cirq.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: 'cirq.Sampler',
564
- first_qubit: 'cirq.Qid',
565
- second_qubit: 'cirq.Qid',
566
- circuit: 'cirq.AbstractCircuit',
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['cirq.Qid'], num_cliffords: int, c1: list
692
- ) -> 'cirq.Circuit':
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: 'cirq.Qid', num_cfds: int, cfds: Sequence[Sequence['cirq.ops.SingleQubitCliffordGate']]
747
- ) -> List['cirq.Operation']:
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: 'cirq.Qid', q_1: 'cirq.Qid', num_cfds: int, cfd_matrices: np.ndarray, cliffords: Cliffords
759
- ) -> 'cirq.Circuit':
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: 'cirq.Qid', q_1: 'cirq.Qid', idx: int, cliffords: Cliffords
823
- ) -> Iterator['cirq.OP_TREE']:
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: 'cirq.Qid', q_1: 'cirq.Qid', idx_0: int, idx_1: int, cliffords: Cliffords
879
- ) -> Iterator['cirq.OP_TREE']:
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: 'cirq.Qid', q_1: 'cirq.Qid', idx_2: int, cliffords: Cliffords
888
- ) -> Iterator['cirq.OP_TREE']:
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