cirq-core 1.7.0.dev20250806162852__py3-none-any.whl → 1.7.0.dev20250812001555__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 (61) hide show
  1. cirq/_version.py +1 -1
  2. cirq/_version_test.py +1 -1
  3. cirq/contrib/noise_models/noise_models.py +8 -8
  4. cirq/contrib/quimb/grid_circuits.py +1 -1
  5. cirq/contrib/quimb/grid_circuits_test.py +10 -5
  6. cirq/contrib/quimb/mps_simulator.py +3 -3
  7. cirq/contrib/quimb/mps_simulator_test.py +41 -42
  8. cirq/contrib/quimb/state_vector_test.py +14 -13
  9. cirq/contrib/quirk/export_to_quirk_test.py +2 -2
  10. cirq/contrib/quirk/linearize_circuit.py +1 -1
  11. cirq/contrib/routing/device.py +1 -1
  12. cirq/contrib/routing/device_test.py +7 -5
  13. cirq/contrib/routing/greedy_test.py +7 -2
  14. cirq/contrib/routing/initialization_test.py +1 -1
  15. cirq/contrib/routing/router_test.py +9 -10
  16. cirq/contrib/routing/swap_network_test.py +10 -4
  17. cirq/contrib/routing/utils_test.py +4 -4
  18. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +9 -9
  19. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +18 -16
  20. cirq/contrib/svg/svg.py +1 -1
  21. cirq/devices/grid_device_metadata_test.py +12 -12
  22. cirq/devices/grid_qubit_test.py +52 -52
  23. cirq/devices/line_qubit_test.py +37 -37
  24. cirq/devices/named_topologies.py +7 -5
  25. cirq/devices/named_topologies_test.py +3 -2
  26. cirq/devices/noise_model.py +1 -1
  27. cirq/devices/noise_properties_test.py +1 -1
  28. cirq/devices/noise_utils.py +1 -1
  29. cirq/devices/noise_utils_test.py +6 -6
  30. cirq/devices/superconducting_qubits_noise_properties_test.py +31 -24
  31. cirq/devices/thermal_noise_model_test.py +48 -44
  32. cirq/devices/unconstrained_device.py +1 -1
  33. cirq/devices/unconstrained_device_test.py +3 -3
  34. cirq/experiments/benchmarking/parallel_xeb.py +24 -17
  35. cirq/experiments/benchmarking/parallel_xeb_test.py +42 -28
  36. cirq/experiments/fidelity_estimation.py +5 -5
  37. cirq/experiments/fidelity_estimation_test.py +7 -7
  38. cirq/experiments/purity_estimation.py +1 -1
  39. cirq/experiments/purity_estimation_test.py +1 -1
  40. cirq/experiments/qubit_characterizations_test.py +10 -10
  41. cirq/experiments/random_quantum_circuit_generation.py +1 -1
  42. cirq/experiments/random_quantum_circuit_generation_test.py +18 -13
  43. cirq/experiments/readout_confusion_matrix_test.py +12 -8
  44. cirq/experiments/single_qubit_readout_calibration_test.py +13 -13
  45. cirq/experiments/t2_decay_experiment.py +1 -1
  46. cirq/experiments/t2_decay_experiment_test.py +13 -13
  47. cirq/experiments/two_qubit_xeb_test.py +20 -22
  48. cirq/experiments/xeb_fitting.py +3 -3
  49. cirq/experiments/xeb_fitting_test.py +21 -19
  50. cirq/experiments/xeb_sampling.py +2 -2
  51. cirq/experiments/xeb_sampling_test.py +9 -9
  52. cirq/experiments/xeb_simulation.py +1 -1
  53. cirq/experiments/xeb_simulation_test.py +6 -6
  54. cirq/ops/measure_util.py +2 -0
  55. cirq/transformers/eject_phased_paulis.py +2 -19
  56. cirq/transformers/eject_phased_paulis_test.py +3 -51
  57. {cirq_core-1.7.0.dev20250806162852.dist-info → cirq_core-1.7.0.dev20250812001555.dist-info}/METADATA +1 -1
  58. {cirq_core-1.7.0.dev20250806162852.dist-info → cirq_core-1.7.0.dev20250812001555.dist-info}/RECORD +61 -61
  59. {cirq_core-1.7.0.dev20250806162852.dist-info → cirq_core-1.7.0.dev20250812001555.dist-info}/WHEEL +0 -0
  60. {cirq_core-1.7.0.dev20250806162852.dist-info → cirq_core-1.7.0.dev20250812001555.dist-info}/licenses/LICENSE +0 -0
  61. {cirq_core-1.7.0.dev20250806162852.dist-info → cirq_core-1.7.0.dev20250812001555.dist-info}/top_level.txt +0 -0
