cirq-core 1.2.0.dev20230717225858__py3-none-any.whl → 1.3.0__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.
Files changed (158) hide show
  1. cirq/__init__.py +5 -0
  2. cirq/_compat.py +26 -11
  3. cirq/_compat_test.py +37 -3
  4. cirq/_version.py +31 -1
  5. cirq/_version_test.py +1 -1
  6. cirq/circuits/circuit.py +106 -32
  7. cirq/circuits/circuit_operation.py +2 -2
  8. cirq/circuits/circuit_operation_test.py +1 -1
  9. cirq/circuits/circuit_test.py +109 -3
  10. cirq/circuits/frozen_circuit.py +80 -5
  11. cirq/circuits/frozen_circuit_test.py +47 -2
  12. cirq/circuits/qasm_output_test.py +9 -9
  13. cirq/conftest.py +1 -2
  14. cirq/contrib/acquaintance/devices.py +1 -1
  15. cirq/contrib/hacks/disable_validation_test.py +1 -1
  16. cirq/contrib/noise_models/noise_models.py +1 -2
  17. cirq/contrib/paulistring/clifford_optimize.py +1 -1
  18. cirq/contrib/paulistring/clifford_target_gateset_test.py +4 -4
  19. cirq/contrib/qcircuit/qcircuit_pdf.py +1 -1
  20. cirq/contrib/quimb/density_matrix.py +2 -3
  21. cirq/contrib/quimb/grid_circuits.py +3 -3
  22. cirq/contrib/quimb/state_vector.py +3 -5
  23. cirq/contrib/routing/utils.py +1 -2
  24. cirq/contrib/svg/svg.py +4 -6
  25. cirq/devices/grid_qubit.py +49 -38
  26. cirq/devices/grid_qubit_test.py +1 -3
  27. cirq/devices/insertion_noise_model.py +21 -1
  28. cirq/devices/insertion_noise_model_test.py +6 -0
  29. cirq/devices/line_qubit.py +67 -40
  30. cirq/devices/named_topologies.py +8 -14
  31. cirq/devices/noise_properties.py +1 -1
  32. cirq/devices/noise_utils.py +7 -5
  33. cirq/devices/noise_utils_test.py +7 -0
  34. cirq/experiments/fidelity_estimation_test.py +1 -1
  35. cirq/experiments/qubit_characterizations.py +6 -5
  36. cirq/experiments/random_quantum_circuit_generation.py +1 -1
  37. cirq/experiments/random_quantum_circuit_generation_test.py +28 -1
  38. cirq/experiments/readout_confusion_matrix.py +6 -6
  39. cirq/experiments/xeb_fitting.py +3 -5
  40. cirq/experiments/xeb_fitting_test.py +2 -2
  41. cirq/experiments/xeb_sampling.py +1 -1
  42. cirq/interop/quirk/url_to_circuit.py +40 -38
  43. cirq/json_resolver_cache.py +2 -0
  44. cirq/linalg/decompositions.py +6 -5
  45. cirq/ops/__init__.py +2 -0
  46. cirq/ops/classically_controlled_operation.py +1 -1
  47. cirq/ops/clifford_gate.py +9 -9
  48. cirq/ops/clifford_gate_test.py +3 -4
  49. cirq/ops/common_channels.py +2 -5
  50. cirq/ops/common_channels_test.py +3 -5
  51. cirq/ops/common_gates_test.py +7 -7
  52. cirq/ops/controlled_operation_test.py +2 -2
  53. cirq/ops/dense_pauli_string.py +3 -0
  54. cirq/ops/eigen_gate_test.py +1 -3
  55. cirq/ops/fourier_transform.py +1 -2
  56. cirq/ops/fsim_gate.py +1 -1
  57. cirq/ops/gate_features_test.py +2 -2
  58. cirq/ops/gate_operation_test.py +1 -2
  59. cirq/ops/greedy_qubit_manager.py +86 -0
  60. cirq/ops/greedy_qubit_manager_test.py +98 -0
  61. cirq/ops/linear_combinations.py +1 -1
  62. cirq/ops/named_qubit.py +55 -18
  63. cirq/ops/parity_gates.py +65 -18
  64. cirq/ops/parity_gates_test.py +41 -2
  65. cirq/ops/pauli_gates.py +2 -2
  66. cirq/ops/pauli_string.py +3 -4
  67. cirq/ops/pauli_string_raw_types_test.py +3 -3
  68. cirq/ops/pauli_string_test.py +3 -4
  69. cirq/ops/random_gate_channel_test.py +3 -3
  70. cirq/ops/raw_types.py +1 -1
  71. cirq/ops/raw_types_test.py +5 -5
  72. cirq/ops/three_qubit_gates.py +12 -8
  73. cirq/protocols/act_on_protocol_test.py +9 -9
  74. cirq/protocols/apply_channel_protocol.py +9 -6
  75. cirq/protocols/apply_unitary_protocol_test.py +1 -1
  76. cirq/protocols/equal_up_to_global_phase_protocol_test.py +2 -2
  77. cirq/protocols/has_stabilizer_effect_protocol.py +52 -6
  78. cirq/protocols/has_stabilizer_effect_protocol_test.py +21 -8
  79. cirq/protocols/has_unitary_protocol_test.py +1 -3
  80. cirq/protocols/json_serialization.py +6 -6
  81. cirq/protocols/json_serialization_test.py +7 -14
  82. cirq/protocols/json_test_data/InsertionNoiseModel.json +91 -0
  83. cirq/protocols/json_test_data/InsertionNoiseModel.repr +4 -0
  84. cirq/protocols/json_test_data/OpIdentifier.json +45 -10
  85. cirq/protocols/json_test_data/OpIdentifier.repr +7 -1
  86. cirq/protocols/json_test_data/spec.py +4 -0
  87. cirq/protocols/measurement_key_protocol_test.py +1 -1
  88. cirq/protocols/unitary_protocol_test.py +13 -16
  89. cirq/qis/clifford_tableau.py +7 -8
  90. cirq/qis/measures.py +1 -1
  91. cirq/qis/states.py +2 -3
  92. cirq/sim/__init__.py +2 -0
  93. cirq/sim/classical_simulator.py +107 -0
  94. cirq/sim/classical_simulator_test.py +207 -0
  95. cirq/sim/clifford/clifford_simulator_test.py +7 -7
  96. cirq/sim/clifford/stabilizer_simulation_state.py +2 -2
  97. cirq/sim/clifford/stabilizer_state_ch_form.py +7 -7
  98. cirq/sim/density_matrix_simulation_state.py +19 -4
  99. cirq/sim/density_matrix_simulator_test.py +5 -13
  100. cirq/sim/simulation_state_test.py +13 -14
  101. cirq/sim/simulator_test.py +6 -9
  102. cirq/sim/state_vector_simulation_state.py +1 -1
  103. cirq/study/resolver.py +41 -41
  104. cirq/study/resolver_test.py +13 -12
  105. cirq/testing/__init__.py +4 -1
  106. cirq/testing/circuit_compare.py +1 -1
  107. cirq/testing/circuit_compare_test.py +11 -11
  108. cirq/testing/consistent_controlled_gate_op.py +15 -1
  109. cirq/testing/consistent_controlled_gate_op_test.py +12 -3
  110. cirq/testing/consistent_decomposition.py +0 -1
  111. cirq/testing/consistent_protocols.py +6 -1
  112. cirq/testing/consistent_protocols_test.py +5 -10
  113. cirq/testing/consistent_qasm.py +2 -4
  114. cirq/testing/consistent_qasm_test.py +2 -3
  115. cirq/testing/consistent_specified_has_unitary_test.py +1 -3
  116. cirq/testing/equals_tester.py +1 -1
  117. cirq/testing/equals_tester_test.py +5 -5
  118. cirq/testing/equivalent_repr_eval_test.py +1 -3
  119. cirq/testing/gate_features_test.py +6 -6
  120. cirq/testing/order_tester_test.py +1 -3
  121. cirq/testing/random_circuit_test.py +1 -3
  122. cirq/transformers/__init__.py +3 -0
  123. cirq/transformers/analytical_decompositions/__init__.py +1 -0
  124. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +1 -2
  125. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +2 -5
  126. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +38 -0
  127. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +18 -0
  128. cirq/transformers/expand_composite_test.py +4 -4
  129. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +1 -1
  130. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -2
  131. cirq/transformers/merge_k_qubit_gates_test.py +2 -2
  132. cirq/transformers/qubit_management_transformers.py +177 -0
  133. cirq/transformers/qubit_management_transformers_test.py +250 -0
  134. cirq/transformers/routing/route_circuit_cqc.py +23 -4
  135. cirq/transformers/routing/route_circuit_cqc_test.py +42 -0
  136. cirq/transformers/stratify.py +10 -11
  137. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +10 -10
  138. cirq/transformers/target_gatesets/cz_gateset_test.py +8 -10
  139. cirq/transformers/transformer_primitives.py +138 -28
  140. cirq/value/abc_alt_test.py +4 -4
  141. cirq/value/duration.py +68 -37
  142. cirq/value/duration_test.py +2 -0
  143. cirq/value/measurement_key_test.py +1 -1
  144. cirq/value/product_state.py +4 -8
  145. cirq/value/value_equality_attr.py +12 -5
  146. cirq/vis/heatmap.py +7 -4
  147. cirq/vis/heatmap_test.py +14 -4
  148. cirq/vis/histogram.py +4 -4
  149. cirq/vis/state_histogram.py +10 -6
  150. cirq/vis/state_histogram_test.py +2 -0
  151. cirq/work/observable_measurement_data_test.py +1 -1
  152. cirq/work/observable_measurement_test.py +2 -2
  153. cirq/work/zeros_sampler.py +1 -1
  154. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/METADATA +11 -19
  155. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/RECORD +158 -150
  156. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/WHEEL +1 -1
  157. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/LICENSE +0 -0
  158. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/top_level.txt +0 -0
