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
@@ -23,7 +23,6 @@ import pytest
23
23
  import sympy
24
24
 
25
25
  import cirq
26
- import cirq.testing
27
26
  from cirq import circuits
28
27
  from cirq import ops
29
28
  from cirq.testing.devices import ValidatingTestDevice
@@ -72,19 +71,32 @@ moment_and_op_type_validating_device = _MomentAndOpTypeValidatingDeviceType()
72
71
 
73
72
  def test_from_moments():
74
73
  a, b, c, d = cirq.LineQubit.range(4)
75
- assert cirq.Circuit.from_moments(
74
+ moment = cirq.Moment(cirq.Z(a), cirq.Z(b))
75
+ subcircuit = cirq.FrozenCircuit.from_moments(cirq.X(c), cirq.Y(d))
76
+ circuit = cirq.Circuit.from_moments(
77
+ moment,
78
+ subcircuit,
76
79
  [cirq.X(a), cirq.Y(b)],
77
80
  [cirq.X(c)],
78
81
  [],
79
82
  cirq.Z(d),
80
83
  [cirq.measure(a, b, key='ab'), cirq.measure(c, d, key='cd')],
81
- ) == cirq.Circuit(
84
+ )
85
+ assert circuit == cirq.Circuit(
86
+ cirq.Moment(cirq.Z(a), cirq.Z(b)),
87
+ cirq.Moment(
88
+ cirq.CircuitOperation(
89
+ cirq.FrozenCircuit(cirq.Moment(cirq.X(c)), cirq.Moment(cirq.Y(d)))
90
+ )
91
+ ),
82
92
  cirq.Moment(cirq.X(a), cirq.Y(b)),
83
93
  cirq.Moment(cirq.X(c)),
84
94
  cirq.Moment(),
85
95
  cirq.Moment(cirq.Z(d)),
86
96
  cirq.Moment(cirq.measure(a, b, key='ab'), cirq.measure(c, d, key='cd')),
87
97
  )
98
+ assert circuit[0] is moment
99
+ assert circuit[1].operations[0].circuit is subcircuit
88
100
 
89
101
 
90
102
  def test_alignment():
@@ -4521,6 +4533,100 @@ def test_freeze_not_relocate_moments():
4521
4533
  assert [mc is fc for mc, fc in zip(c, f)] == [True, True]
4522
4534
 
4523
4535
 
4536
+ def test_freeze_is_cached():
4537
+ q = cirq.q(0)
4538
+ c = cirq.Circuit(cirq.X(q), cirq.measure(q))
4539
+ f0 = c.freeze()
4540
+ f1 = c.freeze()
4541
+ assert f1 is f0
4542
+
4543
+ c.append(cirq.Y(q))
4544
+ f2 = c.freeze()
4545
+ f3 = c.freeze()
4546
+ assert f2 is not f1
4547
+ assert f3 is f2
4548
+
4549
+ c[-1] = cirq.Moment(cirq.Y(q))
4550
+ f4 = c.freeze()
4551
+ f5 = c.freeze()
4552
+ assert f4 is not f3
4553
+ assert f5 is f4
4554
+
4555
+
4556
+ @pytest.mark.parametrize(
4557
+ "circuit, mutate",
4558
+ [
4559
+ (
4560
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))),
4561
+ lambda c: c.__setitem__(0, cirq.Moment(cirq.Y(cirq.q(0)))),
4562
+ ),
4563
+ (cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))), lambda c: c.__delitem__(0)),
4564
+ (cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))), lambda c: c.__imul__(2)),
4565
+ (
4566
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))),
4567
+ lambda c: c.insert(1, cirq.Y(cirq.q(0))),
4568
+ ),
4569
+ (
4570
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))),
4571
+ lambda c: c.insert_into_range([cirq.Y(cirq.q(1)), cirq.M(cirq.q(1))], 0, 2),
4572
+ ),
4573
+ (
4574
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))),
4575
+ lambda c: c.insert_at_frontier([cirq.Y(cirq.q(0)), cirq.Y(cirq.q(1))], 1),
4576
+ ),
4577
+ (
4578
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))),
4579
+ lambda c: c.batch_replace([(0, cirq.X(cirq.q(0)), cirq.Y(cirq.q(0)))]),
4580
+ ),
4581
+ (
4582
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0), cirq.q(1))),
4583
+ lambda c: c.batch_insert_into([(0, cirq.X(cirq.q(1)))]),
4584
+ ),
4585
+ (
4586
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))),
4587
+ lambda c: c.batch_insert([(1, cirq.Y(cirq.q(0)))]),
4588
+ ),
4589
+ (
4590
+ cirq.Circuit(cirq.X(cirq.q(0)), cirq.M(cirq.q(0))),
4591
+ lambda c: c.clear_operations_touching([cirq.q(0)], [0]),
4592
+ ),
4593
+ ],
4594
+ )
4595
+ def test_mutation_clears_cached_attributes(circuit, mutate):
4596
+ cached_attributes = [
4597
+ "_all_qubits",
4598
+ "_frozen",
4599
+ "_is_measurement",
4600
+ "_is_parameterized",
4601
+ "_parameter_names",
4602
+ ]
4603
+
4604
+ for attr in cached_attributes:
4605
+ assert getattr(circuit, attr) is None, f"{attr=} is not None"
4606
+
4607
+ # Check that attributes are cached after getting them.
4608
+ qubits = circuit.all_qubits()
4609
+ frozen = circuit.freeze()
4610
+ is_measurement = cirq.is_measurement(circuit)
4611
+ is_parameterized = cirq.is_parameterized(circuit)
4612
+ parameter_names = cirq.parameter_names(circuit)
4613
+
4614
+ for attr in cached_attributes:
4615
+ assert getattr(circuit, attr) is not None, f"{attr=} is None"
4616
+
4617
+ # Check that getting again returns same object.
4618
+ assert circuit.all_qubits() is qubits
4619
+ assert circuit.freeze() is frozen
4620
+ assert cirq.is_measurement(circuit) is is_measurement
4621
+ assert cirq.is_parameterized(circuit) is is_parameterized
4622
+ assert cirq.parameter_names(circuit) is parameter_names
4623
+
4624
+ # Check that attributes are cleared after mutation.
4625
+ mutate(circuit)
4626
+ for attr in cached_attributes:
4627
+ assert getattr(circuit, attr) is None, f"{attr=} is not None"
4628
+
4629
+
4524
4630
  def test_factorize_one_factor():