@@ -14,6 +14,8 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ from typing import Any, Sequence
18
+
17
19
  import numpy as np
18
20
  import pytest
19
21
 
@@ -37,7 +39,9 @@ DEFAULT_GATE_NS: dict[type, float] = {
37
39
  }
38
40
 
39
41
 
40
- def default_props(system_qubits: list[cirq.Qid], qubit_pairs: list[tuple[cirq.Qid, cirq.Qid]]):
42
+ def default_props(
43
+ system_qubits: Sequence[cirq.Qid], qubit_pairs: Sequence[tuple[cirq.Qid, cirq.Qid]]
44
+ ) -> dict[str, Any]:
41
45
  return {
42
46
  'gate_times_ns': DEFAULT_GATE_NS,
43
47
  't1_ns': {q: 1e5 for q in system_qubits},
@@ -75,7 +79,7 @@ class ExampleNoiseProperties(SuperconductingQubitsNoiseProperties):
75
79
  return set()
76
80
 
77
81
 
78
- def test_init_validation():
82
+ def test_init_validation() -> None:
79
83
  q0, q1, q2 = cirq.LineQubit.range(3)
80
84
  with pytest.raises(ValueError, match='Keys specified for T1 and Tphi are not identical.'):
81
85
  _ = ExampleNoiseProperties(
@@ -92,7 +96,7 @@ def test_init_validation():
92
96
  t1_ns={q0: 1},
93
97
  tphi_ns={q0: 1},
94
98
  readout_errors={q0: [0.1, 0.2]},
95
- gate_pauli_errors={OpIdentifier(cirq.CCNOT, q0, q1, q2): 0.1},
99
+ gate_pauli_errors={OpIdentifier(type(cirq.CCNOT), q0, q1, q2): 0.1},
96
100
  )
97
101
 
98
102
  with pytest.raises(ValueError, match='does not appear in the symmetric or asymmetric'):
@@ -102,8 +106,8 @@ def test_init_validation():
102
106
  tphi_ns={q0: 1},
103
107
  readout_errors={q0: [0.1, 0.2]},
104
108
  gate_pauli_errors={
105
- OpIdentifier(cirq.CNOT, q0, q1): 0.1,
106
- OpIdentifier(cirq.CNOT, q1, q0): 0.1,
109
+ OpIdentifier(cirq.CNotPowGate, q0, q1): 0.1,
110
+ OpIdentifier(cirq.CNotPowGate, q1, q0): 0.1,
107
111
  },
108
112
  )
109
113
 
@@ -136,18 +140,19 @@ def test_init_validation():
136
140
  # All errors are ignored if validation is disabled.
137
141
  _ = ExampleNoiseProperties(
138
142
  gate_times_ns=DEFAULT_GATE_NS,
139
- t1_ns={},
143
+ # t1_ns={},
144
+ t1_ns={q0: 1},
140
145
  tphi_ns={q0: 1},
141
146
  readout_errors={q0: [0.1, 0.2]},
142
147
  gate_pauli_errors={
143
- OpIdentifier(cirq.CCNOT, q0, q1, q2): 0.1,
144
- OpIdentifier(cirq.CNOT, q0, q1): 0.1,
148
+ OpIdentifier(type(cirq.CCNOT), q0, q1, q2): 0.1,
149
+ OpIdentifier(type(cirq.CNOT), q0, q1): 0.1,
145
150
  },
146
151
  validate=False,
147
152
  )
148
153
 
149
154
 
150
- def test_qubits():
155
+ def test_qubits() -> None:
151
156
  q0 = cirq.LineQubit(0)
152
157
  props = ExampleNoiseProperties(**default_props([q0], []))
153
158
  assert props.qubits == [q0]
@@ -155,7 +160,7 @@ def test_qubits():
155
160
  assert props.qubits == [q0]
156
161
 
157
162
 
158
- def test_depol_memoization():
163
+ def test_depol_memoization() -> None:
159
164
  # Verify that depolarizing error is memoized.
160
165
  q0 = cirq.LineQubit(0)
161
166
  props = ExampleNoiseProperties(**default_props([q0], []))
@@ -165,7 +170,7 @@ def test_depol_memoization():
165
170
  assert depol_error_a is depol_error_b
166
171
 
167
172
 
168
- def test_depol_validation():
173
+ def test_depol_validation() -> None:
169
174
  q0, q1, q2 = cirq.LineQubit.range(3)
170
175
  # Create unvalidated properties with too many qubits on a Z gate.
171
176
  z_2q_props = ExampleNoiseProperties(
@@ -213,7 +218,7 @@ def test_depol_validation():
213
218
  ),
214
219
  ],
215
220
  )