@@ -19,7 +19,7 @@ from typing_extensions import Self
19
19
 
20
20
  import numpy as np
21
21
 
22
- from cirq import _compat, ops, protocols
22
+ from cirq import ops, protocols
23
23
 
24
24
  if TYPE_CHECKING:
25
25
  import cirq
@@ -29,9 +29,43 @@ if TYPE_CHECKING:
29
29
  class _BaseGridQid(ops.Qid):
30
30
  """The Base class for `GridQid` and `GridQubit`."""
31
31
 
32
- def __init__(self, row: int, col: int):
33
- self._row = row
34
- self._col = col
32
+ _row: int
33
+ _col: int
34
+ _dimension: int
35
+ _hash: Optional[int] = None
36
+
37
+ def __getstate__(self):
38
+ # Don't save hash when pickling; see #3777.
39
+ state = self.__dict__
40
+ if "_hash" in state:
41
+ state = state.copy()
42
+ del state["_hash"]
43
+ return state
44
+
45
+ def __hash__(self) -> int:
46
+ if self._hash is None:
47
+ self._hash = hash((self._row, self._col, self._dimension))
48
+ return self._hash
49
+
50
+ def __eq__(self, other):
51
+ # Explicitly implemented for performance (vs delegating to Qid).
52
+ if isinstance(other, _BaseGridQid):
53
+ return (
54
+ self._row == other._row
55
+ and self._col == other._col
56
+ and self._dimension == other._dimension
57
+ )
58
+ return NotImplemented
59
+
60
+ def __ne__(self, other):
61
+ # Explicitly implemented for performance (vs delegating to Qid).
62
+ if isinstance(other, _BaseGridQid):
63
+ return (
64
+ self._row != other._row
65
+ or self._col != other._col
66
+ or self._dimension != other._dimension
67
+ )
68
+ return NotImplemented
35
69
 