4525
4631
  circuit = cirq.Circuit()
4526
4632
  q0, q1, q2 = cirq.LineQubit.range(3)
@@ -12,7 +12,17 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  """An immutable version of the Circuit data structure."""
15
- from typing import AbstractSet, FrozenSet, Iterable, Iterator, Sequence, Tuple, TYPE_CHECKING, Union
15
+ from typing import (
16
+ AbstractSet,
17
+ FrozenSet,
18
+ Hashable,
19
+ Iterable,
20
+ Iterator,
21
+ Sequence,
22
+ Tuple,
23
+ TYPE_CHECKING,
24
+ Union,
25
+ )
16
26
 
17
27
  import numpy as np
18
28
 
@@ -34,7 +44,10 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
34
44
  """
35
45
 
36
46
  def __init__(
37
- self, *contents: 'cirq.OP_TREE', strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST
47
+ self,
48
+ *contents: 'cirq.OP_TREE',
49
+ strategy: 'cirq.InsertStrategy' = InsertStrategy.EARLIEST,
50
+ tags: Sequence[Hashable] = (),
38
51
  ) -> None:
39
52
  """Initializes a frozen circuit.
40
53
 
@@ -47,9 +60,14 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
47
60
  strategy: When initializing the circuit with operations and moments
48
61
  from `contents`, this determines how the operations are packed
49
62
  together.