216
- def test_single_qubit_gates(op):
221
+ def test_single_qubit_gates(op) -> None:
217
222
  q0 = cirq.LineQubit(0)
218
223
  props = ExampleNoiseProperties(**default_props([q0], []))
219
224
  model = NoiseModelFromNoiseProperties(props)
@@ -237,10 +242,10 @@ def test_single_qubit_gates(op):
237
242
  assert np.allclose(
238
243
  thermal_choi,
239
244
  [
240
- [1, 0, 0, 9.99750031e-01],
241
- [0, 2.49968753e-04, 0, 0],
242
- [0, 0, 0, 0],
243
- [9.99750031e-01, 0, 0, 9.99750031e-01],
245
+ [1.0, 0.0, 0.0, 9.99750031e-01],
246
+ [0.0, 2.49968753e-04, 0.0, 0.0],
247
+ [0.0, 0.0, 0.0, 0.0],
248
+ [9.99750031e-01, 0.0, 0.0, 9.99750031e-01],
244
249
  ],
245
250
  )
246
251
 
@@ -248,7 +253,7 @@ def test_single_qubit_gates(op):
248
253
  @pytest.mark.parametrize(
249
254
  'op', [cirq.ISWAP(*cirq.LineQubit.range(2)) ** 0.6, cirq.CZ(*cirq.LineQubit.range(2)) ** 0.3]
250
255
  )
251
- def test_two_qubit_gates(op):
256
+ def test_two_qubit_gates(op) -> None:
252
257
  q0, q1 = cirq.LineQubit.range(2)
253
258
  props = ExampleNoiseProperties(**default_props([q0, q1], [(q0, q1), (q1, q0)]))
254
259
  model = NoiseModelFromNoiseProperties(props)
@@ -268,6 +273,8 @@ def test_two_qubit_gates(op):
268
273
  assert len(noisy_circuit.moments[2].operations) == 2
269
274
  thermal_op_0 = noisy_circuit.moments[2].operation_at(q0)
270
275
  thermal_op_1 = noisy_circuit.moments[2].operation_at(q1)
276
+ assert thermal_op_0 is not None
277
+ assert thermal_op_1 is not None
271
278
  assert isinstance(thermal_op_0.gate, cirq.KrausChannel)
272
279
  assert isinstance(thermal_op_1.gate, cirq.KrausChannel)
273
280
  thermal_choi_0 = cirq.kraus_to_choi(cirq.kraus(thermal_op_0))
@@ -284,7 +291,7 @@ def test_two_qubit_gates(op):
284
291
  assert np.allclose(thermal_choi_1, expected_thermal_choi)
285
292
 
286
293
 
287
- def test_measure_gates():
294
+ def test_measure_gates() -> None:
288
295
  q00, q01, q10, q11 = cirq.GridQubit.rect(2, 2)
289
296
  qubits = [q00, q01, q10, q11]
