cirq-core 1.1.0.dev20221219200817__py3-none-any.whl → 1.2.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 (229) hide show
  1. cirq/__init__.py +8 -0
  2. cirq/_compat.py +29 -4
  3. cirq/_compat_test.py +24 -26
  4. cirq/_version.py +32 -1
  5. cirq/_version_test.py +1 -1
  6. cirq/circuits/_block_diagram_drawer_test.py +4 -3
  7. cirq/circuits/circuit.py +109 -63
  8. cirq/circuits/circuit_operation.py +2 -3
  9. cirq/circuits/circuit_operation_test.py +4 -4
  10. cirq/circuits/circuit_test.py +11 -0
  11. cirq/circuits/frozen_circuit.py +13 -1
  12. cirq/circuits/frozen_circuit_test.py +5 -1
  13. cirq/circuits/moment.py +39 -14
  14. cirq/circuits/moment_test.py +7 -0
  15. cirq/circuits/text_diagram_drawer.py +1 -1
  16. cirq/circuits/text_diagram_drawer_test.py +3 -7
  17. cirq/conftest.py +8 -0
  18. cirq/contrib/acquaintance/bipartite.py +1 -1
  19. cirq/contrib/acquaintance/devices.py +2 -2
  20. cirq/contrib/acquaintance/executor.py +5 -2
  21. cirq/contrib/acquaintance/gates.py +3 -2
  22. cirq/contrib/acquaintance/permutation.py +13 -2
  23. cirq/contrib/acquaintance/testing.py +3 -5
  24. cirq/contrib/paulistring/recombine.py +3 -6
  25. cirq/contrib/qasm_import/_parser.py +17 -21
  26. cirq/contrib/qasm_import/_parser_test.py +30 -45
  27. cirq/contrib/qcircuit/qcircuit_test.py +3 -7
  28. cirq/contrib/quantum_volume/quantum_volume.py +3 -3
  29. cirq/contrib/quimb/mps_simulator.py +1 -1
  30. cirq/contrib/quimb/state_vector.py +2 -0
  31. cirq/contrib/quirk/quirk_gate.py +1 -0
  32. cirq/contrib/svg/svg.py +4 -7
  33. cirq/contrib/svg/svg_test.py +29 -1
  34. cirq/devices/grid_qubit.py +26 -28
  35. cirq/devices/grid_qubit_test.py +21 -5
  36. cirq/devices/line_qubit.py +10 -12
  37. cirq/devices/line_qubit_test.py +9 -2
  38. cirq/devices/named_topologies.py +1 -1
  39. cirq/devices/noise_model.py +4 -1
  40. cirq/devices/superconducting_qubits_noise_properties.py +1 -3
  41. cirq/experiments/n_qubit_tomography.py +1 -1
  42. cirq/experiments/qubit_characterizations.py +2 -2
  43. cirq/experiments/single_qubit_readout_calibration.py +1 -1
  44. cirq/experiments/t2_decay_experiment.py +1 -1
  45. cirq/experiments/xeb_simulation_test.py +2 -2
  46. cirq/interop/quirk/cells/testing.py +1 -1
  47. cirq/json_resolver_cache.py +1 -0
  48. cirq/linalg/__init__.py +2 -0
  49. cirq/linalg/decompositions_test.py +4 -4
  50. cirq/linalg/diagonalize_test.py +5 -6
  51. cirq/linalg/transformations.py +72 -9
  52. cirq/linalg/transformations_test.py +23 -7
  53. cirq/ops/__init__.py +4 -0
  54. cirq/ops/arithmetic_operation.py +4 -6
  55. cirq/ops/classically_controlled_operation.py +10 -3
  56. cirq/ops/clifford_gate.py +1 -7
  57. cirq/ops/common_channels.py +21 -15
  58. cirq/ops/common_gate_families.py +2 -3
  59. cirq/ops/common_gates.py +48 -11
  60. cirq/ops/common_gates_test.py +4 -0
  61. cirq/ops/controlled_gate.py +44 -18
  62. cirq/ops/controlled_operation.py +13 -5
  63. cirq/ops/dense_pauli_string.py +14 -19
  64. cirq/ops/diagonal_gate.py +3 -4
  65. cirq/ops/eigen_gate.py +8 -10
  66. cirq/ops/eigen_gate_test.py +6 -0
  67. cirq/ops/gate_operation.py +11 -6
  68. cirq/ops/gate_operation_test.py +11 -2
  69. cirq/ops/gateset.py +2 -1
  70. cirq/ops/gateset_test.py +38 -5
  71. cirq/ops/global_phase_op.py +28 -2
  72. cirq/ops/global_phase_op_test.py +21 -0
  73. cirq/ops/identity.py +1 -1
  74. cirq/ops/kraus_channel_test.py +2 -2
  75. cirq/ops/linear_combinations.py +7 -6
  76. cirq/ops/linear_combinations_test.py +26 -10
  77. cirq/ops/matrix_gates.py +8 -4
  78. cirq/ops/matrix_gates_test.py +25 -3
  79. cirq/ops/measure_util.py +13 -5
  80. cirq/ops/measure_util_test.py +8 -2
  81. cirq/ops/measurement_gate.py +1 -1
  82. cirq/ops/measurement_gate_test.py +9 -4
  83. cirq/ops/mixed_unitary_channel_test.py +4 -4
  84. cirq/ops/named_qubit.py +2 -4
  85. cirq/ops/parity_gates.py +5 -1
  86. cirq/ops/parity_gates_test.py +6 -0
  87. cirq/ops/pauli_gates.py +9 -9
  88. cirq/ops/pauli_string.py +4 -2
  89. cirq/ops/pauli_string_raw_types.py +4 -11
  90. cirq/ops/pauli_string_test.py +13 -13
  91. cirq/ops/pauli_sum_exponential.py +6 -1
  92. cirq/ops/qubit_manager.py +97 -0
  93. cirq/ops/qubit_manager_test.py +66 -0
  94. cirq/ops/raw_types.py +75 -33
  95. cirq/ops/raw_types_test.py +34 -0
  96. cirq/ops/three_qubit_gates.py +16 -10
  97. cirq/ops/three_qubit_gates_test.py +4 -2
  98. cirq/ops/two_qubit_diagonal_gate.py +3 -3
  99. cirq/ops/wait_gate.py +1 -1
  100. cirq/protocols/__init__.py +1 -0
  101. cirq/protocols/act_on_protocol.py +3 -3
  102. cirq/protocols/act_on_protocol_test.py +5 -5
  103. cirq/protocols/apply_channel_protocol.py +9 -8
  104. cirq/protocols/apply_mixture_protocol.py +8 -8
  105. cirq/protocols/apply_mixture_protocol_test.py +1 -1
  106. cirq/protocols/apply_unitary_protocol.py +66 -19
  107. cirq/protocols/apply_unitary_protocol_test.py +50 -0
  108. cirq/protocols/circuit_diagram_info_protocol.py +7 -9
  109. cirq/protocols/decompose_protocol.py +167 -125
  110. cirq/protocols/decompose_protocol_test.py +132 -2
  111. cirq/protocols/has_stabilizer_effect_protocol.py +2 -1
  112. cirq/protocols/inverse_protocol.py +2 -2
  113. cirq/protocols/json_serialization_test.py +3 -3
  114. cirq/protocols/json_test_data/Linspace.json +20 -7
  115. cirq/protocols/json_test_data/Linspace.repr +4 -1
  116. cirq/protocols/json_test_data/Points.json +19 -8
  117. cirq/protocols/json_test_data/Points.repr +4 -1
  118. cirq/protocols/json_test_data/Result.repr_inward +1 -1
  119. cirq/protocols/json_test_data/ResultDict.repr +1 -1
  120. cirq/protocols/json_test_data/ResultDict.repr_inward +1 -1
  121. cirq/protocols/json_test_data/TrialResult.repr_inward +1 -1
  122. cirq/protocols/json_test_data/XPowGate.json +13 -5
  123. cirq/protocols/json_test_data/XPowGate.repr +1 -1
  124. cirq/protocols/json_test_data/ZPowGate.json +13 -5
  125. cirq/protocols/json_test_data/ZPowGate.repr +1 -1
  126. cirq/protocols/json_test_data/ZipLongest.json +19 -0
  127. cirq/protocols/json_test_data/ZipLongest.repr +1 -0
  128. cirq/protocols/json_test_data/spec.py +1 -0
  129. cirq/protocols/kraus_protocol.py +3 -4
  130. cirq/protocols/measurement_key_protocol.py +3 -1
  131. cirq/protocols/mixture_protocol.py +3 -2
  132. cirq/protocols/phase_protocol.py +3 -3
  133. cirq/protocols/pow_protocol.py +1 -2
  134. cirq/protocols/qasm.py +4 -4
  135. cirq/protocols/qid_shape_protocol.py +8 -8
  136. cirq/protocols/resolve_parameters.py +8 -3
  137. cirq/protocols/resolve_parameters_test.py +3 -3
  138. cirq/protocols/unitary_protocol.py +19 -11
  139. cirq/protocols/unitary_protocol_test.py +37 -0
  140. cirq/qis/channels.py +1 -1
  141. cirq/qis/clifford_tableau.py +4 -5
  142. cirq/qis/quantum_state_representation.py +7 -9
  143. cirq/qis/states.py +21 -13
  144. cirq/qis/states_test.py +7 -0
  145. cirq/sim/clifford/clifford_simulator.py +3 -3
  146. cirq/sim/density_matrix_simulation_state.py +2 -1
  147. cirq/sim/density_matrix_simulator.py +1 -1
  148. cirq/sim/density_matrix_simulator_test.py +9 -5
  149. cirq/sim/density_matrix_utils.py +7 -32
  150. cirq/sim/mux.py +2 -2
  151. cirq/sim/simulation_state.py +58 -18
  152. cirq/sim/simulation_state_base.py +5 -2
  153. cirq/sim/simulation_state_test.py +121 -9
  154. cirq/sim/simulation_utils.py +59 -0
  155. cirq/sim/simulation_utils_test.py +32 -0
  156. cirq/sim/simulator.py +2 -1
  157. cirq/sim/simulator_base_test.py +3 -3
  158. cirq/sim/sparse_simulator.py +1 -1
  159. cirq/sim/sparse_simulator_test.py +5 -5
  160. cirq/sim/state_vector.py +7 -36
  161. cirq/sim/state_vector_simulation_state.py +18 -1
  162. cirq/sim/state_vector_simulator.py +3 -2
  163. cirq/sim/state_vector_simulator_test.py +24 -2
  164. cirq/sim/state_vector_test.py +46 -15
  165. cirq/study/__init__.py +1 -0
  166. cirq/study/flatten_expressions.py +2 -2
  167. cirq/study/resolver.py +2 -0
  168. cirq/study/resolver_test.py +1 -1
  169. cirq/study/result.py +1 -1
  170. cirq/study/sweeps.py +103 -9
  171. cirq/study/sweeps_test.py +64 -0
  172. cirq/testing/__init__.py +4 -0
  173. cirq/testing/circuit_compare.py +15 -18
  174. cirq/testing/consistent_act_on.py +4 -4
  175. cirq/testing/consistent_controlled_gate_op_test.py +1 -1
  176. cirq/testing/consistent_decomposition.py +11 -2
  177. cirq/testing/consistent_decomposition_test.py +8 -1
  178. cirq/testing/consistent_protocols.py +2 -0
  179. cirq/testing/consistent_protocols_test.py +8 -4
  180. cirq/testing/consistent_qasm.py +8 -15
  181. cirq/testing/consistent_specified_has_unitary.py +1 -1
  182. cirq/testing/consistent_unitary.py +85 -0
  183. cirq/testing/consistent_unitary_test.py +96 -0
  184. cirq/testing/equivalent_repr_eval.py +10 -10
  185. cirq/testing/json.py +3 -3
  186. cirq/testing/logs.py +1 -1
  187. cirq/testing/order_tester.py +4 -5
  188. cirq/testing/random_circuit.py +3 -5
  189. cirq/testing/sample_gates.py +79 -0
  190. cirq/testing/sample_gates_test.py +59 -0
  191. cirq/transformers/__init__.py +2 -0
  192. cirq/transformers/analytical_decompositions/__init__.py +8 -0
  193. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +130 -0
  194. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +58 -0
  195. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +230 -0
  196. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +112 -0
  197. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -3
  198. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
  199. cirq/transformers/expand_composite.py +1 -1
  200. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +4 -4
  201. cirq/transformers/measurement_transformers.py +4 -4
  202. cirq/transformers/merge_single_qubit_gates.py +17 -4
  203. cirq/transformers/routing/route_circuit_cqc.py +2 -2
  204. cirq/transformers/stratify.py +125 -62
  205. cirq/transformers/stratify_test.py +20 -16
  206. cirq/transformers/transformer_api.py +1 -1
  207. cirq/transformers/transformer_primitives.py +3 -2
  208. cirq/transformers/transformer_primitives_test.py +11 -0
  209. cirq/value/abc_alt.py +3 -2
  210. cirq/value/abc_alt_test.py +1 -0
  211. cirq/value/classical_data.py +10 -10
  212. cirq/value/digits.py +2 -2
  213. cirq/value/linear_dict.py +18 -19
  214. cirq/value/product_state.py +7 -6
  215. cirq/value/value_equality_attr.py +2 -2
  216. cirq/vis/heatmap.py +1 -1
  217. cirq/vis/heatmap_test.py +2 -2
  218. cirq/work/collector.py +2 -2
  219. cirq/work/observable_measurement_data.py +5 -5
  220. cirq/work/observable_readout_calibration.py +3 -1
  221. cirq/work/observable_settings.py +1 -1
  222. cirq/work/pauli_sum_collector.py +9 -8
  223. cirq/work/sampler.py +2 -0
  224. cirq/work/zeros_sampler.py +2 -2
  225. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
  226. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/RECORD +229 -215
  227. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
  228. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
  229. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