63
+ tags: A sequence of any type of object that is useful to attach metadata
64
+ to this circuit as long as the type is hashable. If you wish the
65
+ resulting circuit to be eventually serialized into JSON, you should
66
+ also restrict the tags to be JSON serializable.
50
67
  """
51
68
  base = Circuit(contents, strategy=strategy)
52
69
  self._moments = tuple(base.moments)
70
+ self._tags = tuple(tags)
53
71
 
54
72
  @classmethod
55
73
  def _from_moments(cls, moments: Iterable['cirq.Moment']) -> 'FrozenCircuit':
@@ -61,10 +79,41 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
61
79
  def moments(self) -> Sequence['cirq.Moment']:
62
80
  return self._moments
63
81
 
82
+ def freeze(self) -> 'cirq.FrozenCircuit':
83
+ return self
84
+
85
+ def unfreeze(self, copy: bool = True) -> 'cirq.Circuit':
86
+ return Circuit.from_moments(*self)
87
+
88
+ @property
89
+ def tags(self) -> Tuple[Hashable, ...]:
90
+ """Returns a tuple of the Circuit's tags."""
91
+ return self._tags
92
+
93
+ @_compat.cached_property
94
+ def untagged(self) -> 'cirq.FrozenCircuit':
95
+ """Returns the underlying FrozenCircuit without any tags."""
96
+ return self._from_moments(self._moments) if self.tags else self
97
+
98
+ def with_tags(self, *new_tags: Hashable) -> 'cirq.FrozenCircuit':
99
+ """Creates a new tagged `FrozenCircuit` with `self.tags` and `new_tags` combined."""
100
+ if not new_tags:
101
+ return self
102
+ new_circuit = FrozenCircuit(tags=self.tags + new_tags)
103
+ new_circuit._moments = self._moments
104
+ return new_circuit
105
+
64
106
  @_compat.cached_method
65
107
  def __hash__(self) -> int:
66
108
  # Explicitly cached for performance
67
- return hash((self.moments,))
109
+ return hash((self.moments, self.tags))
110
+
111
+ def __eq__(self, other):
112
+ super_eq = super().__eq__(other)
113
+ if super_eq is not True:
114
+ return super_eq
115
+ other_tags = other.tags if isinstance(other, FrozenCircuit) else ()
116
+ return self.tags == other_tags
68
117
 
69
118
  def __getstate__(self):
70
119
  # Don't save hash when pickling; see #3777.
@@ -130,11 +179,23 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
130
179
 
131
180
  @_compat.cached_method
132
181
  def _is_parameterized_(self) -> bool:
133
- return super()._is_parameterized_()
182
+ return super()._is_parameterized_() or any(
183
+ protocols.is_parameterized(tag) for tag in self.tags
184
+ )
134
185
 
135
186
  @_compat.cached_method
136
187
  def _parameter_names_(self) -> AbstractSet[str]:
137
- return super()._parameter_names_()
188
+ tag_params = {name for tag in self.tags for name in protocols.parameter_names(tag)}
189
+ return super()._parameter_names_() | tag_params
190
+
191
+ def _resolve_parameters_(
192
+ self, resolver: 'cirq.ParamResolver', recursive: bool
193
+ ) -> 'cirq.FrozenCircuit':
194
+ resolved_circuit = super()._resolve_parameters_(resolver, recursive)
195
+ resolved_tags = [
196
+ protocols.resolve_parameters(tag, resolver, recursive) for tag in self.tags
197
+ ]
198
+ return resolved_circuit.with_tags(*resolved_tags)
138
199
 
139
200
  def _measurement_key_names_(self) -> FrozenSet[str]:
140
201
  return self.all_measurement_key_names()
@@ -161,6 +222,20 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
161
222
  except:
162
223
  return NotImplemented
163
224
 
225
+ def _repr_args(self) -> str:
226
+ moments_repr = super()._repr_args()
227
+ tag_repr = ','.join(_compat.proper_repr(t) for t in self._tags)
228
+ return f'{moments_repr}, tags=[{tag_repr}]' if self.tags else moments_repr
229
+
230
+ def _json_dict_(self):
231
+ attribute_names = ['moments', 'tags'] if self.tags else ['moments']
232
+ ret = protocols.obj_to_dict_helper(self, attribute_names)
233
+ return ret
234
+
235
+ @classmethod
236
+ def _from_json_dict_(cls, moments, *, tags=(), **kwargs):
237
+ return cls(moments, strategy=InsertStrategy.EARLIEST, tags=tags)
238
+
164
239
  def concat_ragged(
165
240
  *circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT
166
241
  ) -> 'cirq.FrozenCircuit':