290
297
  props = ExampleNoiseProperties(
@@ -311,7 +318,7 @@ def test_measure_gates():
311
318
  # Amplitude damping before measurement
312
319
  assert len(noisy_circuit.moments[0].operations) == 4
313
320
  for q in qubits:
314
- op = noisy_circuit.moments[0].operation_at(q)
321
+ op = noisy_circuit.moments[0].operation_at(q) # type: ignore[assignment]
315
322
  assert isinstance(op.gate, cirq.GeneralizedAmplitudeDampingChannel), q
316
323
  assert np.isclose(op.gate.p, 0.90909090), q
317
324
  assert np.isclose(op.gate.gamma, 0.011), q
@@ -322,7 +329,7 @@ def test_measure_gates():
322
329
  assert noisy_circuit.moments[1] == circuit.moments[0]
323
330
 
324
331
 
325
- def test_wait_gates():
332
+ def test_wait_gates() -> None:
326
333
  q0 = cirq.LineQubit(0)
327
334
  props = ExampleNoiseProperties(**default_props([q0], []))
328
335
  model = NoiseModelFromNoiseProperties(props)
@@ -341,9 +348,9 @@ def test_wait_gates():
341
348
  assert np.allclose(
342
349
  thermal_choi,
343
350
  [
344
- [1, 0, 0, 9.990005e-01],
345
- [0, 9.99500167e-04, 0, 0],
346
- [0, 0, 0, 0],
347
- [9.990005e-01, 0, 0, 9.990005e-01],
351
+ [1.0, 0.0, 0.0, 9.990005e-01],
352
+ [0.0, 9.99500167e-04, 0.0, 0.0],
353
+ [0.0, 0.0, 0.0, 0.0],
354
+ [9.990005e-01, 0.0, 0.0, 9.990005e-01],
348
355
  ],
349
356
  )
@@ -28,7 +28,7 @@ from cirq.devices.thermal_noise_model import (
28
28
  )
29
29
 
30
30
 
31
- def test_helper_method_errors():
31
+ def test_helper_method_errors() -> None:
32
32
  with pytest.raises(ValueError, match='_left_mul only accepts square matrices'):
33
33
  _ = _left_mul(np.array([[1, 2, 3], [4, 5, 6]]))
34
34
 
@@ -49,12 +49,12 @@ def test_helper_method_errors():
49
49
  _validate_rates({q0}, {q0: np.array([[0.001, 0.01, 0.1], [0.002, 0.02, 0.2]])})
50
50
 
51
51
 
52
- def test_create_thermal_noise_per_qubit():
52
+ def test_create_thermal_noise_per_qubit() -> None:
53
53
  q0, q1 = cirq.LineQubit.range(2)
54
- gate_durations = {cirq.PhasedXZGate: 25.0}
55
- heat_rate_GHz = {q0: 1e-5, q1: 2e-5}
56
- cool_rate_GHz = {q0: 1e-4, q1: 2e-4}
57
- dephase_rate_GHz = {q0: 3e-4, q1: 4e-4}
54
+ gate_durations: dict[type, float] = {cirq.PhasedXZGate: 25.0}
55
+ heat_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-5, q1: 2e-5}
56
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4, q1: 2e-4}
57
+ dephase_rate_GHz: dict[cirq.Qid, float] = {q0: 3e-4, q1: 4e-4}
58
58
  model = ThermalNoiseModel(
59
59
  qubits={q0, q1},
60
60
  gate_durations_ns=gate_durations,
@@ -69,11 +69,11 @@ def test_create_thermal_noise_per_qubit():
69
69
  assert np.allclose(model.rate_matrix_GHz[q1], np.array([[0, 2e-4], [2e-5, 4e-4]]))
70
70
 
71
71
 
72
- def test_create_thermal_noise_mixed_type():
72
+ def test_create_thermal_noise_mixed_type() -> None:
73
73
  q0, q1 = cirq.LineQubit.range(2)
74
- gate_durations = {cirq.PhasedXZGate: 25.0}
74
+ gate_durations: dict[type, float] = {cirq.PhasedXZGate: 25.0}
75
75
  heat_rate_GHz = None
76
- cool_rate_GHz = {q0: 1e-4, q1: 2e-4}
76
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4, q1: 2e-4}
77
77
  dephase_rate_GHz = 3e-4