36
70
  def _comparison_key(self):
37
71
  return self._row, self._col
@@ -44,6 +78,10 @@ class _BaseGridQid(ops.Qid):
44
78
  def col(self) -> int:
45
79
  return self._col
46
80
 
81
+ @property
82
+ def dimension(self) -> int:
83
+ return self._dimension
84
+
47
85
  def with_dimension(self, dimension: int) -> 'GridQid':
48
86
  return GridQid(self._row, self._col, dimension=dimension)
49
87
 
@@ -149,13 +187,10 @@ class GridQid(_BaseGridQid):
149
187
  dimension: The dimension of the qid's Hilbert space, i.e.
150
188
  the number of quantum levels.
151
189
  """
152
- super().__init__(row, col)
153
- self._dimension = dimension
154
190
  self.validate_dimension(dimension)
155
-
156
- @property
157
- def dimension(self):
158
- return self._dimension
191
+ self._row = row
192
+ self._col = col
193
+ self._dimension = dimension
159
194
 
160
195
  def _with_row_col(self, row: int, col: int) -> 'GridQid':
161
196
  return GridQid(row, col, dimension=self.dimension)
@@ -288,35 +323,11 @@ class GridQubit(_BaseGridQid):
288
323
  cirq.GridQubit(5, 4)
289
324
  """
290
325
 
291
- def __getstate__(self):
292
- # Don't save hash when pickling; see #3777.
293
- state = self.__dict__
294
- hash_key = _compat._method_cache_name(self.__hash__)
295
- if hash_key in state:
296
- state = state.copy()
297
- del state[hash_key]
298
- return state
299
-
300
- @_compat.cached_method
301
- def __hash__(self) -> int:
302
- # Explicitly cached for performance (vs delegating to Qid).
303
- return super().__hash__()
326
+ _dimension = 2
304
327
 
305
- def __eq__(self, other):
306
- # Explicitly implemented for performance (vs delegating to Qid).
307
- if isinstance(other, GridQubit):
308
- return self._row == other._row and self._col == other._col
309
- return NotImplemented
310
-
311
- def __ne__(self, other):
312
- # Explicitly implemented for performance (vs delegating to Qid).
313
- if isinstance(other, GridQubit):
314
- return self._row != other._row or self._col != other._col
315
- return NotImplemented
316
-
317
- @property
318
- def dimension(self) -> int:
319
- return 2
328
+ def __init__(self, row: int, col: int) -> None:
329
+ self._row = row
330
+ self._col = col
320
331
 
321
332
  def _with_row_col(self, row: int, col: int):
322
333
  return GridQubit(row, col)
@@ -19,7 +19,6 @@ import numpy as np
19
19
  import pytest
20
20
 
21
21
  import cirq
22
- from cirq import _compat
23
22
 
24
23
 
25
24
  def test_init():
@@ -45,8 +44,7 @@ def test_pickled_hash():
45
44
  q = cirq.GridQubit(3, 4)
46
45
  q_bad = cirq.GridQubit(3, 4)
47
46
  _ = hash(q_bad) # compute hash to ensure it is cached.
48
- hash_key = _compat._method_cache_name(cirq.GridQubit.__hash__)
49
- setattr(q_bad, hash_key, getattr(q_bad, hash_key) + 1)
47
+ q_bad._hash = q_bad._hash + 1
50
48
  assert q_bad == q