cirq/study/sweeps_test.py CHANGED
@@ -77,6 +77,64 @@ def test_zip():
77
77
  assert _values(sweep, 'b') == [4, 5, 6]
78
78
 
79
79
 
80
+ def test_zip_longest():
81
+ sweep = cirq.ZipLongest(cirq.Points('a', [1, 2, 3]), cirq.Points('b', [4, 5, 6, 7]))
82
+ assert tuple(sweep.param_tuples()) == (
83
+ (('a', 1), ('b', 4)),
84
+ (('a', 2), ('b', 5)),
85
+ (('a', 3), ('b', 6)),
86
+ (('a', 3), ('b', 7)),
87
+ )
88
+ assert sweep.keys == ['a', 'b']
89
+ assert (
90
+ str(sweep) == 'ZipLongest(cirq.Points(\'a\', [1, 2, 3]), cirq.Points(\'b\', [4, 5, 6, 7]))'
91
+ )
92
+ assert (
93
+ repr(sweep)
94
+ == 'cirq_google.ZipLongest(cirq.Points(\'a\', [1, 2, 3]), cirq.Points(\'b\', [4, 5, 6, 7]))'
95
+ )
96
+
97
+
98
+ def test_zip_longest_compatibility():
99
+ sweep = cirq.Zip(cirq.Points('a', [1, 2, 3]), cirq.Points('b', [4, 5, 6]))
100
+ sweep_longest = cirq.ZipLongest(cirq.Points('a', [1, 2, 3]), cirq.Points('b', [4, 5, 6]))
101
+ assert tuple(sweep.param_tuples()) == tuple(sweep_longest.param_tuples())
102
+
103
+ sweep = cirq.Zip(
104
+ (cirq.Points('a', [1, 3]) * cirq.Points('b', [2, 4])), cirq.Points('c', [4, 5, 6, 7])
105
+ )
106
+ sweep_longest = cirq.ZipLongest(
107
+ (cirq.Points('a', [1, 3]) * cirq.Points('b', [2, 4])), cirq.Points('c', [4, 5, 6, 7])
108
+ )
109
+ assert tuple(sweep.param_tuples()) == tuple(sweep_longest.param_tuples())
110
+
111
+
112
+ def test_empty_zip():
113
+ assert len(cirq.ZipLongest()) == 0
114
+ with pytest.raises(ValueError, match='non-empty'):
115
+ _ = cirq.ZipLongest(cirq.Points('e', []), cirq.Points('a', [1, 2, 3]))
116
+
117
+
118
+ def test_zip_eq():
119
+ et = cirq.testing.EqualsTester()
120
+ point_sweep1 = cirq.Points('a', [1, 2, 3])
121
+ point_sweep2 = cirq.Points('b', [4, 5, 6, 7])
122
+ point_sweep3 = cirq.Points('c', [1, 2])
123
+
124
+ et.add_equality_group(cirq.ZipLongest(), cirq.ZipLongest())
125
+
126
+ et.add_equality_group(
127
+ cirq.ZipLongest(point_sweep1, point_sweep2), cirq.ZipLongest(point_sweep1, point_sweep2)
128
+ )
129
+
130
+ et.add_equality_group(cirq.ZipLongest(point_sweep3, point_sweep2))
131
+ et.add_equality_group(cirq.ZipLongest(point_sweep2, point_sweep1))
132
+ et.add_equality_group(cirq.ZipLongest(point_sweep1, point_sweep2, point_sweep3))
133
+
134
+ et.add_equality_group(cirq.Zip(point_sweep1, point_sweep2, point_sweep3))
135
+ et.add_equality_group(cirq.Zip(point_sweep1, point_sweep2))
136
+
137
+
80
138
  def test_product():