78
78
  model = ThermalNoiseModel(
79
79
  qubits={q0, q1},
@@ -89,11 +89,11 @@ def test_create_thermal_noise_mixed_type():
89
89
  assert np.allclose(model.rate_matrix_GHz[q1], np.array([[0, 2e-4], [0, 3e-4]]))
90
90
 
91
91
 
92
- def test_incomplete_rates():
92
+ def test_incomplete_rates() -> None:
93
93
  q0, q1 = cirq.LineQubit.range(2)
94
- gate_durations = {cirq.PhasedXZGate: 25.0}
95
- heat_rate_GHz = {q1: 1e-5}
96
- cool_rate_GHz = {q0: 1e-4}
94
+ gate_durations: dict[type, float] = {cirq.PhasedXZGate: 25.0}
95
+ heat_rate_GHz: dict[cirq.Qid, float] = {q1: 1e-5}
96
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4}
97
97
  model = ThermalNoiseModel(
98
98
  qubits={q0, q1},
99
99
  gate_durations_ns=gate_durations,
@@ -108,12 +108,12 @@ def test_incomplete_rates():
108
108
  assert np.allclose(model.rate_matrix_GHz[q1], np.array([[0, 0], [1e-5, 0]]))
109
109
 
110
110
 
111
- def test_noise_from_empty_moment():
111
+ def test_noise_from_empty_moment() -> None:
112
112
  # Verify that a moment with no duration has no noise.
113
113
  q0, q1 = cirq.LineQubit.range(2)
114
- gate_durations = {}
115
- heat_rate_GHz = {q1: 1e-5}
116
- cool_rate_GHz = {q0: 1e-4}
114
+ gate_durations: dict[type, float] = {}
115
+ heat_rate_GHz: dict[cirq.Qid, float] = {q1: 1e-5}
116
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4}
117
117
  model = ThermalNoiseModel(
118
118
  qubits={q0, q1},
119
119
  gate_durations_ns=gate_durations,
@@ -127,12 +127,12 @@ def test_noise_from_empty_moment():
127
127
  assert model.noisy_moment(moment, system_qubits=[q0, q1]) == [moment]
128
128
 
129
129
 
130
- def test_noise_from_zero_duration():
130
+ def test_noise_from_zero_duration() -> None:
131
131
  # Verify that a moment with no duration has no noise.
132
132
  q0, q1 = cirq.LineQubit.range(2)
133
- gate_durations = {}
134
- heat_rate_GHz = {q1: 1e-5}
135
- cool_rate_GHz = {q0: 1e-4}
133
+ gate_durations: dict[type, float] = {}
134
+ heat_rate_GHz: dict[cirq.Qid, float] = {q1: 1e-5}
135
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4}
136
136
  model = ThermalNoiseModel(
137
137
  qubits={q0, q1},
138
138
  gate_durations_ns=gate_durations,
@@ -146,13 +146,13 @@ def test_noise_from_zero_duration():
146
146
  assert model.noisy_moment(moment, system_qubits=[q0, q1]) == [moment]
147
147
 
148
148
 
149
- def test_noise_from_virtual_gates():
149
+ def test_noise_from_virtual_gates() -> None:
150
150
  # Verify that a moment with only virtual gates has no noise if
151
151
  # require_physical_tag is True.
152
152
  q0, q1 = cirq.LineQubit.range(2)
153
- gate_durations = {cirq.ZPowGate: 25.0}
154
- heat_rate_GHz = {q1: 1e-5}
155
- cool_rate_GHz = {q0: 1e-4}
153
+ gate_durations: dict[type, float] = {cirq.ZPowGate: 25.0}
154
+ heat_rate_GHz: dict[cirq.Qid, float] = {q1: 1e-5}
155
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4}
156
156
  model = ThermalNoiseModel(
157
157
  qubits={q0, q1},
158
158
  gate_durations_ns=gate_durations,
@@ -170,16 +170,16 @@ def test_noise_from_virtual_gates():
170
170
  _ = model.noisy_moment(part_virtual_moment, system_qubits=[q0, q1])
171
171
 
172
172
  model.require_physical_tag = False
173
- assert len(model.noisy_moment(moment, system_qubits=[q0, q1])) == 2
173
+ assert len(model.noisy_moment(moment, system_qubits=[q0, q1])) == 2 # type: ignore[arg-type]
174
174
 
175
175
 
176
- def test_noise_from_measurement():
176
+ def test_noise_from_measurement() -> None:
177
177
  # Verify that a moment with only measurement gates has no noise if
178
178
  # skip_measurements is True.
179
179
  q0, q1 = cirq.LineQubit.range(2)
180
- gate_durations = {cirq.ZPowGate: 25.0, cirq.MeasurementGate: 4000.0}
181
- heat_rate_GHz = {q1: 1e-5}
182
- cool_rate_GHz = {q0: 1e-4}
180
+ gate_durations: dict[type, float] = {cirq.ZPowGate: 25.0, cirq.MeasurementGate: 4000.0}
181
+ heat_rate_GHz: dict[cirq.Qid, float] = {q1: 1e-5}
182
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4}
183
183
  model = ThermalNoiseModel(
184
184
  qubits={q0, q1},
185
185
  gate_durations_ns=gate_durations,
@@ -193,13 +193,13 @@ def test_noise_from_measurement():
193
193
  assert model.noisy_moment(moment, system_qubits=[q0, q1]) == [moment]
194
194
 
195
195
  part_measure_moment = cirq.Moment(cirq.measure(q0, key='m'), cirq.Z(q1))
196
- assert len(model.noisy_moment(part_measure_moment, system_qubits=[q0, q1])) == 2
196
+ assert len(model.noisy_moment(part_measure_moment, system_qubits=[q0, q1])) == 2 # type: ignore[arg-type]
197
197
 
198
198
  model.skip_measurements = False
199
- assert len(model.noisy_moment(moment, system_qubits=[q0, q1])) == 2
199
+ assert len(model.noisy_moment(moment, system_qubits=[q0, q1])) == 2 # type: ignore[arg-type]
200
200
 
201
201
 
202
- def test_noisy_moment_one_qubit():
202
+ def test_noisy_moment_one_qubit() -> None:
203
203
  q0, q1 = cirq.LineQubit.range(2)
204
204
  model = ThermalNoiseModel(
205
205
  qubits={q0, q1},
@@ -212,6 +212,7 @@ def test_noisy_moment_one_qubit():
212
212
  gate = cirq.PhasedXZGate(x_exponent=1, z_exponent=0.5, axis_phase_exponent=0.25)
213
213
  moment = cirq.Moment(gate.on(q0))
214
214
  noisy_moment = model.noisy_moment(moment, system_qubits=[q0, q1])
215
+ assert isinstance(noisy_moment, list)
215
216
  assert noisy_moment[0] == moment
216
217
  # Noise applies to both qubits, even if only one is acted upon.
217
218
  assert len(noisy_moment[1]) == 2
@@ -227,7 +228,7 @@ def test_noisy_moment_one_qubit():
227
228
  )
228
229
 
229
230
 
230
- def test_noisy_moment_one_qubit_prepend():
231
+ def test_noisy_moment_one_qubit_prepend() -> None:
231
232
  q0, q1 = cirq.LineQubit.range(2)
232
233
  model = ThermalNoiseModel(
233
234
  qubits={q0, q1},
@@ -241,6 +242,7 @@ def test_noisy_moment_one_qubit_prepend():
241
242
  gate = cirq.PhasedXZGate(x_exponent=1, z_exponent=0.5, axis_phase_exponent=0.25)
242
243
  moment = cirq.Moment(gate.on(q0))
243
244
  noisy_moment = model.noisy_moment(moment, system_qubits=[q0, q1])
245
+ assert isinstance(noisy_moment, list)
244
246
  # Noise applies to both qubits, even if only one is acted upon.
245
247
  assert len(noisy_moment[0]) == 2
246
248
  noisy_choi = cirq.kraus_to_choi(cirq.kraus(noisy_moment[0].operations[0]))
@@ -257,12 +259,12 @@ def test_noisy_moment_one_qubit_prepend():
257
259
  assert noisy_moment[1] == moment
258
260
 
259
261
 
260
- def test_noise_from_wait():
262
+ def test_noise_from_wait() -> None:
261
263
  # Verify that wait-gate noise is duration-dependent.
262
264
  q0 = cirq.LineQubit(0)
263
- gate_durations = {cirq.ZPowGate: 25.0}
264
- heat_rate_GHz = {q0: 1e-5}
265
- cool_rate_GHz = {q0: 1e-4}
265
+ gate_durations: dict[type, float] = {cirq.ZPowGate: 25.0}
266
+ heat_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-5}
267
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4}
266
268
  model = ThermalNoiseModel(
267
269
  qubits={q0},
268
270
  gate_durations_ns=gate_durations,
@@ -274,6 +276,7 @@ def test_noise_from_wait():
274
276
  )