51
49
  assert hash(q_bad) != hash(q)
52
50
  data = pickle.dumps(q_bad)
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import dataclasses
16
- from typing import TYPE_CHECKING, Dict, List, Optional, Sequence
16
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence
17
17
 
18
18
  from cirq import devices
19
19
  from cirq.devices import noise_utils
@@ -74,3 +74,23 @@ class InsertionNoiseModel(devices.NoiseModel):
74
74
  if self.prepend:
75
75
  return [*noise_steps.moments, moment]
76
76
  return [moment, *noise_steps.moments]
77
+
78
+ def __repr__(self) -> str:
79
+ return (
80
+ f'cirq.devices.InsertionNoiseModel(ops_added={self.ops_added},'
81
+ + f' prepend={self.prepend},'
82
+ + f' require_physical_tag={self.require_physical_tag})'
83
+ )
84
+
85
+ def _json_dict_(self) -> Dict[str, Any]:
86
+ return {
87
+ 'ops_added': list(self.ops_added.items()),
88
+ 'prepend': self.prepend,
89
+ 'require_physical_tag': self.require_physical_tag,
90
+ }
91
+
92
+ @classmethod
93
+ def _from_json_dict_(cls, ops_added, prepend, require_physical_tag, **kwargs):
94
+ return cls(
95
+ ops_added=dict(ops_added), prepend=prepend, require_physical_tag=require_physical_tag
96
+ )
@@ -47,6 +47,8 @@ def test_insertion_noise():
47
47
  moment_3 = cirq.Moment(cirq.Z(q0), cirq.X(q1))
48
48
  assert model.noisy_moment(moment_3, system_qubits=[q0, q1]) == [moment_3]
49
49
 
50
+ cirq.testing.assert_equivalent_repr(model)
51
+
50
52
 
51
53
  def test_colliding_noise_qubits():
52
54
  # Check that noise affecting other qubits doesn't cause issues.
@@ -61,6 +63,8 @@ def test_colliding_noise_qubits():
61
63
  cirq.Moment(cirq.CNOT(q1, q2)),
62
64
  ]
63
65
 
66
+ cirq.testing.assert_equivalent_repr(model)
67
+
64
68
 
65
69
  def test_prepend():
66
70
  q0, q1 = cirq.LineQubit.range(2)
@@ -106,3 +110,5 @@ def test_supertype_matching():
106
110
 
107
111
  moment_1 = cirq.Moment(cirq.Y(q0))
108
112
  assert model.noisy_moment(moment_1, system_qubits=[q0]) == [moment_1, cirq.Moment(cirq.T(q0))]
113
+
114
+ cirq.testing.assert_equivalent_repr(model)
@@ -27,19 +27,48 @@ if TYPE_CHECKING:
27
27
  class _BaseLineQid(ops.Qid):
28
28
  """The base class for `LineQid` and `LineQubit`."""
29
29
 
30
- def __init__(self, x: int) -> None:
31
- """Initializes a line qubit at the given x coordinate."""
32
- self._x = x
30
+ _x: int
31
+ _dimension: int
32
+ _hash: Optional[int] = None
33
+
34
+ def __getstate__(self):
35
+ # Don't save hash when pickling; see #3777.
36
+ state = self.__dict__
37
+ if "_hash" in state:
38
+ state = state.copy()
39
+ del state["_hash"]
40
+ return state
41
+
42
+ def __hash__(self) -> int:
43
+ if self._hash is None:
44
+ self._hash = hash((self._x, self._dimension))
45
+ return self._hash
46
+
47
+ def __eq__(self, other):
48
+ # Explicitly implemented for performance (vs delegating to Qid).
49
+ if isinstance(other, _BaseLineQid):
50
+ return self._x == other._x and self._dimension == other._dimension
51
+ return NotImplemented
52
+
53
+ def __ne__(self, other):
54
+ # Explicitly implemented for performance (vs delegating to Qid).
55
+ if isinstance(other, _BaseLineQid):
56
+ return self._x != other._x or self._dimension != other._dimension
57
+ return NotImplemented
33
58
 
34
59
  def _comparison_key(self):
35
- return self.x
60
+ return self._x
36
61
 
37
62
  @property
38
63
  def x(self) -> int:
39
64
  return self._x
40
65
 
66
+ @property
67
+ def dimension(self) -> int:
68
+ return self._dimension
69
+
41
70
  def with_dimension(self, dimension: int) -> 'LineQid':
42
- return LineQid(self.x, dimension)
71
+ return LineQid(self._x, dimension)
43
72
 
44
73
  def is_adjacent(self, other: 'cirq.Qid') -> bool:
45
74
  """Determines if two qubits are adjacent line qubits.
@@ -49,7 +78,7 @@ class _BaseLineQid(ops.Qid):
49
78
 
50
79
  Returns: True iff other and self are adjacent.
51
80
  """
52
- return isinstance(other, _BaseLineQid) and abs(self.x - other.x) == 1
81
+ return isinstance(other, _BaseLineQid) and abs(self._x - other._x) == 1
53
82
 