81
139
  sweep = cirq.Points('a', [1, 2, 3]) * cirq.Points('b', [4, 5, 6, 7])
82
140
  assert len(sweep) == 12
@@ -215,6 +273,12 @@ def test_repr():
215
273
  )
216
274
  cirq.testing.assert_equivalent_repr(cirq.Points('zero&pi', [0, 3.14159]))
217
275
  cirq.testing.assert_equivalent_repr(cirq.Linspace('I/10', 0, 1, 10))
276
+ cirq.testing.assert_equivalent_repr(
277
+ cirq.Points('zero&pi', [0, 3.14159], metadata='example str')
278
+ )
279
+ cirq.testing.assert_equivalent_repr(
280
+ cirq.Linspace('for_q0', 0, 1, 10, metadata=cirq.LineQubit(0))
281
+ )
218
282
 
219
283
 
220
284
  def test_zip_product_str():
cirq/testing/__init__.py CHANGED
@@ -107,3 +107,7 @@ from cirq.testing.routing_devices import (
107
107
  )
108
108
 
109
109
  from cirq.testing.sample_circuits import nonoptimal_toffoli_circuit
110
+
111
+ from cirq.testing.sample_gates import PhaseUsingCleanAncilla, PhaseUsingDirtyAncilla
112
+
113
+ from cirq.testing.consistent_unitary import assert_unitary_is_consistent
@@ -11,6 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
14
15
  from typing import Any, Dict, Iterable, List, Optional, Sequence, Union