275
277
  moment = cirq.Moment(cirq.wait(q0, nanos=100))
276
278
  noisy_moment = model.noisy_moment(moment, system_qubits=[q0])
279
+ assert isinstance(noisy_moment, list)
277
280
  assert noisy_moment[0] == moment
278
281
  assert len(noisy_moment[1]) == 1
279
282
  noisy_choi = cirq.kraus_to_choi(cirq.kraus(noisy_moment[1].operations[0]))
@@ -288,11 +291,11 @@ def test_noise_from_wait():
288
291
  )
289
292
 
290
293
 
291
- def test_symbolic_times_for_wait_gate():
294
+ def test_symbolic_times_for_wait_gate() -> None:
292
295
  q0 = cirq.LineQubit(0)
293
- gate_durations = {cirq.ZPowGate: 25.0}
294
- heat_rate_GHz = {q0: 1e-5}
295
- cool_rate_GHz = {q0: 1e-4}
296
+ gate_durations: dict[type, float] = {cirq.ZPowGate: 25.0}
297
+ heat_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-5}
298
+ cool_rate_GHz: dict[cirq.Qid, float] = {q0: 1e-4}
296
299
  model = ThermalNoiseModel(
297
300
  qubits={q0},
298
301
  gate_durations_ns=gate_durations,
@@ -307,7 +310,7 @@ def test_symbolic_times_for_wait_gate():
307
310
  _ = model.noisy_moment(moment, system_qubits=[q0])
308
311
 
309
312
 
310
- def test_noisy_moment_two_qubit():
313
+ def test_noisy_moment_two_qubit() -> None:
311
314
  q0, q1 = cirq.LineQubit.range(2)
312
315
  model = ThermalNoiseModel(
313
316
  qubits={q0, q1},
@@ -320,6 +323,7 @@ def test_noisy_moment_two_qubit():
320
323
  gate = cirq.CZ**0.5
321
324
  moment = cirq.Moment(gate.on(q0, q1))
322
325
  noisy_moment = model.noisy_moment(moment, system_qubits=[q0, q1])
326
+ assert isinstance(noisy_moment, list)
323
327
  assert noisy_moment[0] == moment
324
328
  assert len(noisy_moment[1]) == 2
325
329
  noisy_choi_0 = cirq.kraus_to_choi(cirq.kraus(noisy_moment[1].operations[0]))
@@ -344,7 +348,7 @@ def test_noisy_moment_two_qubit():
344
348
  )
345
349
 
346
350
 
347
- def test_repr():
351
+ def test_repr() -> None:
348
352
  q0 = cirq.LineQubit(0)
349
353
  model = ThermalNoiseModel(
350
354
  qubits={q0},
@@ -47,5 +47,5 @@ class _UnconstrainedDevice(device.Device):
47
47
  return protocols.obj_to_dict_helper(self, [])
48
48
 
49
49
 
50
- UNCONSTRAINED_DEVICE: device.Device = _UnconstrainedDevice()
50
+ UNCONSTRAINED_DEVICE = _UnconstrainedDevice()
51
51
  document(UNCONSTRAINED_DEVICE, """A device with no constraints on operations or qubits.""")
@@ -17,17 +17,17 @@ from __future__ import annotations
17
17
  import cirq
18
18
 
19
19
 
20
- def test_repr():
20
+ def test_repr() -> None:
21
21
  cirq.testing.assert_equivalent_repr(cirq.UNCONSTRAINED_DEVICE)
22
22
 
23
23
 
24
- def test_infinitely_fast():
24
+ def test_infinitely_fast() -> None:
25
25
  assert cirq.UNCONSTRAINED_DEVICE.duration_of(cirq.X(cirq.NamedQubit('a'))) == cirq.Duration(
26
26
  picos=0
27
27
  )
28
28
 
29
29
 
30
- def test_any_qubit_works():
30
+ def test_any_qubit_works() -> None:
31
31
  moment = cirq.Moment([cirq.X(cirq.LineQubit(987654321))])
32
32
  cirq.UNCONSTRAINED_DEVICE.validate_moment(moment)
33
33
  cirq.UNCONSTRAINED_DEVICE.validate_circuit(cirq.Circuit(moment))
@@ -17,7 +17,7 @@
17
17
  from __future__ import annotations
18
18
 
19
19
  from concurrent import futures
20
- from typing import overload, Sequence, TYPE_CHECKING, Union
20
+ from typing import Iterable, Mapping, overload, Sequence, TYPE_CHECKING, Union
21
21
 
22
22
  import attrs
23
23
  import networkx as nx
@@ -34,14 +34,18 @@ if TYPE_CHECKING:
34
34
 
35
35
  _TARGET_T = Union['cirq.Gate', 'cirq.Operation', 'cirq.AbstractCircuit']
36
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]]]
37
+ _CANONICAL_TARGET_T = Union['cirq.Operation', Mapping[_QUBIT_PAIR_T, 'cirq.Operation']]
38
+ _PROBABILITIES_DICT_T = Mapping[_QUBIT_PAIR_T, list[list[np.ndarray]]]
39
39
 