@@ -17,25 +17,39 @@ Behavior shared with Circuit is tested with parameters in circuit_test.py.
17
17
  """
18
18
 
19
19
  import pytest
20
+ import sympy
20
21
 
21
22
  import cirq
22
23
 
23
24
 
24
25
  def test_from_moments():
25
26
  a, b, c, d = cirq.LineQubit.range(4)
26
- assert cirq.FrozenCircuit.from_moments(
27
+ moment = cirq.Moment(cirq.Z(a), cirq.Z(b))
28
+ subcircuit = cirq.FrozenCircuit.from_moments(cirq.X(c), cirq.Y(d))
29
+ circuit = cirq.FrozenCircuit.from_moments(
30
+ moment,
31
+ subcircuit,
27
32
  [cirq.X(a), cirq.Y(b)],
28
33
  [cirq.X(c)],
29
34
  [],
30
35
  cirq.Z(d),
31
36
  [cirq.measure(a, b, key='ab'), cirq.measure(c, d, key='cd')],
32
- ) == cirq.FrozenCircuit(
37
+ )
38
+ assert circuit == cirq.FrozenCircuit(
39
+ cirq.Moment(cirq.Z(a), cirq.Z(b)),
40
+ cirq.Moment(
41
+ cirq.CircuitOperation(
42
+ cirq.FrozenCircuit(cirq.Moment(cirq.X(c)), cirq.Moment(cirq.Y(d)))
43
+ )
44
+ ),
33
45
  cirq.Moment(cirq.X(a), cirq.Y(b)),
34
46
  cirq.Moment(cirq.X(c)),
35
47
  cirq.Moment(),
36
48
  cirq.Moment(cirq.Z(d)),
37
49
  cirq.Moment(cirq.measure(a, b, key='ab'), cirq.measure(c, d, key='cd')),
38
50
  )
51
+ assert circuit[0] is moment
52
+ assert circuit[1].operations[0].circuit is subcircuit
39
53
 
40
54
 
41
55
  def test_freeze_and_unfreeze():
@@ -74,3 +88,34 @@ def test_immutable():
74
88
  match="(can't set attribute)|(property 'moments' of 'FrozenCircuit' object has no setter)",
75
89
  ):
76
90
  c.moments = (cirq.Moment(cirq.H(q)), cirq.Moment(cirq.X(q)))
91
+
92
+
93
+ def test_tagged_circuits():
94
+ q = cirq.LineQubit(0)
95
+ ops = [cirq.X(q), cirq.H(q)]
96
+ tags = [sympy.Symbol("a"), "b"]
97
+ circuit = cirq.Circuit(ops)
98
+ frozen_circuit = cirq.FrozenCircuit(ops)
99
+ tagged_circuit = cirq.FrozenCircuit(ops, tags=tags)
100
+ # Test equality
101
+ assert tagged_circuit.tags == tuple(tags)
102
+ assert circuit == frozen_circuit != tagged_circuit
103
+ assert cirq.approx_eq(circuit, frozen_circuit)
104
+ assert cirq.approx_eq(frozen_circuit, tagged_circuit)
105
+ # Test hash
106
+ assert hash(frozen_circuit) != hash(tagged_circuit)
107
+ # Test _repr_ and _json_ round trips.
108
+ cirq.testing.assert_equivalent_repr(tagged_circuit)
109
+ cirq.testing.assert_json_roundtrip_works(tagged_circuit)
110
+ # Test utility methods and constructors
111
+ assert frozen_circuit.with_tags() is frozen_circuit
112
+ assert frozen_circuit.with_tags(*tags) == tagged_circuit
113
+ assert tagged_circuit.with_tags("c") == cirq.FrozenCircuit(ops, tags=[*tags, "c"])
114
+ assert tagged_circuit.untagged == frozen_circuit
115
+ assert frozen_circuit.untagged is frozen_circuit
116
+ # Test parameterized protocols
117
+ assert cirq.is_parameterized(frozen_circuit) is False
118
+ assert cirq.is_parameterized(tagged_circuit) is True
119
+ assert cirq.parameter_names(tagged_circuit) == {"a"}
120
+ # Tags are not propagated to diagrams yet.
121
+ assert str(frozen_circuit) == str(tagged_circuit)
@@ -248,18 +248,18 @@ def test_unsupported_operation():
248
248
 
249
249
 
250
250
  def _all_operations(q0, q1, q2, q3, q4, include_measurements=True):
251
- class DummyOperation(cirq.Operation):
251
+ class ExampleOperation(cirq.Operation):
252
252
  qubits = (q0,)
253
253
  with_qubits = NotImplemented
254
254
 
255
255
  def _qasm_(self, args: cirq.QasmArgs) -> str:
256
- return '// Dummy operation\n'
256
+ return '// Example operation\n'
257
257
 
258
258
  def _decompose_(self):
259
259
  # Only used by test_output_unitary_same_as_qiskit
260
- return () # coverage: ignore
260
+ return () # pragma: no cover
261
261
 
262
- class DummyCompositeOperation(cirq.Operation):
262
+ class ExampleCompositeOperation(cirq.Operation):
263
263
  qubits = (q0,)
264
264
  with_qubits = NotImplemented
265
265
 
@@ -267,7 +267,7 @@ def _all_operations(q0, q1, q2, q3, q4, include_measurements=True):
267
267
  return cirq.X(self.qubits[0])
268
268
 
269
269
  def __repr__(self):
270
- return 'DummyCompositeOperation()'
270
+ return 'ExampleCompositeOperation()'
271
271
 
272
272
  return (
273
273
  cirq.I(q0),
@@ -328,8 +328,8 @@ def _all_operations(q0, q1, q2, q3, q4, include_measurements=True):
328
328
  )
329
329
  if include_measurements
330
330
  else (),
331
- DummyOperation(),
332
- DummyCompositeOperation(),
331
+ ExampleOperation(),
332
+ ExampleCompositeOperation(),
333
333
  )
334
334
 
335
335
 
@@ -539,9 +539,9 @@ measure q[2] -> m_multi[1];
539
539
  x q[2]; // Undo the inversion
540
540
  measure q[3] -> m_multi[2];
541
541
 
542
- // Dummy operation
542
+ // Example operation
543
543
 
544
- // Operation: DummyCompositeOperation()
544
+ // Operation: ExampleCompositeOperation()
545
545
  x q[0];
546
546
  """