15
16
 
16
17
  from collections import defaultdict
@@ -175,10 +176,10 @@ def assert_circuits_with_terminal_measurements_are_equivalent(
175
176
  "Circuit's effect differs from the reference circuit.\n"
176
177
  '\n'
177
178
  'Diagram of actual circuit:\n'
178
- '{}\n'
179
+ f'{actual}\n'
179
180
  '\n'
180
181
  'Diagram of reference circuit with desired function:\n'
181
- '{}\n'.format(actual, reference)
182
+ f'{reference}\n'
182
183
  )
183
184
 
184
185
 
@@ -195,20 +196,20 @@ def assert_same_circuits(
195
196
  "Actual circuit differs from expected circuit.\n"
196
197
  "\n"
197
198
  "Diagram of actual circuit:\n"
198
- "{}\n"
199
+ f"{actual}\n"
199
200
  "\n"
200
201
  "Diagram of expected circuit:\n"
201
- "{}\n"
202
+ f"{expected}\n"
202
203
  "\n"
203
204
  "Index of first differing moment:\n"
204
- "{}\n"
205
+ f"{_first_differing_moment_index(actual, expected)}\n"
205
206
  "\n"
206
207
  "Full repr of actual circuit:\n"
207
- "{!r}\n"
208
+ f"{actual!r}\n"
208
209
  "\n"
209
210
  "Full repr of expected circuit:\n"
210
- "{!r}\n"
211
- ).format(actual, expected, _first_differing_moment_index(actual, expected), actual, expected)
211
+ f"{expected!r}\n"
212
+ )
212
213
 
213
214
 