54
83
  def neighbors(self, qids: Optional[Iterable[ops.Qid]] = None) -> Set['_BaseLineQid']:
55
84
  """Returns qubits that are potential neighbors to this LineQubit
@@ -57,11 +86,7 @@ class _BaseLineQid(ops.Qid):
57
86
  Args:
58
87
  qids: optional Iterable of qubits to constrain neighbors to.
59
88
  """
60
- neighbors = set()
61
- for q in [self - 1, self + 1]:
62
- if qids is None or q in qids:
63
- neighbors.add(q)
64
- return neighbors
89
+ return {q for q in [self - 1, self + 1] if qids is None or q in qids}
65
90
 
66
91
  @abc.abstractmethod
67
92
  def _with_x(self, x: int) -> Self:
@@ -69,29 +94,29 @@ class _BaseLineQid(ops.Qid):
69
94
 
70
95
  def __add__(self, other: Union[int, Self]) -> Self:
71
96
  if isinstance(other, _BaseLineQid):
72
- if self.dimension != other.dimension:
97
+ if self._dimension != other._dimension:
73
98
  raise TypeError(
74
99
  "Can only add LineQids with identical dimension. "
75
- f"Got {self.dimension} and {other.dimension}"
100
+ f"Got {self._dimension} and {other._dimension}"
76
101
  )
77
- return self._with_x(x=self.x + other.x)
102
+ return self._with_x(x=self._x + other._x)
78
103
  if not isinstance(other, int):
79
104
  raise TypeError(f"Can only add ints and {type(self).__name__}. Instead was {other}")
80
- return self._with_x(self.x + other)
105
+ return self._with_x(self._x + other)
81
106
 
82
107
  def __sub__(self, other: Union[int, Self]) -> Self:
83
108
  if isinstance(other, _BaseLineQid):
84
- if self.dimension != other.dimension:
109
+ if self._dimension != other._dimension:
85
110
  raise TypeError(
86
111
  "Can only subtract LineQids with identical dimension. "
87
- f"Got {self.dimension} and {other.dimension}"
112
+ f"Got {self._dimension} and {other._dimension}"
88
113
  )
89
- return self._with_x(x=self.x - other.x)
114
+ return self._with_x(x=self._x - other._x)
90
115
  if not isinstance(other, int):
91
116
  raise TypeError(
92
117
  f"Can only subtract ints and {type(self).__name__}. Instead was {other}"
93
118
  )
94
- return self._with_x(self.x - other)
119
+ return self._with_x(self._x - other)
95
120
 
96
121
  def __radd__(self, other: int) -> Self:
97
122
  return self + other
@@ -100,16 +125,16 @@ class _BaseLineQid(ops.Qid):
100
125
  return -self + other
101
126
 
102
127
  def __neg__(self) -> Self:
103
- return self._with_x(-self.x)
128
+ return self._with_x(-self._x)
104
129
 
105
130
  def __complex__(self) -> complex:
106
- return complex(self.x)
131
+ return complex(self._x)
107
132
 
108
133
  def __float__(self) -> float:
109
- return float(self.x)
134
+ return float(self._x)
110
135
 
111
136
  def __int__(self) -> int:
112
- return int(self.x)
137
+ return int(self._x)
113
138
 
114
139
 
115
140
  class LineQid(_BaseLineQid):
@@ -137,16 +162,12 @@ class LineQid(_BaseLineQid):
137
162
  dimension: The dimension of the qid's Hilbert space, i.e.
138
163
  the number of quantum levels.
139
164
  """
140
- super().__init__(x)
141
- self._dimension = dimension
142
165
  self.validate_dimension(dimension)
143
-
144
- @property
145
- def dimension(self):
146
- return self._dimension
166
+ self._x = x
167
+ self._dimension = dimension
147
168
 
148
169
  def _with_x(self, x: int) -> 'LineQid':
149
- return LineQid(x, dimension=self.dimension)
170
+ return LineQid(x, dimension=self._dimension)
150
171
 
151
172
  @staticmethod
152
173
  def range(*range_args, dimension: int) -> List['LineQid']:
@@ -192,15 +213,15 @@ class LineQid(_BaseLineQid):
192
213
  return LineQid.for_qid_shape(qid_shape(val), start=start, step=step)
193
214
 
194
215
  def __repr__(self) -> str:
195
- return f"cirq.LineQid({self.x}, dimension={self.dimension})"
216
+ return f"cirq.LineQid({self._x}, dimension={self._dimension})"
196
217
 
197
218
  def __str__(self) -> str:
198
- return f"q({self.x}) (d={self.dimension})"
219
+ return f"q({self._x}) (d={self._dimension})"
199
220
 
200
221
  def _circuit_diagram_info_(
201
222
  self, args: 'cirq.CircuitDiagramInfoArgs'
202
223
  ) -> 'cirq.CircuitDiagramInfo':
203
- return protocols.CircuitDiagramInfo(wire_symbols=(f"{self.x} (d={self.dimension})",))
224
+ return protocols.CircuitDiagramInfo(wire_symbols=(f"{self._x} (d={self._dimension})",))
204
225
 
205
226
  def _json_dict_(self) -> Dict[str, Any]:
206
227
  return protocols.obj_to_dict_helper(self, ['x', 'dimension'])
@@ -223,9 +244,15 @@ class LineQubit(_BaseLineQid):
223
244
 
224
245
  """