40
40
 
41
41
  def _canonize_pair(pair: _QUBIT_PAIR_T) -> _QUBIT_PAIR_T:
42
42
  return min(pair), max(pair)
43
43
 
44
44
 
45
+ def _tuple_from_ints(seq: Iterable[int]) -> tuple[int, ...]:
46
+ return tuple(seq)
47
+
48
+
45
49
  @attrs.frozen
46
50
  class XEBParameters:
47
51
  """A frozen dataclass that holds the parameter of an XEB experiment.
@@ -56,7 +60,9 @@ class XEBParameters:
56
60
  n_repetitions: int = 10**4
57
61
  n_combinations: int = 10
58
62
  n_circuits: int = 20
59
- cycle_depths: tuple[int, ...] = attrs.field(default=(5, 25, 50, 100, 200, 300), converter=tuple)
63
+ cycle_depths: tuple[int, ...] = attrs.field(
64
+ default=(5, 25, 50, 100, 200, 300), converter=_tuple_from_ints
65
+ )
60
66
 
61
67
 
62
68
  @attrs.frozen
@@ -75,7 +81,7 @@ class XEBWideCircuitInfo:
75
81
  pairs: Sequence[_QUBIT_PAIR_T] = attrs.field(
76
82
  converter=lambda seq: [_canonize_pair(pair) for pair in seq]
77
83
  )
78
- narrow_template_indices: tuple[int, ...] = attrs.field(converter=tuple)
84
+ narrow_template_indices: tuple[int, ...] = attrs.field(converter=_tuple_from_ints)
79
85
  cycle_depth: int | None = None
80
86
 
81
87
  @staticmethod
@@ -166,7 +172,7 @@ def _target_to_operation(target: _TARGET_T) -> cirq.Operation:
166
172
  return target
167
173
 
168
174
 
169
- def _canonize_target(target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T]) -> _CANONICAL_TARGET_T:
175
+ def _canonize_target(target: _TARGET_T | Mapping[_QUBIT_PAIR_T, _TARGET_T]) -> _CANONICAL_TARGET_T:
170
176
  if isinstance(target, (ops.Gate, ops.Operation, circuits.AbstractCircuit)):
171
177
  return _target_to_operation(target)
172
178
  return {k: _target_to_operation(v) for k, v in target.items()}
@@ -272,10 +278,10 @@ def simulate_circuit_library(
272
278
  @overload
273
279
  def simulate_circuit_library(
274
280
  circuit_templates: Sequence[cirq.Circuit],
275
- target_or_dict: dict[_QUBIT_PAIR_T, ops.Operation],
281
+ target_or_dict: Mapping[_QUBIT_PAIR_T, ops.Operation],
276
282
  cycle_depths: Sequence[int],
277
283
  pool: futures.Executor | None = None,
278
- ) -> dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]: ...
284
+ ) -> Mapping[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]: ...
279
285
 
280
286
 
281
287
  def simulate_circuit_library(
@@ -283,7 +289,7 @@ def simulate_circuit_library(
283
289
  target_or_dict: _CANONICAL_TARGET_T,
284
290
  cycle_depths: Sequence[int],
285
291
  pool: futures.Executor | None = None,
286
- ) -> Sequence[Sequence[np.ndarray]] | dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]:
292
+ ) -> Sequence[Sequence[np.ndarray]] | Mapping[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]:
287
293
  """Simulate the given sequence of circuits.