214
215
  def _first_differing_moment_index(
@@ -237,7 +238,7 @@ def assert_circuits_have_same_unitary_given_final_permutation(
237
238
  ValueError: if 'qubit_map' does not have the same set of keys and values.
238
239
  """
239
240
  if set(qubit_map.keys()) != set(qubit_map.values()):
240
- raise ValueError("'qubit_map' must have the same set of of keys and values.")
241
+ raise ValueError("'qubit_map' must have the same set of keys and values.")
241
242
 
242
243
  if not set(qubit_map.keys()).issubset(actual.all_qubits()):
243
244
  raise ValueError(
@@ -275,17 +276,13 @@ def assert_has_diagram(
275
276
  "Circuit's text diagram differs from the desired diagram.\n"
276
277
  '\n'
277
278
  'Diagram of actual circuit:\n'
278
- '{}\n'
279
+ f'{actual_diagram}\n'
279
280
  '\n'
280
281
  'Desired text diagram:\n'
281
- '{}\n'
282
+ f'{desired_diagram}\n'
282
283
  '\n'
283
284
  'Highlighted differences:\n'
284
- '{}\n'.format(
285
- actual_diagram,
286
- desired_diagram,
287
- highlight_text_differences(actual_diagram, desired_diagram),
288
- )
285
+ f'{highlight_text_differences(actual_diagram, desired_diagram)}\n'
289
286
  )
290
287
 
291
288
 
@@ -329,7 +326,7 @@ def assert_has_consistent_apply_unitary(val: Any, *, atol: float = 1e-8) -> None
329
326
  # If you applied a unitary, it should match the one you say you have.
330
327
  if actual is not None:
331
328
  assert expected is not None
332
- n = np.product([2, *qid_shape])
329
+ n = np.prod([2, *qid_shape])
333
330
  np.testing.assert_allclose(actual.reshape(n, n), expected, atol=atol)
334
331
 
335
332
 
@@ -373,7 +370,7 @@ def assert_has_consistent_apply_channel(val: Any, *, atol: float = 1e-8) -> None
373
370
  # If you applied a channel, it should match the superoperator you say you have.
374
371
  if actual is not None:
375
372
  assert expected is not None
376
- n = np.product(qid_shape) ** 2
373
+ n = np.prod(qid_shape) ** 2
377
374
  np.testing.assert_allclose(actual.reshape((n, n)), expected, atol=atol)
378
375
 
379
376
 
@@ -68,7 +68,7 @@ def assert_all_implemented_act_on_effects_match_unitary(
68
68
  Checks that act_on with CliffordTableau or StabilizerStateCHForm behaves
69
69
  consistently with act_on through final state vector. Does not work with
70
70
  Operations or Gates expecting non-qubit Qids. If either of the
71
- assert_*_implmented args is true, fails if the corresponding method is not
71
+ assert_*_implemented args is true, fails if the corresponding method is not
72
72
  implemented for the test circuit.
73
73
 
74
74
  Args:
@@ -95,7 +95,7 @@ def assert_all_implemented_act_on_effects_match_unitary(
95
95
  "Could not assert if any act_on methods were "
96
96
  "implemented. Operating on qudits or with a "
97
97
  "non-unitary or parameterized operation is "
98
- "unsupported.\n\nval: {!r}".format(val)
98
+ f"unsupported.\n\nval: {val!r}"
99
99
  )
100
100
  return None
101
101
 
@@ -124,7 +124,7 @@ def assert_all_implemented_act_on_effects_match_unitary(
124
124
  state_vector_has_stabilizer(state_vector, stab) for stab in tableau.stabilizers()
125
125
  ), (
126
126
  "act_on clifford tableau is not consistent with "
127
- "final_state_vector simulation.\n\nval: {!r}".format(val)
127
+ f"final_state_vector simulation.\n\nval: {val!r}"
128
128
  )
129
129
 
130
130
  stabilizer_ch_form = _final_stabilizer_state_ch_form(circuit, qubit_map)
@@ -133,7 +133,7 @@ def assert_all_implemented_act_on_effects_match_unitary(
133
133
  "Failed to generate final "
134
134
  "stabilizer state CH form "
135
135
  "for the test circuit."
136
- "\n\nval: {!r}".format(val)
136
+ f"\n\nval: {val!r}"
137
137
  )
138
138
  else:
139
139
  np.testing.assert_allclose(
@@ -49,7 +49,7 @@ class BadGate(cirq.EigenGate, cirq.testing.SingleQubitGate):
49
49
 
50
50
  def controlled(
51
51
  self,
52
- num_controls: int = None,
52
+ num_controls: Optional[int] = None,
53
53
  control_values: Optional[
54
54
  Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
55
55
  ] = None,
@@ -40,8 +40,17 @@ def assert_decompose_is_consistent_with_unitary(val: Any, ignoring_global_phase:
40
40
  # If there's no decomposition, it's vacuously consistent.
41
41
  return
42
42
 
43
- actual = circuits.Circuit(dec).unitary(qubit_order=qubits)
44
-
43
+ c = circuits.Circuit(dec)
44
+ if len(c.all_qubits().difference(qubits)):
45
+ # The decomposition contains ancilla qubits.
46
+ ancilla = tuple(c.all_qubits().difference(qubits))
47
+ qubit_order = ancilla + qubits
48
+ actual = c.unitary(qubit_order=qubit_order)
49
+ qid_shape = protocols.qid_shape(qubits)
50
+ vol = np.prod(qid_shape, dtype=np.int64)
51
+ actual = actual[:vol, :vol]
52
+ else:
53
+ actual = c.unitary(qubit_order=qubits)
45
54
  if ignoring_global_phase:
46
55
  lin_alg_utils.assert_allclose_up_to_global_phase(actual, expected, atol=1e-8)
47
56
  else:
@@ -43,6 +43,14 @@ def test_assert_decompose_is_consistent_with_unitary():
43
43
  GoodGateDecompose().on(cirq.NamedQubit('q'))
44
44
  )
45
45
 
46
+ cirq.testing.assert_decompose_is_consistent_with_unitary(
47
+ cirq.testing.PhaseUsingCleanAncilla(theta=0.1, ancilla_bitsize=3)
48
+ )
49
+
50
+ cirq.testing.assert_decompose_is_consistent_with_unitary(
51
+ cirq.testing.PhaseUsingDirtyAncilla(phase_state=1, ancilla_bitsize=4)
52
+ )
53
+
46
54
  with pytest.raises(AssertionError):
47
55
  cirq.testing.assert_decompose_is_consistent_with_unitary(BadGateDecompose())
48
56
 
@@ -83,7 +91,6 @@ class ParameterizedGate(cirq.Gate):
83
91
 
84
92
 
85
93
  def test_assert_decompose_ends_at_default_gateset():
86
-
87
94
  cirq.testing.assert_decompose_ends_at_default_gateset(GateDecomposesToDefaultGateset())
88
95
  cirq.testing.assert_decompose_ends_at_default_gateset(
89
96
  GateDecomposesToDefaultGateset().on(*cirq.LineQubit.range(2))
@@ -37,6 +37,7 @@ from cirq.testing.consistent_resolve_parameters import assert_consistent_resolve
37
37
  from cirq.testing.consistent_specified_has_unitary import assert_specifies_has_unitary_if_unitary
38
38
  from cirq.testing.equivalent_repr_eval import assert_equivalent_repr
39
39
  from cirq.testing.consistent_controlled_gate_op import assert_controlled_and_controlled_by_identical
40
+ from cirq.testing.consistent_unitary import assert_unitary_is_consistent
40
41
 
41
42
 
42
43
  def assert_implements_consistent_protocols(
@@ -153,6 +154,7 @@ def _assert_meets_standards_helper(
153
154
  assert_qasm_is_consistent_with_unitary(val)
154
155
  assert_has_consistent_trace_distance_bound(val)
155
156
  assert_decompose_is_consistent_with_unitary(val, ignoring_global_phase=ignoring_global_phase)
157
+ assert_unitary_is_consistent(val, ignoring_global_phase=ignoring_global_phase)
156
158
  if not ignore_decompose_to_default_gateset:
157
159
  assert_decompose_ends_at_default_gateset(val)
158
160
  assert_phase_by_is_consistent_with_unitary(val)
@@ -186,8 +186,10 @@ class GoodEigenGate(cirq.EigenGate, cirq.testing.SingleQubitGate):
186
186
  return [(0, np.diag([1, 0])), (1, np.diag([0, 1]))]
187
187
 
188
188
  def __repr__(self):
189
- return 'GoodEigenGate(exponent={}, global_shift={!r})'.format(
190
- proper_repr(self._exponent), self._global_shift
189
+ return (
190
+ 'GoodEigenGate('
191
+ f'exponent={proper_repr(self._exponent)}, '
192
+ f'global_shift={self._global_shift!r})'
191
193
  )
192
194
 
193
195
 
@@ -196,8 +198,10 @@ class BadEigenGate(GoodEigenGate):
196
198
  return [0, 0]
197
199
 
198
200
  def __repr__(self):
199
- return 'BadEigenGate(exponent={}, global_shift={!r})'.format(
200
- proper_repr(self._exponent), self._global_shift
201
+ return (
202
+ 'BadEigenGate('
203
+ f'exponent={proper_repr(self._exponent)}, '
204
+ f'global_shift={self._global_shift!r})'
201
205
  )
202
206
 
203
207
 
@@ -11,6 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
14
15
  import warnings
15
16
  from typing import Any, List, Sequence, Optional
16
17
 
@@ -90,21 +91,13 @@ qreg q[{num_qubits}];
90
91
  p_qasm_unitary = None
91
92
  raise AssertionError(
92
93
  'QASM not consistent with cirq.unitary(op) up to global phase.\n\n'
93
- 'op:\n{}\n\n'
94
- 'cirq.unitary(op):\n{}\n\n'
95
- 'Generated QASM:\n\n{}\n\n'
96
- 'Unitary of generated QASM:\n{}\n\n'
97
- 'Phased matched cirq.unitary(op):\n{}\n\n'
98
- 'Phased matched unitary of generated QASM:\n{}\n\n'
99
- 'Underlying error:\n{}'.format(
100
- _indent(repr(op)),
101
- _indent(repr(unitary)),
102
- _indent(qasm),
103
- _indent(repr(qasm_unitary)),
104
- _indent(repr(p_unitary)),
105
- _indent(repr(p_qasm_unitary)),
106
- _indent(str(ex)),
107
- )
94
+ f'op:\n{_indent(repr(op))}\n\n'
95
+ f'cirq.unitary(op):\n{_indent(repr(unitary))}\n\n'
96
+ f'Generated QASM:\n\n{_indent(qasm)}\n\n'
97
+ f'Unitary of generated QASM:\n{_indent(repr(qasm_unitary))}\n\n'
98
+ f'Phased matched cirq.unitary(op):\n{_indent(repr(p_unitary))}\n\n'
99
+ f'Phased matched unitary of generated QASM:\n{_indent(repr(p_qasm_unitary))}\n\n'
100
+ f'Underlying error:\n{_indent(str(ex))}'
108
101
  )
109
102
 
110
103
 
@@ -28,5 +28,5 @@ def assert_specifies_has_unitary_if_unitary(val: Any) -> None:
28
28
  "Value is unitary but doesn't specify a _has_unitary_ method that "
29
29
  "can be used to cheaply verify this fact.\n"
30
30
  "\n"
31
- "val: {!r}".format(val)
31
+ f"val: {val!r}"
32
32
  )
@@ -0,0 +1,85 @@
1
+ # Copyright 2023 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ from typing import Any
17
+ import cirq
18
+ import numpy as np
19
+
20
+
21
+ def assert_unitary_is_consistent(val: Any, ignoring_global_phase: bool = False):
22
+ if not isinstance(val, (cirq.Operation, cirq.Gate)):
23
+ return
24
+
25
+ if not cirq.has_unitary(val):
26
+ return
27
+
28
+ # Ensure that `u` is a unitary.
29
+ u = cirq.unitary(val)
30
+ assert not (u is None or u is NotImplemented)
31
+ assert cirq.is_unitary(u)
32
+
33
+ if isinstance(val, cirq.Operation):
34
+ qubits = val.qubits
35
+ decomposition = cirq.decompose_once(val, default=None)
36
+ else:
37
+ qubits = tuple(cirq.LineQid.for_gate(val))
38
+ decomposition = cirq.decompose_once_with_qubits(val, qubits, default=None)
39
+
40
+ if decomposition is None or decomposition is NotImplemented:
41
+ return
42
+
43
+ c = cirq.Circuit(decomposition)
44
+ if len(c.all_qubits().difference(qubits)) == 0:
45
+ return
46
+
47
+ clean_qubits = tuple(q for q in c.all_qubits() if isinstance(q, cirq.ops.CleanQubit))
48
+ borrowable_qubits = tuple(q for q in c.all_qubits() if isinstance(q, cirq.ops.BorrowableQubit))
49
+ qubit_order = clean_qubits + borrowable_qubits + qubits
50
+
51
+ # Check that the decomposition uses all data qubits in addition to
52
+ # clean and/or borrowable qubits.
53
+ assert set(qubit_order) == c.all_qubits()
54
+
55
+ qid_shape = cirq.qid_shape(qubit_order)
56
+ full_unitary = cirq.apply_unitaries(
57
+ decomposition,
58
+ qubits=qubit_order,
59
+ args=cirq.ApplyUnitaryArgs.for_unitary(qid_shape=qid_shape),
60
+ default=None,
61
+ )
62
+ if full_unitary is None:
63
+ raise ValueError(f'apply_unitaries failed on the decomposition of {val}')
64
+ vol = np.prod(qid_shape, dtype=np.int64)
65
+ full_unitary = full_unitary.reshape((vol, vol))
66
+
67
+ vol = np.prod(cirq.qid_shape(borrowable_qubits + qubits), dtype=np.int64)
68
+
69
+ # Extract the submatrix acting on the |0..0> subspace of clean qubits.
70
+ # This submatirx must be a unitary.
71
+ clean_qubits_zero_subspace = full_unitary[:vol, :vol]
72
+
73
+ # If the borrowable qubits are restored to their initial state, then
74
+ # the decomposition's effect on it is the identity matrix.
75
+ # This means that the `clean_qubits_zero_subspace` must be I \otimes u.
76
+ # So checking that `clean_qubits_zero_subspace` is I \otimes u checks correctness
77
+ # for both clean and borrowable qubits at the same time.
78
+ expected = np.kron(np.eye(2 ** len(borrowable_qubits), dtype=np.complex128), u)
79
+
80
+ if ignoring_global_phase:
81
+ cirq.testing.assert_allclose_up_to_global_phase(
82
+ clean_qubits_zero_subspace, expected, atol=1e-8
83
+ )
84
+ else:
85
+ np.testing.assert_allclose(clean_qubits_zero_subspace, expected, atol=1e-8)
@@ -0,0 +1,96 @@
1
+ # Copyright 2023 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import cirq
16
+
17
+ import pytest
18
+ import numpy as np
19
+
20
+
21
+ class InconsistentGate(cirq.Gate):
22
+ def _num_qubits_(self) -> int:
23
+ return 1
24
+
25
+ def _unitary_(self) -> np.ndarray:
26
+ return np.eye(2, dtype=np.complex128)
27
+
28
+ def _decompose_with_context_(self, qubits, *, context):
29
+ (q,) = context.qubit_manager.qalloc(1)
30
+ yield cirq.X(q)
31
+ yield cirq.CNOT(q, qubits[0])
32
+
33
+
34
+ class FailsOnDecompostion(cirq.Gate):
35
+ def _num_qubits_(self) -> int:
36
+ return 1
37
+
38
+ def _unitary_(self) -> np.ndarray:
39
+ return np.eye(2, dtype=np.complex128)
40
+
41
+ def _has_unitary_(self) -> bool:
42
+ return True
43
+
44
+ def _decompose_with_context_(self, qubits, *, context):
45
+ (q,) = context.qubit_manager.qalloc(1)
46
+ yield cirq.X(q)
47
+ yield cirq.measure(qubits[0])
48
+
49
+
50
+ class CleanCorrectButBorrowableIncorrectGate(cirq.Gate):
51
+ """Ancilla type determines if the decomposition is correct or not."""
52
+
53
+ def __init__(self, use_clean_ancilla: bool) -> None:
54
+ self.ancillas_are_clean = use_clean_ancilla
55
+
56
+ def _num_qubits_(self):
57
+ return 2
58
+
59
+ def _decompose_with_context_(self, qubits, *, context):
60
+ if self.ancillas_are_clean:
61
+ anc = context.qubit_manager.qalloc(1)
62
+ else:
63
+ anc = context.qubit_manager.qborrow(1)
64
+ yield cirq.CCNOT(*qubits, *anc)
65
+ yield cirq.Z(*anc)
66
+ yield cirq.CCNOT(*qubits, *anc)
67
+ context.qubit_manager.qfree(anc)
68
+
69
+
70
+ @pytest.mark.parametrize('ignore_phase', [False, True])
71
+ @pytest.mark.parametrize(
72
+ 'g,is_consistent',
73
+ [
74
+ (cirq.testing.PhaseUsingCleanAncilla(theta=0.1, ancilla_bitsize=3), True),
75
+ (cirq.testing.PhaseUsingDirtyAncilla(phase_state=1, ancilla_bitsize=4), True),
76
+ (InconsistentGate(), False),
77
+ (CleanCorrectButBorrowableIncorrectGate(use_clean_ancilla=True), True),
78
+ (CleanCorrectButBorrowableIncorrectGate(use_clean_ancilla=False), False),
79
+ ],
80
+ )
81
+ def test_assert_unitary_is_consistent(g, ignore_phase, is_consistent):
82
+ if is_consistent:
83
+ cirq.testing.assert_unitary_is_consistent(g, ignore_phase)
84
+ cirq.testing.assert_unitary_is_consistent(g.on(*cirq.LineQid.for_gate(g)), ignore_phase)
85
+ else:
86
+ with pytest.raises(AssertionError):
87
+ cirq.testing.assert_unitary_is_consistent(g, ignore_phase)
88
+ with pytest.raises(AssertionError):
89
+ cirq.testing.assert_unitary_is_consistent(g.on(*cirq.LineQid.for_gate(g)), ignore_phase)
90
+
91
+
92
+ def test_failed_decomposition():
93
+ with pytest.raises(ValueError):
94
+ cirq.testing.assert_unitary_is_consistent(FailsOnDecompostion())
95
+
96
+ _ = cirq.testing.assert_unitary_is_consistent(cirq.Circuit())
@@ -52,10 +52,10 @@ def assert_equivalent_repr(
52
52
  raise AssertionError(
53
53
  'eval(repr(value)) raised an exception.\n'
54
54
  '\n'
55
- 'setup_code={}\n'
56
- 'type(value): {}\n'
57
- 'value={!r}\n'
58
- 'error={!r}'.format(setup_code, type(value), value, ex)
55
+ f'setup_code={setup_code}\n'
56
+ f'type(value): {type(value)}\n'
57
+ f'value={value!r}\n'
58
+ f'error={ex!r}'
59
59
  )
60
60
 
61
61
  assert eval_repr_value == value, (
@@ -87,14 +87,14 @@ def assert_equivalent_repr(
87
87
  a = eval(f'{value!r}.__class__', global_vals, local_vals)
88
88
  except Exception:
89
89
  raise AssertionError(
90
- "The repr of a value of type {} wasn't 'dottable'.\n"
91
- "{!r}.XXX must be equivalent to ({!r}).XXX, "
92
- "but it raised an error instead.".format(type(value), value, value)
90
+ f"The repr of a value of type {type(value)} wasn't 'dottable'.\n"
91
+ f"{value!r}.XXX must be equivalent to ({value!r}).XXX, "
92
+ "but it raised an error instead."
93
93
  )
94
94
 
95
95
  b = eval(f'({value!r}).__class__', global_vals, local_vals)
96
96
  assert a == b, (
97
- "The repr of a value of type {} wasn't 'dottable'.\n"
98
- "{!r}.XXX must be equivalent to ({!r}).XXX, "
99
- "but it wasn't.".format(type(value), value, value)
97
+ f"The repr of a value of type {type(value)} wasn't 'dottable'.\n"
98
+ f"{value!r}.XXX must be equivalent to ({value!r}).XXX, "
99
+ "but it wasn't."
100
100
  )
cirq/testing/json.py CHANGED
@@ -95,11 +95,11 @@ class ModuleJsonTestSpec:
95
95
 
96
96
  return result
97
97
 
98
- def get_resolver_cache_types(self):
98
+ def get_resolver_cache_types(self) -> Set[Tuple[str, Type]]:
99
99
  result: Set[Tuple[str, Type]] = set()
100
100
  for k, v in self.resolver_cache.items():
101
- t = v if isinstance(v, type) else None
102
- result.add((k, t))
101
+ if isinstance(v, type):
102
+ result.add((k, v))
103
103
  return result
104
104
 
105
105
  def get_all_names(self) -> Iterator[str]:
cirq/testing/logs.py CHANGED
@@ -48,7 +48,7 @@ def assert_logs(
48
48
  module for valid levels. By default this captures at the
49
49
  `logging.WARNING` level and above, so this does not capture `logging.INFO`
50
50
  or `logging.DEBUG` logs by default.
51
- max_level: The maxium level at which to capture the logs. See the python logging
51
+ max_level: The maximum level at which to capture the logs. See the python logging
52
52
  module for valid levels. By default this captures to the `logging.CRITICAL` level
53
53
  thus, all the errors and critical messages will be captured as well.
54
54
  capture_warnings: Whether warnings from the python's `warnings` module
@@ -50,10 +50,9 @@ class OrderTester:
50
50
  expected = cmp_func(0, sign)
51
51
  actual = cmp_func(a, b)
52
52
  assert expected == actual, (
53
- "Ordering constraint violated. Expected X={} to {} Y={}, "
54
- "but X {} Y returned {}".format(
55
- a, ['be more than', 'equal', 'be less than'][sign + 1], b, cmp_name, actual
56
- )
53
+ f"Ordering constraint violated. Expected X={a} "
54
+ f"to {['be more than', 'equal', 'be less than'][sign + 1]} Y={b}, "
55
+ f"but X {cmp_name} Y returned {actual}"
57
56
  )
58
57
 
59
58
  def _verify_ordering(self, a: Any, b: Any, sign: int):
@@ -74,7 +73,7 @@ class OrderTester:
74
73
  " if not isinstance(other, type(self)):\n"
75
74
  " return NotImplemented\n"
76
75
  "\n"
77
- "That rule is being violated by this value: {!r}".format(item)
76
+ f"That rule is being violated by this value: {item!r}"
78
77
  ) from ex
79
78
 
80
79
  def add_ascending(self, *items: Any):
@@ -114,9 +114,7 @@ def random_circuit(
114
114
  free_qubits = set(qubits)
115
115
  while len(free_qubits) >= max_arity:
116
116
  gate, arity = gate_arity_pairs[prng.randint(num_gates)]
117
- op_qubits = prng.choice(
118
- sorted(free_qubits), size=arity, replace=False # type: ignore[arg-type]
119
- )
117
+ op_qubits = prng.choice(sorted(free_qubits), size=arity, replace=False)
120
118
  free_qubits.difference_update(op_qubits)
121
119
  if prng.rand() <= op_density:
122
120
  operations.append(gate(*op_qubits))
@@ -127,8 +125,8 @@ def random_circuit(
127
125
 
128
126
  def random_two_qubit_circuit_with_czs(
129
127
  num_czs: int = 3,
130
- q0: Qid = None,
131
- q1: Qid = None,
128
+ q0: Optional[Qid] = None,
129
+ q1: Optional[Qid] = None,
132
130
  random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
133
131
  ) -> circuits.Circuit:
134
132
  """Creates a random two qubit circuit with the given number of CNOTs.