225
246
 
226
- @property
227
- def dimension(self) -> int:
228
- return 2
247
+ _dimension = 2
248
+
249
+ def __init__(self, x: int) -> None:
250
+ """Initializes a line qubit at the given x coordinate.
251
+
252
+ Args:
253
+ x: The x coordinate.
254
+ """
255
+ self._x = x
229
256
 
230
257
  def _with_x(self, x: int) -> 'LineQubit':
231
258
  return LineQubit(x)
@@ -234,7 +261,7 @@ class LineQubit(_BaseLineQid):
234
261
  cls = LineQid if type(self) is LineQubit else type(self)
235
262
  # Must be the same as Qid._cmp_tuple but with cls in place of
236
263
  # type(self).
237
- return (cls.__name__, repr(cls), self._comparison_key(), self.dimension)
264
+ return (cls.__name__, repr(cls), self._comparison_key(), self._dimension)
238
265
 
239
266
  @staticmethod
240
267
  def range(*range_args) -> List['LineQubit']:
@@ -249,15 +276,15 @@ class LineQubit(_BaseLineQid):
249
276
  return [LineQubit(i) for i in range(*range_args)]
250
277
 
251
278
  def __repr__(self) -> str:
252
- return f"cirq.LineQubit({self.x})"
279
+ return f"cirq.LineQubit({self._x})"
253
280
 
254
281
  def __str__(self) -> str:
255
- return f"q({self.x})"
282
+ return f"q({self._x})"
256
283
 
257
284
  def _circuit_diagram_info_(
258
285
  self, args: 'cirq.CircuitDiagramInfoArgs'
259
286
  ) -> 'cirq.CircuitDiagramInfo':
260
- return protocols.CircuitDiagramInfo(wire_symbols=(f"{self.x}",))
287
+ return protocols.CircuitDiagramInfo(wire_symbols=(f"{self._x}",))
261
288
 
262
289
  def _json_dict_(self) -> Dict[str, Any]:
263
290
  return protocols.obj_to_dict_helper(self, ['x'])