288
294
 
289
295
  Args:
@@ -407,15 +413,16 @@ def _reshape_sampling_results(
407
413
 
408
414
  def _reshape_simulation_results(
409
415
  simulation_results: (
410
- Sequence[Sequence[np.ndarray]] | dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
416
+ Sequence[Sequence[np.ndarray]] | Mapping[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
411
417
  ),
412
418
  cycle_depths: Sequence[int],
413
419
  pairs: Sequence[_QUBIT_PAIR_T],
414
420
  num_templates: int,
415
421
  ) -> _PROBABILITIES_DICT_T:
422
+ cycle_depth_to_index: dict[int, int]
416
423
  cycle_depth_to_index = {d: i for i, d in enumerate(cycle_depths)}
417
424
 
418
- if isinstance(simulation_results, dict):
425
+ if isinstance(simulation_results, Mapping):
419
426
  pure_probabilities = {
420
427
  pair: [[np.empty(0)] * num_templates for _ in range(len(cycle_depths))]
421
428
  for pair in pairs
@@ -463,7 +470,7 @@ def _cross_entropy(p: np.ndarray, q: np.ndarray, eps: float = 1e-60) -> float:
463
470
  def estimate_fidelities(
464
471
  sampling_results: Sequence[dict[str, np.ndarray]],
465
472
  simulation_results: (
466
- Sequence[Sequence[np.ndarray]] | dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
473
+ Sequence[Sequence[np.ndarray]] | Mapping[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
467
474
  ),
468
475
  cycle_depths: Sequence[int],
469
476
  wide_circuits_info: Sequence[XEBWideCircuitInfo],
@@ -525,7 +532,7 @@ def estimate_fidelities(
525
532
 
526
533
  def _extract_pairs(
527
534
  sampler: cirq.Sampler,
528
- target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T],
535
+ target: _TARGET_T | Mapping[_QUBIT_PAIR_T, _TARGET_T],
529
536
  qubits: Sequence[cirq.GridQubit] | None,
530
537
  pairs: Sequence[_QUBIT_PAIR_T] | None,
531
538
  ) -> Sequence[_QUBIT_PAIR_T]:
@@ -545,8 +552,8 @@ def _extract_pairs(
545
552
 
546
553
  def parallel_xeb_workflow(
547
554
  sampler: cirq.Sampler,
548
- target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T],
549
- ideal_target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T] | None = None,
555
+ target: _TARGET_T | Mapping[_QUBIT_PAIR_T, _TARGET_T],
556
+ ideal_target: _TARGET_T | Mapping[_QUBIT_PAIR_T, _TARGET_T] | None = None,
550
557
  qubits: Sequence[cirq.GridQubit] | None = None,
551
558
  pairs: Sequence[_QUBIT_PAIR_T] | None = None,
552
559
  parameters: XEBParameters = XEBParameters(),
@@ -644,8 +651,8 @@ def parallel_xeb_workflow(
644
651
 
645
652
  def parallel_two_qubit_xeb(
646
653
  sampler: cirq.Sampler,
647
- target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T],
648
- ideal_target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T] | None = None,
654
+ target: _TARGET_T | Mapping[_QUBIT_PAIR_T, _TARGET_T],
655
+ ideal_target: _TARGET_T | Mapping[_QUBIT_PAIR_T, _TARGET_T] | None = None,
649
656
  qubits: Sequence[cirq.GridQubit] | None = None,
650
657
  pairs: Sequence[_QUBIT_PAIR_T] | None = None,
651
658
  parameters: XEBParameters = XEBParameters(),