547
547
  )
cirq/conftest.py CHANGED
@@ -27,8 +27,7 @@ def pytest_configure(config):
27
27
 
28
28
  def pytest_pyfunc_call(pyfuncitem):
29
29
  if inspect.iscoroutinefunction(pyfuncitem._obj):
30
- # coverage: ignore
31
- raise ValueError(
30
+ raise ValueError( # pragma: no cover
32
31
  f'{pyfuncitem._obj.__name__} is a bare async function. '
33
32
  f'It should be decorated with "@duet.sync".'
34
33
  )
@@ -68,7 +68,7 @@ class _UnconstrainedAcquaintanceDevice(AcquaintanceDevice):
68
68
  """An acquaintance device with no constraints other than of the gate types."""
69
69
 
70
70
  def __repr__(self) -> str:
71
- return 'UnconstrainedAcquaintanceDevice' # coverage: ignore
71
+ return 'UnconstrainedAcquaintanceDevice' # pragma: no cover
72
72
 
73
73
 
74
74
  UnconstrainedAcquaintanceDevice = _UnconstrainedAcquaintanceDevice()
@@ -29,7 +29,7 @@ def test_disable_op_validation():
29
29
  with pytest.raises(ValueError, match='mysterious and terrible'):
30
30
  with disable_op_validation():
31
31
  # This does not run - the with condition errors out first.
32
- _ = cirq.H(q0, q1) # coverage: ignore
32
+ _ = cirq.H(q0, q1) # pragma: no cover
33
33
 
34
34
  # Passes, skipping validation.
35
35
  with disable_op_validation(accept_debug_responsibility=True):
@@ -41,8 +41,7 @@ class DepolarizingNoiseModel(devices.NoiseModel):
41
41
  self._prepend = prepend
42
42
 
43
43
  def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']):
44
- if validate_all_measurements(moment) or self.is_virtual_moment(moment):
45
- # coverage: ignore
44
+ if validate_all_measurements(moment) or self.is_virtual_moment(moment): # pragma: no cover
46
45
  return moment
47
46
 
48
47
  output = [
@@ -161,7 +161,7 @@ def clifford_optimized_circuit(circuit: circuits.Circuit, atol: float = 1e-8) ->
161
161
  else:
162
162
  # Two CZ gates that share one qubit
163
163
  # Pass through and keep looking
164
- continue # coverage: ignore
164
+ continue # pragma: no cover
165
165
  # The above line is covered by test_remove_staggered_czs but the
166
166
  # coverage checker disagrees.
167
167
  return 0
@@ -182,11 +182,11 @@ def test_already_converted():
182
182
 
183
183
 
184
184
  def test_ignore_unsupported_gate():
185
- class UnsupportedDummy(cirq.testing.TwoQubitGate):
185
+ class UnsupportedGate(cirq.testing.TwoQubitGate):
186
186
  pass
187
187
 
188
188
  q0, q1 = cirq.LineQubit.range(2)
189
- c_orig = cirq.Circuit(UnsupportedDummy()(q0, q1), cirq.X(q0) ** sympy.Symbol("theta"))
189
+ c_orig = cirq.Circuit(UnsupportedGate()(q0, q1), cirq.X(q0) ** sympy.Symbol("theta"))
190
190
  c_new = cirq.optimize_for_target_gateset(
191
191
  c_orig, gateset=CliffordTargetGateset(), ignore_failures=True
192
192
  )
@@ -194,11 +194,11 @@ def test_ignore_unsupported_gate():
194
194
 
195
195
 
196
196
  def test_fail_unsupported_gate():
197
- class UnsupportedDummy(cirq.testing.TwoQubitGate):
197
+ class UnsupportedGate(cirq.testing.TwoQubitGate):
198
198
  pass
199
199
 
200
200
  q0, q1 = cirq.LineQubit.range(2)
201
- c_orig = cirq.Circuit(UnsupportedDummy()(q0, q1))
201
+ c_orig = cirq.Circuit(UnsupportedGate()(q0, q1))
202
202
  with pytest.raises(ValueError):
203
203
  _ = cirq.optimize_for_target_gateset(
204
204
  c_orig, gateset=CliffordTargetGateset(), ignore_failures=False
@@ -12,7 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # coverage: ignore
15
+ # pragma: no cover
16
16
 
17
17
  import errno
18
18
  import os
@@ -106,8 +106,7 @@ def circuit_to_density_matrix_tensors(
106
106
  ValueError: If an op is encountered that cannot be converted.
107
107
  """
108
108
  if qubits is None:
109
- # coverage: ignore
110
- qubits = sorted(circuit.all_qubits())
109
+ qubits = sorted(circuit.all_qubits()) # pragma: no cover
111
110
  qubits = tuple(qubits)
112
111
 
113
112
  qubit_frontier: Dict[cirq.Qid, int] = {q: 0 for q in qubits}
@@ -190,7 +189,7 @@ def circuit_to_density_matrix_tensors(
190
189
  )
191
190
  kraus_frontier += 1
192
191
  else:
193
- raise ValueError(repr(op)) # coverage: ignore
192
+ raise ValueError(repr(op)) # pragma: no cover
194
193
 
195
194
  _positions(mi + 1, op.qubits)
196
195
  return tensors, qubit_frontier, positions
@@ -54,12 +54,12 @@ def get_grid_moments(
54
54
  for col in range(col_start + col_start_offset, col_end + col_end_offset, col_step):
55
55
  node1 = (row, col)
56
56
  if node1 not in problem_graph.nodes:
57
- continue # coverage: ignore
57
+ continue # pragma: no cover
58
58
  node2 = get_neighbor(row, col)
59
59
  if node2 not in problem_graph.nodes:
60
- continue # coverage: ignore
60
+ continue # pragma: no cover
61
61
  if (node1, node2) not in problem_graph.edges:
62
- continue # coverage: ignore
62
+ continue # pragma: no cover
63
63
 
64
64
  weight = problem_graph.edges[node1, node2].get('weight', 1)
65
65
  yield two_qubit_gate(exponent=weight, global_shift=-0.5).on(
@@ -9,7 +9,6 @@ import quimb.tensor as qtn
9
9
  import cirq
10
10
 
11
11
 
12
- # coverage: ignore
13
12
  def _get_quimb_version():
14
13
  """Returns the quimb version and parsed (major,minor) numbers if possible.
15
14
  Returns:
@@ -18,7 +17,7 @@ def _get_quimb_version():
18
17
  version = quimb.__version__
19
18
  try:
20
19
  return tuple(int(x) for x in version.split('.')), version
21
- except:
20
+ except: # pragma: no cover
22
21
  return (0, 0), version
23
22
 
24
23
 
@@ -59,7 +58,7 @@ def circuit_to_tensors(
59
58
  corresponding to the |0> state.
60
59
  """
61
60
  if qubits is None:
62
- qubits = sorted(circuit.all_qubits()) # coverage: ignore
61
+ qubits = sorted(circuit.all_qubits()) # pragma: no cover
63
62
 
64
63
  qubit_frontier = {q: 0 for q in qubits}
65
64
  positions = None
@@ -163,8 +162,7 @@ def tensor_expectation_value(
163
162
  ]
164
163
  tn = qtn.TensorNetwork(tensors + end_bras)
165
164
  if QUIMB_VERSION[0] < (1, 3):
166
- # coverage: ignore
167
- warnings.warn(
165
+ warnings.warn( # pragma: no cover
168
166
  f'quimb version {QUIMB_VERSION[1]} detected. Please use '
169
167
  f'quimb>=1.3 for optimal performance in '
170
168
  '`tensor_expectation_value`. '
@@ -96,8 +96,7 @@ def get_circuit_connectivity(circuit: 'cirq.Circuit') -> nx.Graph:
96
96
  for op in circuit.all_operations():
97
97
  n_qubits = len(op.qubits)
98
98
  if n_qubits > 2:
99
- # coverage: ignore
100
- raise ValueError(
99
+ raise ValueError( # pragma: no cover
101
100
  f"Cannot build a graph out of a circuit that "
102
101
  f"contains {n_qubits}-qubit operations"
103
102
  )
cirq/contrib/svg/svg.py CHANGED
@@ -2,12 +2,14 @@
2
2
  from typing import TYPE_CHECKING, List, Tuple, cast, Dict
3
3
 
4
4
  import matplotlib.textpath
5
+ import matplotlib.font_manager
6
+
5
7
 
6
8
  if TYPE_CHECKING:
7
9
  import cirq
8
10
 
9
11
  QBLUE = '#1967d2'
10
- FONT = "Arial"
12
+ FONT = matplotlib.font_manager.FontProperties(family="Arial")
11
13
  EMPTY_MOMENT_COLWIDTH = float(21) # assumed default column width
12
14
 
13
15
 
@@ -140,12 +142,11 @@ def _fit_vertical(
140
142
  return row_starts, row_heights, yi_map
141
143
 
142
144
 
143
- def _debug_spacing(col_starts, row_starts):
145
+ def _debug_spacing(col_starts, row_starts): # pragma: no cover
144
146
  """Return a string suitable for inserting inside an <svg> tag that
145
147
  draws green lines where columns and rows start. This is very useful
146
148
  if you're developing this code and are debugging spacing issues.
147
149
  """
148
- # coverage: ignore
149
150
  t = ''
150
151
  for i, cs in enumerate(col_starts):
151
152
  t += (
@@ -198,7 +199,6 @@ def tdd_to_svg(
198
199
  # qubits start at far left and their wires shall be blue
199
200
  stroke = QBLUE
200
201
  else:
201
- # coverage: ignore
202
202
  stroke = 'black'
203
203
  t += f'<line x1="{x1}" x2="{x2}" y1="{y}" y2="{y}" stroke="{stroke}" stroke-width="1" />'
204
204
 
@@ -261,11 +261,9 @@ class SVGCircuit:
261
261
  """
262
262
 
263
263
  def __init__(self, circuit: 'cirq.Circuit'):
264
- # coverage: ignore
265
264
  self.circuit = circuit
266
265
 
267
266
  def _repr_svg_(self) -> str:
268
- # coverage: ignore
269
267
  return circuit_to_svg(self.circuit)
270
268
 
271
269