@@ -74,7 +74,7 @@ def _node_and_coordinates(
74
74
 
75
75
 
76
76
  def draw_gridlike(
77
- graph: nx.Graph, ax: plt.Axes = None, tilted: bool = True, **kwargs
77
+ graph: nx.Graph, ax: Optional[plt.Axes] = None, tilted: bool = True, **kwargs
78
78
  ) -> Dict[Any, Tuple[int, int]]:
79
79
  """Draw a grid-like graph using Matplotlib.
80
80
 
@@ -93,7 +93,7 @@ def draw_gridlike(
93
93
  to NetworkX plotting functionality.
94
94
  """
95
95
  if ax is None:
96
- ax = plt.gca() # coverage: ignore
96
+ ax = plt.gca() # pragma: no cover
97
97
 
98
98
  if tilted:
99
99
  pos = {node: (y, -x) for node, (x, y) in _node_and_coordinates(graph.nodes)}
@@ -295,8 +295,7 @@ def get_placements(
295
295
  for big_to_small_map in matcher.subgraph_monomorphisms_iter():
296
296
  dedupe[frozenset(big_to_small_map.keys())] = big_to_small_map
297
297
  if len(dedupe) > max_placements:
298
- # coverage: ignore
299
- raise ValueError(
298
+ raise ValueError( # pragma: no cover
300
299
  f"We found more than {max_placements} placements. Please use a "
301
300
  f"more constraining `big_graph` or a more constrained `small_graph`."
302
301
  )
@@ -367,27 +366,23 @@ def draw_placements(
367
366
  this callback is called. The callback should accept `ax` and `i` keyword arguments
368
367
  for the current axis and mapping index, respectively.
369
368
  """
370
- if len(small_to_big_mappings) > max_plots:
371
- # coverage: ignore
369
+ if len(small_to_big_mappings) > max_plots: # pragma: no cover
372
370
  warnings.warn(f"You've provided a lot of mappings. Only plotting the first {max_plots}")
373
371
  small_to_big_mappings = small_to_big_mappings[:max_plots]
374
372
 
375
373
  call_show = False
376
374
  if axes is None:
377
- # coverage: ignore
378
- call_show = True
375
+ call_show = True # pragma: no cover
379
376
 
380
377
  for i, small_to_big_map in enumerate(small_to_big_mappings):
381
378
  if axes is not None:
382
379
  ax = axes[i]
383
- else:
384
- # coverage: ignore
380
+ else: # pragma: no cover
385
381
  ax = plt.gca()
386
382
 
387
383
  small_mapped = nx.relabel_nodes(small_graph, small_to_big_map)
388
384
  if bad_placement_callback is not None:
389
- # coverage: ignore
390
- if not _is_valid_placement_helper(
385
+ if not _is_valid_placement_helper( # pragma: no cover
391
386
  big_graph=big_graph,
392
387
  small_mapped=small_mapped,
393
388
  small_to_big_mapping=small_to_big_map,
@@ -406,7 +401,6 @@ def draw_placements(
406
401
  )
407
402
  ax.axis('equal')
408
403
  if call_show:
409
- # coverage: ignore
410
404
  # poor man's multi-axis figure: call plt.show() after each plot
411
405
  # and jupyter will put the plots one after another.
412
- plt.show()
406
+ plt.show() # pragma: no cover
@@ -97,7 +97,7 @@ class NoiseModelFromNoiseProperties(devices.NoiseModel):
97
97
  # only ops with PHYSICAL_GATE_TAG will receive noise.
98
98
  if virtual_ops:
99
99
  # Only subclasses will trigger this case.
100
- new_moments.append(circuits.Moment(virtual_ops)) # coverage: ignore
100
+ new_moments.append(circuits.Moment(virtual_ops)) # pragma: no cover
101
101
  if physical_ops:
102
102
  new_moments.append(circuits.Moment(physical_ops))
103
103
 
@@ -16,6 +16,7 @@ from typing import TYPE_CHECKING, Any, Dict, Tuple, Type, Union
16
16
  import numpy as np
17
17
 
18
18
  from cirq import ops, protocols, value
19
+ from cirq._compat import proper_repr
19
20
 
20
21
  if TYPE_CHECKING:
21
22
  import cirq
@@ -78,20 +79,21 @@ class OpIdentifier:
78
79
  return f'{self.gate_type}{self.qubits}'
79
80
 
80
81
  def __repr__(self) -> str:
81
- fullname = f'{self.gate_type.__module__}.{self.gate_type.__qualname__}'
82
82
  qubits = ', '.join(map(repr, self.qubits))
83
- return f'cirq.devices.noise_utils.OpIdentifier({fullname}, {qubits})'
83
+ return f'cirq.devices.noise_utils.OpIdentifier({proper_repr(self.gate_type)}, {qubits})'
84
84
 
85
85
  def _value_equality_values_(self) -> Any:
86
86
  return (self.gate_type, self.qubits)
87
87
 
88
88
  def _json_dict_(self) -> Dict[str, Any]:
89
- gate_json = protocols.json_cirq_type(self._gate_type)
90
- return {'gate_type': gate_json, 'qubits': self._qubits}
89
+ if hasattr(self.gate_type, '__name__'):
90
+ return {'gate_type': protocols.json_cirq_type(self._gate_type), 'qubits': self._qubits}
91
+ return {'gate_type': self._gate_type, 'qubits': self._qubits}
91
92
 
92
93
  @classmethod
93
94
  def _from_json_dict_(cls, gate_type, qubits, **kwargs) -> 'OpIdentifier':
94
- gate_type = protocols.cirq_type_from_json(gate_type)
95
+ if isinstance(gate_type, str):
96
+ gate_type = protocols.cirq_type_from_json(gate_type)
95
97
  return cls(gate_type, *qubits)
96
98
 
97
99
 
@@ -62,6 +62,13 @@ def test_op_id_swap():
62
62
  assert cirq.CZ(q1, q0) in swap_id
63
63
 
64
64
 
65
+ def test_op_id_instance():
66
+ q0 = cirq.LineQubit.range(1)[0]
67
+ gate = cirq.SingleQubitCliffordGate.from_xz_map((cirq.X, False), (cirq.Z, False))
68
+ op_id = OpIdentifier(gate, q0)
69
+ cirq.testing.assert_equivalent_repr(op_id)
70
+
71
+
65
72
  @pytest.mark.parametrize(
66
73
  'decay_constant,num_qubits,expected_output',
67
74
  [(0.01, 1, 1 - (0.99 * 1 / 2)), (0.05, 2, 1 - (0.95 * 3 / 4))],
@@ -81,7 +81,7 @@ def test_xeb_fidelity(depolarization, estimator):
81
81
  f2 = cirq.xeb_fidelity(
82
82
  circuit, bitstrings, qubits, amplitudes=amplitudes, estimator=estimator
83
83
  )
84
- assert np.abs(f - f2) < 1e-6
84
+ assert np.abs(f - f2) < 2e-6
85
85
 
86
86
  fs.append(f)
87
87
 
@@ -15,13 +15,13 @@
15
15
  import dataclasses
16
16
  import itertools
17
17
 
18
- from typing import Any, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING
18
+ from typing import Any, cast, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING
19
19
  import numpy as np
20
20
 
21
21
  from matplotlib import pyplot as plt
22
22
 
23
23
  # this is for older systems with matplotlib <3.2 otherwise 3d projections fail
24
- from mpl_toolkits import mplot3d # pylint: disable=unused-import
24
+ from mpl_toolkits import mplot3d
25
25
  from cirq import circuits, ops, protocols
26
26
 
27
27
  if TYPE_CHECKING:
@@ -89,8 +89,9 @@ class RandomizedBenchMarkResult:
89
89
  """
90
90
  show_plot = not ax
91
91
  if not ax:
92
- fig, ax = plt.subplots(1, 1, figsize=(8, 8))
93
- ax.set_ylim([0, 1])
92
+ fig, ax = plt.subplots(1, 1, figsize=(8, 8)) # pragma: no cover
93
+ ax = cast(plt.Axes, ax) # pragma: no cover
94
+ ax.set_ylim((0.0, 1.0)) # pragma: no cover
94
95
  ax.plot(self._num_cfds_seq, self._gnd_state_probs, 'ro-', **plot_kwargs)
95
96
  ax.set_xlabel(r"Number of Cliffords")
96
97
  ax.set_ylabel('Ground State Probability')
@@ -541,7 +542,7 @@ def _find_inv_matrix(mat: np.ndarray, mat_sequence: np.ndarray) -> int:
541
542
  def _matrix_bar_plot(
542
543
  mat: np.ndarray,
543
544
  z_label: str,
544
- ax: plt.Axes,
545
+ ax: mplot3d.axes3d.Axes3D,
545
546
  kets: Optional[Sequence[str]] = None,
546
547
  title: Optional[str] = None,
547
548
  ylim: Tuple[int, int] = (-1, 1),
@@ -693,5 +693,5 @@ def _two_qubit_layer(
693
693
  prng: 'np.random.RandomState',
694
694
  ) -> 'cirq.OP_TREE':
695
695
  for a, b in coupled_qubit_pairs:
696
- if (a, b) in layer:
696
+ if (a, b) in layer or (b, a) in layer:
697
697
  yield two_qubit_op_factory(a, b, prng)
@@ -259,6 +259,30 @@ class FakeSycamoreGate(cirq.FSimGate):
259
259
  'seed, expected_circuit_length, single_qubit_layers_slice, '
260
260
  'two_qubit_layers_slice',
261
261
  (
262
+ (
263
+ (cirq.q(0, 0), cirq.q(0, 1), cirq.q(0, 2)),
264
+ 4,
265
+ lambda a, b, _: cirq.CZ(a, b),
266
+ [[(cirq.q(0, 0), cirq.q(0, 1))], [(cirq.q(0, 1), cirq.q(0, 2))]],
267
+ (cirq.X**0.5,),
268
+ True,
269
+ 1234,
270
+ 9,
271
+ slice(None, None, 2),
272
+ slice(1, None, 2),
273
+ ),
274
+ (
275
+ (cirq.q(0, 0), cirq.q(0, 1), cirq.q(0, 2)),
276
+ 4,
277
+ lambda a, b, _: cirq.CZ(a, b),
278
+ [[(cirq.q(0, 1), cirq.q(0, 0))], [(cirq.q(0, 1), cirq.q(0, 2))]],
279
+ (cirq.X**0.5,),
280
+ True,
281
+ 1234,
282
+ 9,
283
+ slice(None, None, 2),
284
+ slice(1, None, 2),
285
+ ),
262
286
  (
263
287
  cirq.GridQubit.rect(4, 3),
264
288
  20,
@@ -406,7 +430,10 @@ def _validate_two_qubit_layers(
406
430
  # Operation is two-qubit
407
431
  assert cirq.num_qubits(op) == 2
408
432
  # Operation fits pattern
409
- assert op.qubits in pattern[i % len(pattern)]
433
+ assert (
434
+ op.qubits in pattern[i % len(pattern)]
435
+ or op.qubits[::-1] in pattern[i % len(pattern)]
436
+ )
410
437
  active_pairs.add(op.qubits)
411
438
  # All interactions that should be in this layer are present
412
439
  assert all(
@@ -278,7 +278,7 @@ class TensoredConfusionMatrices:
278
278
  raise ValueError(f"method: {method} should be 'pseudo_inverse' or 'least_squares'.")
279
279
 
280
280
  if method == 'pseudo_inverse':
281
- return result @ self.correction_matrix(qubits) # coverage: ignore
281
+ return result @ self.correction_matrix(qubits) # pragma: no cover
282
282
 
283
283
  # Least squares minimization.
284
284
  cm = self.confusion_matrix(qubits)
@@ -291,11 +291,11 @@ class TensoredConfusionMatrices:
291
291
  res = scipy.optimize.minimize(
292
292
  func, result, method='SLSQP', constraints=constraints, bounds=bounds
293
293
  )
294
- if res.success is False: # coverage: ignore
295
- raise ValueError( # coverage: ignore
296
- f"SLSQP optimization for constrained minimization " # coverage: ignore
297
- f"did not converge. Result:\n{res}" # coverage: ignore
298
- ) # coverage: ignore
294
+ if res.success is False: # pragma: no cover
295
+ raise ValueError( # pragma: no cover
296
+ f"SLSQP optimization for constrained minimization " # pragma: no cover
297
+ f"did not converge. Result:\n{res}" # pragma: no cover
298
+ ) # pragma: no cover
299
299
  return res.x
300
300
 
301
301
  def __repr__(self) -> str: