cirq-core 1.1.0.dev20221220224914__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 (228) 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/contrib/acquaintance/bipartite.py +1 -1
  18. cirq/contrib/acquaintance/devices.py +2 -2
  19. cirq/contrib/acquaintance/executor.py +5 -2
  20. cirq/contrib/acquaintance/gates.py +3 -2
  21. cirq/contrib/acquaintance/permutation.py +13 -2
  22. cirq/contrib/acquaintance/testing.py +3 -5
  23. cirq/contrib/paulistring/recombine.py +3 -6
  24. cirq/contrib/qasm_import/_parser.py +17 -21
  25. cirq/contrib/qasm_import/_parser_test.py +30 -45
  26. cirq/contrib/qcircuit/qcircuit_test.py +3 -7
  27. cirq/contrib/quantum_volume/quantum_volume.py +3 -3
  28. cirq/contrib/quimb/mps_simulator.py +1 -1
  29. cirq/contrib/quimb/state_vector.py +2 -0
  30. cirq/contrib/quirk/quirk_gate.py +1 -0
  31. cirq/contrib/svg/svg.py +4 -7
  32. cirq/contrib/svg/svg_test.py +29 -1
  33. cirq/devices/grid_qubit.py +26 -28
  34. cirq/devices/grid_qubit_test.py +21 -5
  35. cirq/devices/line_qubit.py +10 -12
  36. cirq/devices/line_qubit_test.py +9 -2
  37. cirq/devices/named_topologies.py +1 -1
  38. cirq/devices/noise_model.py +4 -1
  39. cirq/devices/superconducting_qubits_noise_properties.py +1 -3
  40. cirq/experiments/n_qubit_tomography.py +1 -1
  41. cirq/experiments/qubit_characterizations.py +2 -2
  42. cirq/experiments/single_qubit_readout_calibration.py +1 -1
  43. cirq/experiments/t2_decay_experiment.py +1 -1
  44. cirq/experiments/xeb_simulation_test.py +2 -2
  45. cirq/interop/quirk/cells/testing.py +1 -1
  46. cirq/json_resolver_cache.py +1 -0
  47. cirq/linalg/__init__.py +2 -0
  48. cirq/linalg/decompositions_test.py +4 -4
  49. cirq/linalg/diagonalize_test.py +5 -6
  50. cirq/linalg/transformations.py +72 -9
  51. cirq/linalg/transformations_test.py +23 -7
  52. cirq/ops/__init__.py +4 -0
  53. cirq/ops/arithmetic_operation.py +4 -6
  54. cirq/ops/classically_controlled_operation.py +10 -3
  55. cirq/ops/clifford_gate.py +1 -7
  56. cirq/ops/common_channels.py +21 -15
  57. cirq/ops/common_gate_families.py +2 -3
  58. cirq/ops/common_gates.py +48 -11
  59. cirq/ops/common_gates_test.py +4 -0
  60. cirq/ops/controlled_gate.py +44 -18
  61. cirq/ops/controlled_operation.py +13 -5
  62. cirq/ops/dense_pauli_string.py +14 -19
  63. cirq/ops/diagonal_gate.py +3 -4
  64. cirq/ops/eigen_gate.py +8 -10
  65. cirq/ops/eigen_gate_test.py +6 -0
  66. cirq/ops/gate_operation.py +11 -6
  67. cirq/ops/gate_operation_test.py +11 -2
  68. cirq/ops/gateset.py +2 -1
  69. cirq/ops/gateset_test.py +38 -5
  70. cirq/ops/global_phase_op.py +28 -2
  71. cirq/ops/global_phase_op_test.py +21 -0
  72. cirq/ops/identity.py +1 -1
  73. cirq/ops/kraus_channel_test.py +2 -2
  74. cirq/ops/linear_combinations.py +7 -6
  75. cirq/ops/linear_combinations_test.py +26 -10
  76. cirq/ops/matrix_gates.py +8 -4
  77. cirq/ops/matrix_gates_test.py +25 -3
  78. cirq/ops/measure_util.py +13 -5
  79. cirq/ops/measure_util_test.py +8 -2
  80. cirq/ops/measurement_gate.py +1 -1
  81. cirq/ops/measurement_gate_test.py +9 -4
  82. cirq/ops/mixed_unitary_channel_test.py +4 -4
  83. cirq/ops/named_qubit.py +2 -4
  84. cirq/ops/parity_gates.py +5 -1
  85. cirq/ops/parity_gates_test.py +6 -0
  86. cirq/ops/pauli_gates.py +9 -9
  87. cirq/ops/pauli_string.py +4 -2
  88. cirq/ops/pauli_string_raw_types.py +4 -11
  89. cirq/ops/pauli_string_test.py +13 -13
  90. cirq/ops/pauli_sum_exponential.py +6 -1
  91. cirq/ops/qubit_manager.py +97 -0
  92. cirq/ops/qubit_manager_test.py +66 -0
  93. cirq/ops/raw_types.py +75 -33
  94. cirq/ops/raw_types_test.py +34 -0
  95. cirq/ops/three_qubit_gates.py +16 -10
  96. cirq/ops/three_qubit_gates_test.py +4 -2
  97. cirq/ops/two_qubit_diagonal_gate.py +3 -3
  98. cirq/ops/wait_gate.py +1 -1
  99. cirq/protocols/__init__.py +1 -0
  100. cirq/protocols/act_on_protocol.py +3 -3
  101. cirq/protocols/act_on_protocol_test.py +5 -5
  102. cirq/protocols/apply_channel_protocol.py +9 -8
  103. cirq/protocols/apply_mixture_protocol.py +8 -8
  104. cirq/protocols/apply_mixture_protocol_test.py +1 -1
  105. cirq/protocols/apply_unitary_protocol.py +66 -19
  106. cirq/protocols/apply_unitary_protocol_test.py +50 -0
  107. cirq/protocols/circuit_diagram_info_protocol.py +7 -9
  108. cirq/protocols/decompose_protocol.py +167 -125
  109. cirq/protocols/decompose_protocol_test.py +132 -2
  110. cirq/protocols/has_stabilizer_effect_protocol.py +2 -1
  111. cirq/protocols/inverse_protocol.py +2 -2
  112. cirq/protocols/json_serialization_test.py +3 -3
  113. cirq/protocols/json_test_data/Linspace.json +20 -7
  114. cirq/protocols/json_test_data/Linspace.repr +4 -1
  115. cirq/protocols/json_test_data/Points.json +19 -8
  116. cirq/protocols/json_test_data/Points.repr +4 -1
  117. cirq/protocols/json_test_data/Result.repr_inward +1 -1
  118. cirq/protocols/json_test_data/ResultDict.repr +1 -1
  119. cirq/protocols/json_test_data/ResultDict.repr_inward +1 -1
  120. cirq/protocols/json_test_data/TrialResult.repr_inward +1 -1
  121. cirq/protocols/json_test_data/XPowGate.json +13 -5
  122. cirq/protocols/json_test_data/XPowGate.repr +1 -1
  123. cirq/protocols/json_test_data/ZPowGate.json +13 -5
  124. cirq/protocols/json_test_data/ZPowGate.repr +1 -1
  125. cirq/protocols/json_test_data/ZipLongest.json +19 -0
  126. cirq/protocols/json_test_data/ZipLongest.repr +1 -0
  127. cirq/protocols/json_test_data/spec.py +1 -0
  128. cirq/protocols/kraus_protocol.py +3 -4
  129. cirq/protocols/measurement_key_protocol.py +3 -1
  130. cirq/protocols/mixture_protocol.py +3 -2
  131. cirq/protocols/phase_protocol.py +3 -3
  132. cirq/protocols/pow_protocol.py +1 -2
  133. cirq/protocols/qasm.py +4 -4
  134. cirq/protocols/qid_shape_protocol.py +8 -8
  135. cirq/protocols/resolve_parameters.py +8 -3
  136. cirq/protocols/resolve_parameters_test.py +3 -3
  137. cirq/protocols/unitary_protocol.py +19 -11
  138. cirq/protocols/unitary_protocol_test.py +37 -0
  139. cirq/qis/channels.py +1 -1
  140. cirq/qis/clifford_tableau.py +4 -5
  141. cirq/qis/quantum_state_representation.py +7 -9
  142. cirq/qis/states.py +21 -13
  143. cirq/qis/states_test.py +7 -0
  144. cirq/sim/clifford/clifford_simulator.py +3 -3
  145. cirq/sim/density_matrix_simulation_state.py +2 -1
  146. cirq/sim/density_matrix_simulator.py +1 -1
  147. cirq/sim/density_matrix_simulator_test.py +9 -5
  148. cirq/sim/density_matrix_utils.py +7 -32
  149. cirq/sim/mux.py +2 -2
  150. cirq/sim/simulation_state.py +58 -18
  151. cirq/sim/simulation_state_base.py +5 -2
  152. cirq/sim/simulation_state_test.py +121 -9
  153. cirq/sim/simulation_utils.py +59 -0
  154. cirq/sim/simulation_utils_test.py +32 -0
  155. cirq/sim/simulator.py +2 -1
  156. cirq/sim/simulator_base_test.py +3 -3
  157. cirq/sim/sparse_simulator.py +1 -1
  158. cirq/sim/sparse_simulator_test.py +5 -5
  159. cirq/sim/state_vector.py +7 -36
  160. cirq/sim/state_vector_simulation_state.py +18 -1
  161. cirq/sim/state_vector_simulator.py +3 -2
  162. cirq/sim/state_vector_simulator_test.py +24 -2
  163. cirq/sim/state_vector_test.py +46 -15
  164. cirq/study/__init__.py +1 -0
  165. cirq/study/flatten_expressions.py +2 -2
  166. cirq/study/resolver.py +2 -0
  167. cirq/study/resolver_test.py +1 -1
  168. cirq/study/result.py +1 -1
  169. cirq/study/sweeps.py +103 -9
  170. cirq/study/sweeps_test.py +64 -0
  171. cirq/testing/__init__.py +4 -0
  172. cirq/testing/circuit_compare.py +15 -18
  173. cirq/testing/consistent_act_on.py +4 -4
  174. cirq/testing/consistent_controlled_gate_op_test.py +1 -1
  175. cirq/testing/consistent_decomposition.py +11 -2
  176. cirq/testing/consistent_decomposition_test.py +8 -1
  177. cirq/testing/consistent_protocols.py +2 -0
  178. cirq/testing/consistent_protocols_test.py +8 -4
  179. cirq/testing/consistent_qasm.py +8 -15
  180. cirq/testing/consistent_specified_has_unitary.py +1 -1
  181. cirq/testing/consistent_unitary.py +85 -0
  182. cirq/testing/consistent_unitary_test.py +96 -0
  183. cirq/testing/equivalent_repr_eval.py +10 -10
  184. cirq/testing/json.py +3 -3
  185. cirq/testing/logs.py +1 -1
  186. cirq/testing/order_tester.py +4 -5
  187. cirq/testing/random_circuit.py +3 -5
  188. cirq/testing/sample_gates.py +79 -0
  189. cirq/testing/sample_gates_test.py +59 -0
  190. cirq/transformers/__init__.py +2 -0
  191. cirq/transformers/analytical_decompositions/__init__.py +8 -0
  192. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +130 -0
  193. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +58 -0
  194. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +230 -0
  195. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +112 -0
  196. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -3
  197. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
  198. cirq/transformers/expand_composite.py +1 -1
  199. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +4 -4
  200. cirq/transformers/measurement_transformers.py +4 -4
  201. cirq/transformers/merge_single_qubit_gates.py +17 -4
  202. cirq/transformers/routing/route_circuit_cqc.py +2 -2
  203. cirq/transformers/stratify.py +125 -62
  204. cirq/transformers/stratify_test.py +20 -16
  205. cirq/transformers/transformer_api.py +1 -1
  206. cirq/transformers/transformer_primitives.py +3 -2
  207. cirq/transformers/transformer_primitives_test.py +11 -0
  208. cirq/value/abc_alt.py +3 -2
  209. cirq/value/abc_alt_test.py +1 -0
  210. cirq/value/classical_data.py +10 -10
  211. cirq/value/digits.py +2 -2
  212. cirq/value/linear_dict.py +18 -19
  213. cirq/value/product_state.py +7 -6
  214. cirq/value/value_equality_attr.py +2 -2
  215. cirq/vis/heatmap.py +1 -1
  216. cirq/vis/heatmap_test.py +2 -2
  217. cirq/work/collector.py +2 -2
  218. cirq/work/observable_measurement_data.py +5 -5
  219. cirq/work/observable_readout_calibration.py +3 -1
  220. cirq/work/observable_settings.py +1 -1
  221. cirq/work/pauli_sum_collector.py +9 -8
  222. cirq/work/sampler.py +2 -0
  223. cirq/work/zeros_sampler.py +2 -2
  224. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
  225. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/RECORD +228 -214
  226. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
  227. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
  228. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
cirq/qis/states_test.py CHANGED
@@ -475,6 +475,13 @@ def test_dirac_notation_precision():
475
475
  assert_dirac_notation_python([sqrt, sqrt], "0.707|0⟩ + 0.707|1⟩", decimals=3)
476
476
 
477
477
 
478
+ def test_dirac_notation_invalid():
479
+ with pytest.raises(ValueError, match='state_vector has incorrect size'):
480
+ _ = cirq.dirac_notation([0.0, 0.0, 1.0])
481
+ with pytest.raises(ValueError, match='state_vector has incorrect size'):
482
+ _ = cirq.dirac_notation([1.0, 1.0], qid_shape=(3,))
483
+
484
+
478
485
  def test_to_valid_state_vector():
479
486
  with pytest.raises(ValueError, match='Computational basis state is out of range'):
480
487
  cirq.to_valid_state_vector(2, 1)
@@ -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
  """An efficient simulator for Clifford circuits.
15
16
 
16
17
  Allowed operations include:
@@ -109,7 +110,6 @@ class CliffordSimulator(
109
110
  measurements: Dict[str, np.ndarray],
110
111
  final_simulator_state: 'cirq.SimulationStateBase[cirq.StabilizerChFormSimulationState]',
111
112
  ):
112
-
113
113
  return CliffordTrialResult(
114
114
  params=params, measurements=measurements, final_simulator_state=final_simulator_state
115
115
  )
@@ -259,8 +259,8 @@ class CliffordState:
259
259
  ):
260
260
  if not isinstance(op.gate, cirq.MeasurementGate):
261
261
  raise TypeError(
262
- 'apply_measurement only supports cirq.MeasurementGate operations. Found %s instead.'
263
- % str(op.gate)
262
+ f'apply_measurement only supports cirq.MeasurementGate operations. '
263
+ f'Found {op.gate} instead.'
264
264
  )
265
265
 
266
266
  if collapse_state_vector:
@@ -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
  """Objects and methods for acting efficiently on a density matrix."""
15
16
 
16
17
  from typing import Any, Callable, List, Optional, Sequence, Tuple, Type, TYPE_CHECKING, Union
@@ -305,7 +306,7 @@ class DensityMatrixSimulationState(SimulationState[_BufferedDensityMatrix]):
305
306
  raise TypeError(
306
307
  "Can't simulate operations that don't implement "
307
308
  "SupportsUnitary, SupportsConsistentApplyUnitary, "
308
- "SupportsMixture or SupportsKraus or is a measurement: {!r}".format(action)
309
+ f"SupportsMixture or SupportsKraus or is a measurement: {action!r}"
309
310
  )
310
311
 
311
312
  def __repr__(self) -> str:
@@ -303,7 +303,7 @@ class DensityMatrixStepResult(simulator_base.StepResultBase['cirq.DensityMatrixS
303
303
  # Dtype doesn't have a good repr, so we work around by invoking __name__.
304
304
  return (
305
305
  f'cirq.DensityMatrixStepResult(sim_state={self._sim_state!r},'
306
- f' dtype=np.{self._dtype.__name__})'
306
+ f' dtype=np.{np.dtype(self._dtype)!r})'
307
307
  )
308
308
 
309
309
 
@@ -950,10 +950,13 @@ def test_density_matrix_step_result_repr():
950
950
  )
951
951
  )
952
952
  )
953
- == "cirq.DensityMatrixStepResult(sim_state=cirq.DensityMatrixSimulationState("
954
- "initial_state=np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], dtype=np.complex64), "
953
+ == "cirq.DensityMatrixStepResult("
954
+ "sim_state=cirq.DensityMatrixSimulationState("
955
+ "initial_state=np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], "
956
+ "dtype=np.dtype('complex64')), "
955
957
  "qubits=(cirq.LineQubit(0),), "
956
- "classical_data=cirq.ClassicalDataDictionaryStore()), dtype=np.complex64)"
958
+ "classical_data=cirq.ClassicalDataDictionaryStore()), "
959
+ "dtype=np.dtype('complex64'))"
957
960
  )
958
961
 
959
962
 
@@ -1034,9 +1037,10 @@ def test_density_matrix_trial_result_repr():
1034
1037
  expected_repr = (
1035
1038
  "cirq.DensityMatrixTrialResult("
1036
1039
  "params=cirq.ParamResolver({'s': 1}), "
1037
- "measurements={'m': np.array([[1]], dtype=np.int32)}, "
1040
+ "measurements={'m': np.array([[1]], dtype=np.dtype('int32'))}, "
1038
1041
  "final_simulator_state=cirq.DensityMatrixSimulationState("
1039
- "initial_state=np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], dtype=np.complex64), "
1042
+ "initial_state=np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], "
1043
+ "dtype=np.dtype('complex64')), "
1040
1044
  "qubits=(cirq.LineQubit(0),), "
1041
1045
  "classical_data=cirq.ClassicalDataDictionaryStore()))"
1042
1046
  )
@@ -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
  """Code to handle density matrices."""
15
16
 
16
17
  from typing import List, Optional, TYPE_CHECKING, Tuple, Sequence
@@ -18,6 +19,7 @@ from typing import List, Optional, TYPE_CHECKING, Tuple, Sequence
18
19
  import numpy as np
19
20
 
20
21
  from cirq import linalg, value
22
+ from cirq.sim import simulation_utils
21
23
 
22
24
  if TYPE_CHECKING:
23
25
  import cirq
@@ -188,33 +190,8 @@ def _probs(
188
190
  """Returns the probabilities for a measurement on the given indices."""
189
191
  # Only diagonal elements matter.
190
192
  all_probs = np.diagonal(np.reshape(density_matrix, (np.prod(qid_shape, dtype=np.int64),) * 2))
191
- # Shape into a tensor
192
- tensor = np.reshape(all_probs, qid_shape)
193
-
194
- # Calculate the probabilities for measuring the particular results.
195
- if len(indices) == len(qid_shape):
196
- # We're measuring every qudit, so no need for fancy indexing
197
- probs = np.abs(tensor)
198
- probs = np.transpose(probs, indices)
199
- probs = probs.reshape(-1)
200
- else:
201
- # Fancy indexing required
202
- meas_shape = tuple(qid_shape[i] for i in indices)
203
- probs = np.abs(
204
- [
205
- tensor[
206
- linalg.slice_for_qubits_equal_to(
207
- indices, big_endian_qureg_value=b, qid_shape=qid_shape
208
- )
209
- ]
210
- for b in range(np.prod(meas_shape, dtype=np.int64))
211
- ]
212
- )
213
- probs = np.sum(probs, axis=tuple(range(1, len(probs.shape))))
214
193
 
215
- # To deal with rounding issues, ensure that the probabilities sum to 1.
216
- probs /= np.sum(probs)
217
- return probs
194
+ return simulation_utils.state_probabilities_by_indices(all_probs.real, indices, qid_shape)
218
195
 
219
196
 
220
197
  def _validate_density_matrix_qid_shape(
@@ -227,10 +204,8 @@ def _validate_density_matrix_qid_shape(
227
204
  if len(shape) == 2:
228
205
  if np.prod(qid_shape, dtype=np.int64) ** 2 != np.prod(shape, dtype=np.int64):
229
206
  raise ValueError(
230
- 'Matrix size does not match qid shape {!r}. Got matrix with '
231
- 'shape {!r}. Expected {!r}.'.format(
232
- qid_shape, shape, np.prod(qid_shape, dtype=np.int64)
233
- )
207
+ f'Matrix size does not match qid shape {qid_shape!r}. Got matrix with '
208
+ f'shape {shape!r}. Expected {np.prod(qid_shape, dtype=np.int64)!r}.'
234
209
  )
235
210
  return qid_shape
236
211
  if len(shape) % 2 != 0:
@@ -257,12 +232,12 @@ def _validate_num_qubits(density_matrix: np.ndarray) -> int:
257
232
  if row_size & (row_size - 1):
258
233
  raise ValueError(
259
234
  'Matrix could not be shaped into a square matrix with dimensions '
260
- 'that are a power of two. Shape was {}'.format(shape)
235
+ f'that are a power of two. Shape was {shape}'
261
236
  )
262
237
  if len(shape) > 2 and not np.allclose(shape, 2):
263
238
  raise ValueError(
264
239
  'Matrix is a tensor of rank greater than 2, but had dimensions '
265
- 'that are not powers of two. Shape was {}'.format(shape)
240
+ f'that are not powers of two. Shape was {shape}'
266
241
  )
267
242
  return int(row_size).bit_length() - 1
268
243
 
cirq/sim/mux.py CHANGED
@@ -139,7 +139,7 @@ def final_state_vector(
139
139
  Returns:
140
140
  The state vector resulting from applying the given unitary operations to
141
141
  the desired initial state. Specifically, a numpy array containing the
142
- the amplitudes in np.kron order, where the order of arguments to kron
142
+ amplitudes in np.kron order, where the order of arguments to kron
143
143
  is determined by the qubit order argument (which defaults to just
144
144
  sorting the qubits that are present into an ascending order).
145
145
 
@@ -160,7 +160,7 @@ def final_state_vector(
160
160
  "because it is not unitary. "
161
161
  "Maybe you wanted `cirq.final_density_matrix`?\n"
162
162
  "\n"
163
- "Program: {!r}".format(circuit_like)
163
+ f"Program: {circuit_like!r}"
164
164
  )
165
165
 
166
166
  result = sparse_simulator.Simulator(dtype=dtype, seed=seed).simulate(
@@ -23,18 +23,19 @@ from typing import (
23
23
  List,
24
24
  Optional,
25
25
  Sequence,
26
+ Set,
26
27
  TypeVar,
27
28
  TYPE_CHECKING,
28
29
  Tuple,
29
30
  )
31
+ from typing_extensions import Self
30
32
 
31
33
  import numpy as np
32
34
 
33
- from cirq import protocols, value
34
- from cirq.protocols.decompose_protocol import _try_decompose_into_operations_and_qubits
35
+ from cirq import ops, protocols, value
36
+
35
37
  from cirq.sim.simulation_state_base import SimulationStateBase
36
38
 
37
- TSelf = TypeVar('TSelf', bound='SimulationState')
38
39
  TState = TypeVar('TState', bound='cirq.QuantumStateRepresentation')
39
40
 
40
41
  if TYPE_CHECKING:
@@ -146,7 +147,7 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
146
147
  return self._state.sample(self.get_axes(qubits), repetitions, seed)
147
148
  raise NotImplementedError()
148
149
 
149
- def copy(self: TSelf, deep_copy_buffers: bool = True) -> TSelf:
150
+ def copy(self, deep_copy_buffers: bool = True) -> Self:
150
151
  """Creates a copy of the object.
151
152
 
152
153
  Args:
@@ -162,11 +163,43 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
162
163
  args._state = self._state.copy(deep_copy_buffers=deep_copy_buffers)
163
164
  return args
164
165
 
165
- def create_merged_state(self: TSelf) -> TSelf:
166
+ def create_merged_state(self) -> Self:
166
167
  """Creates a final merged state."""
167
168
  return self
168
169
 
169
- def kronecker_product(self: TSelf, other: TSelf, *, inplace=False) -> TSelf:
170
+ def add_qubits(self: Self, qubits: Sequence['cirq.Qid']) -> Self:
171
+ """Add `qubits` in the `|0>` state to a new state space and take the kron product.
172
+
173
+ Args:
174
+ qubits: Sequence of qubits to be added.
175
+
176
+ Returns:
177
+ NotImplemented: If the subclass does not implement this method.
178
+ Self: A `cirq.SimulationState` with qubits added or `self` if there are no qubits to
179
+ add.
180
+ """
181
+ if not qubits:
182
+ return self
183
+ return NotImplemented
184
+
185
+ def remove_qubits(self: Self, qubits: Sequence['cirq.Qid']) -> Self:
186
+ """Remove `qubits` from the state space.
187
+
188
+ The qubits to be removed should be untangled from rest of the system and in the |0> state.
189
+
190
+ Args:
191
+ qubits: Sequence of qubits to be removed.
192
+
193
+ Returns:
194
+ NotImplemented: If the subclass does not implement this method.
195
+ Self: A `cirq.SimulationState` with qubits removed or `self` if there are no qubits to
196
+ remove.
197
+ """
198
+ if not qubits:
199
+ return self
200
+ return NotImplemented
201
+
202
+ def kronecker_product(self, other: Self, *, inplace=False) -> Self:
170
203
  """Joins two state spaces together."""
171
204
  args = self if inplace else copy.copy(self)
172
205
  args._state = self._state.kron(other._state)
@@ -174,8 +207,8 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
174
207
  return args
175
208
 
176
209
  def factor(
177
- self: TSelf, qubits: Sequence['cirq.Qid'], *, validate=True, atol=1e-07, inplace=False
178
- ) -> Tuple[TSelf, TSelf]:
210
+ self, qubits: Sequence['cirq.Qid'], *, validate=True, atol=1e-07, inplace=False
211
+ ) -> Tuple[Self, Self]:
179
212
  """Splits two state spaces after a measurement or reset."""
180
213
  extracted = copy.copy(self)
181
214
  remainder = self if inplace else copy.copy(self)
@@ -191,9 +224,7 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
191
224
  """Subclasses that allow factorization should override this."""
192
225
  return self._state.supports_factor if self._state is not None else False
193
226
 
194
- def transpose_to_qubit_order(
195
- self: TSelf, qubits: Sequence['cirq.Qid'], *, inplace=False
196
- ) -> TSelf:
227
+ def transpose_to_qubit_order(self, qubits: Sequence['cirq.Qid'], *, inplace=False) -> Self:
197
228
  """Physically reindexes the state by the new basis.
198
229
 
199
230
  Args:
@@ -276,7 +307,7 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
276
307
  args._set_qubits(qubits)
277
308
  return args
278
309
 
279
- def __getitem__(self: TSelf, item: Optional['cirq.Qid']) -> TSelf:
310
+ def __getitem__(self, item: Optional['cirq.Qid']) -> Self:
280
311
  if item not in self.qubit_map:
281
312
  raise IndexError(f'{item} not in {self.qubits}')
282
313
  return self
@@ -295,14 +326,23 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
295
326
  def strat_act_on_from_apply_decompose(
296
327
  val: Any, args: 'cirq.SimulationState', qubits: Sequence['cirq.Qid']
297
328
  ) -> bool:
298
- operations, qubits1, _ = _try_decompose_into_operations_and_qubits(val)
299
- assert len(qubits1) == len(qubits)
300
- qubit_map = {q: qubits[i] for i, q in enumerate(qubits1)}
301
- if operations is None:
329
+ if isinstance(val, ops.Gate):
330
+ decomposed = protocols.decompose_once_with_qubits(val, qubits, flatten=False, default=None)
331
+ else:
332
+ decomposed = protocols.decompose_once(val, flatten=False, default=None)
333
+ if decomposed is None:
302
334
  return NotImplemented
303
- for operation in operations:
304
- operation = operation.with_qubits(*[qubit_map[q] for q in operation.qubits])
335
+ all_ancilla: Set['cirq.Qid'] = set()
336
+ for operation in ops.flatten_to_ops(decomposed):
337
+ curr_ancilla = tuple(q for q in operation.qubits if q not in args.qubits)
338
+ args = args.add_qubits(curr_ancilla)
339
+ if args is NotImplemented:
340
+ return NotImplemented
341
+ all_ancilla.update(curr_ancilla)
305
342
  protocols.act_on(operation, args)
343
+ args = args.remove_qubits(tuple(all_ancilla))
344
+ if args is NotImplemented:
345
+ raise TypeError(f"{type(args)} implements add_qubits but not remove_qubits.")
306
346
  return True
307
347
 
308
348
 
@@ -27,6 +27,7 @@ from typing import (
27
27
  TypeVar,
28
28
  Union,
29
29
  )
30
+ from typing_extensions import Self
30
31
 
31
32
  import numpy as np
32
33
 
@@ -37,7 +38,6 @@ if TYPE_CHECKING:
37
38
  import cirq
38
39
 
39
40
 
40
- TSelfTarget = TypeVar('TSelfTarget', bound='SimulationStateBase')
41
41
  TSimulationState = TypeVar('TSimulationState', bound='cirq.SimulationState')
42
42
 
43
43
 
@@ -98,7 +98,7 @@ class SimulationStateBase(Generic[TSimulationState], metaclass=abc.ABCMeta):
98
98
  protocols.act_on(op, self)
99
99
 
100
100
  @abc.abstractmethod
101
- def copy(self: TSelfTarget, deep_copy_buffers: bool = True) -> TSelfTarget:
101
+ def copy(self, deep_copy_buffers: bool = True) -> Self:
102
102
  """Creates a copy of the object.
103
103
 
104
104
  Args:
@@ -124,11 +124,14 @@ class SimulationStateBase(Generic[TSimulationState], metaclass=abc.ABCMeta):
124
124
  ) -> np.ndarray:
125
125
  """Samples the state value."""
126
126
 
127
+ @abc.abstractmethod
127
128
  def __getitem__(self, item: Optional['cirq.Qid']) -> TSimulationState:
128
129
  """Gets the item associated with the qubit."""
129
130
 
131
+ @abc.abstractmethod
130
132
  def __len__(self) -> int:
131
133
  """Gets the number of items in the mapping."""
132
134
 
135
+ @abc.abstractmethod
133
136
  def __iter__(self) -> Iterator[Optional['cirq.Qid']]:
134
137
  """Iterates the keys of the mapping."""
@@ -19,6 +19,7 @@ import pytest
19
19
 
20
20
  import cirq
21
21
  from cirq.sim import simulation_state
22
+ from cirq.testing import PhaseUsingCleanAncilla, PhaseUsingDirtyAncilla
22
23
 
23
24
 
24
25
  class DummyQuantumState(cirq.QuantumStateRepresentation):
@@ -33,14 +34,43 @@ class DummyQuantumState(cirq.QuantumStateRepresentation):
33
34
 
34
35
 
35
36
  class DummySimulationState(cirq.SimulationState):
36
- def __init__(self):
37
- super().__init__(state=DummyQuantumState(), qubits=cirq.LineQubit.range(2))
37
+ def __init__(self, qubits=cirq.LineQubit.range(2)):
38
+ super().__init__(state=DummyQuantumState(), qubits=qubits)
38
39
 
39
40
  def _act_on_fallback_(
40
41
  self, action: Any, qubits: Sequence['cirq.Qid'], allow_decompose: bool = True
41
42
  ) -> bool:
42
43
  return True
43
44
 
45
+ def add_qubits(self, qubits):
46
+ ret = super().add_qubits(qubits)
47
+ return self if NotImplemented else ret
48
+
49
+
50
+ class DelegatingAncillaZ(cirq.Gate):
51
+ def __init__(self, exponent=1, measure_ancilla: bool = False):
52
+ self._exponent = exponent
53
+ self._measure_ancilla = measure_ancilla
54
+
55
+ def num_qubits(self) -> int:
56
+ return 1
57
+
58
+ def _decompose_(self, qubits):
59
+ a = cirq.NamedQubit('a')
60
+ yield cirq.CX(qubits[0], a)
61
+ yield PhaseUsingCleanAncilla(self._exponent).on(a)
62
+ yield cirq.CX(qubits[0], a)
63
+ if self._measure_ancilla:
64
+ yield cirq.measure(a)
65
+
66
+
67
+ class Composite(cirq.Gate):
68
+ def num_qubits(self) -> int:
69
+ return 1
70
+
71
+ def _decompose_(self, qubits):
72
+ yield cirq.X(*qubits)
73
+
44
74
 
45
75
  def test_measurements():
46
76
  args = DummySimulationState()
@@ -49,19 +79,24 @@ def test_measurements():
49
79
 
50
80
 
51
81
  def test_decompose():
52
- class Composite(cirq.Gate):
53
- def num_qubits(self) -> int:
54
- return 1
55
-
56
- def _decompose_(self, qubits):
57
- yield cirq.X(*qubits)
58
-
59
82
  args = DummySimulationState()
60
83
  assert simulation_state.strat_act_on_from_apply_decompose(
61
84
  Composite(), args, [cirq.LineQubit(0)]
62
85
  )
63
86
 
64
87
 
88
+ def test_decompose_for_gate_allocating_qubits_raises():
89
+ class Composite(cirq.testing.SingleQubitGate):
90
+ def _decompose_(self, qubits):
91
+ anc = cirq.NamedQubit("anc")
92
+ yield cirq.CNOT(*qubits, anc)
93
+
94
+ args = DummySimulationState()
95
+
96
+ with pytest.raises(TypeError, match="add_qubits but not remove_qubits"):
97
+ simulation_state.strat_act_on_from_apply_decompose(Composite(), args, [cirq.LineQubit(0)])
98
+
99
+
65
100
  def test_mapping():
66
101
  args = DummySimulationState()
67
102
  assert list(iter(args)) == cirq.LineQubit.range(2)
@@ -101,3 +136,80 @@ def test_field_getters():
101
136
  args = DummySimulationState()
102
137
  assert args.prng is np.random
103
138
  assert args.qubit_map == {q: i for i, q in enumerate(cirq.LineQubit.range(2))}
139
+
140
+
141
+ @pytest.mark.parametrize('exp', np.linspace(0, 2 * np.pi, 10))
142
+ def test_delegating_gate_unitary(exp):
143
+ q = cirq.LineQubit(0)
144
+
145
+ test_circuit = cirq.Circuit()
146
+ test_circuit.append(cirq.H(q))
147
+ test_circuit.append(DelegatingAncillaZ(exp).on(q))
148
+
149
+ control_circuit = cirq.Circuit(cirq.H(q))
150
+ control_circuit.append(cirq.ZPowGate(exponent=exp).on(q))
151
+
152
+ assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
153
+ assert_test_circuit_for_sv_simulator(test_circuit, control_circuit)
154
+
155
+
156
+ @pytest.mark.parametrize('exp', np.linspace(0, 2 * np.pi, 10))
157
+ def test_delegating_gate_channel(exp):
158
+ q = cirq.LineQubit(0)
159
+
160
+ test_circuit = cirq.Circuit()
161
+ test_circuit.append(cirq.H(q))
162
+ test_circuit.append(DelegatingAncillaZ(exp, True).on(q))
163
+
164
+ control_circuit = cirq.Circuit(cirq.H(q))
165
+ control_circuit.append(cirq.ZPowGate(exponent=exp).on(q))
166
+
167
+ with pytest.raises(TypeError, match="DensityMatrixSimulator doesn't support"):
168
+ # TODO: This test should pass once we extend support to DensityMatrixSimulator.
169
+ assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
170
+
171
+
172
+ @pytest.mark.parametrize('num_ancilla', [1, 2, 3])
173
+ def test_phase_using_dirty_ancilla(num_ancilla: int):
174
+ q = cirq.LineQubit(0)
175
+ anc = cirq.NamedQubit.range(num_ancilla, prefix='anc')
176
+
177
+ u = cirq.MatrixGate(cirq.testing.random_unitary(2 ** (num_ancilla + 1)))
178
+ test_circuit = cirq.Circuit(
179
+ u.on(q, *anc), PhaseUsingDirtyAncilla(ancilla_bitsize=num_ancilla).on(q)
180
+ )
181
+ control_circuit = cirq.Circuit(u.on(q, *anc), cirq.Z(q))
182
+ assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
183
+ assert_test_circuit_for_sv_simulator(test_circuit, control_circuit)
184
+
185
+
186
+ @pytest.mark.parametrize('num_ancilla', [1, 2, 3])
187
+ @pytest.mark.parametrize('theta', np.linspace(0, 2 * np.pi, 10))
188
+ def test_phase_using_clean_ancilla(num_ancilla: int, theta: float):
189
+ q = cirq.LineQubit(0)
190
+ u = cirq.MatrixGate(cirq.testing.random_unitary(2))
191
+ test_circuit = cirq.Circuit(
192
+ u.on(q), PhaseUsingCleanAncilla(theta=theta, ancilla_bitsize=num_ancilla).on(q)
193
+ )
194
+ control_circuit = cirq.Circuit(u.on(q), cirq.ZPowGate(exponent=theta).on(q))
195
+ assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
196
+ assert_test_circuit_for_sv_simulator(test_circuit, control_circuit)
197
+
198
+
199
+ def assert_test_circuit_for_dm_simulator(test_circuit, control_circuit) -> None:
200
+ # Density Matrix Simulator: For unitary gates, this fallbacks to `cirq.apply_channel`
201
+ # which recursively calls to `cirq.apply_unitary(decompose=True)`.
202
+ for split_untangled_states in [True, False]:
203
+ sim = cirq.DensityMatrixSimulator(split_untangled_states=split_untangled_states)
204
+ control_sim = sim.simulate(control_circuit).final_density_matrix
205
+ test_sim = sim.simulate(test_circuit).final_density_matrix
206
+ assert np.allclose(test_sim, control_sim)
207
+
208
+
209
+ def assert_test_circuit_for_sv_simulator(test_circuit, control_circuit) -> None:
210
+ # State Vector Simulator.
211
+ for split_untangled_states in [True, False]:
212
+ sim = cirq.Simulator(split_untangled_states=split_untangled_states)
213
+ control_sim = sim.simulate(control_circuit).final_state_vector
214
+ test_sim = sim.simulate(test_circuit).final_state_vector
215
+ assert np.allclose(test_sim, control_sim)
@@ -0,0 +1,59 @@
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
+ from typing import Sequence, Tuple
15
+
16
+ import numpy as np
17
+
18
+ from cirq import linalg
19
+
20
+
21
+ def state_probabilities_by_indices(
22
+ state_probability: np.ndarray, indices: Sequence[int], qid_shape: Tuple[int, ...]
23
+ ) -> np.ndarray:
24
+ """Returns the probabilities for a state/measurement on the given indices.
25
+
26
+ Args:
27
+ state_probability: The multi-qubit state probability vector. This is an
28
+ array of 2 to the power of the number of real numbers, and
29
+ so state must be of size ``2**integer``. The `state_probability` can be
30
+ a vector of size ``2**integer`` or a tensor of shape
31
+ ``(2, 2, ..., 2)``.
32
+ indices: Which qubits are measured. The `state_probability` is assumed to be
33
+ supplied in big endian order. That is the xth index of v, when
34
+ expressed as a bitstring, has its largest values in the 0th index.
35
+ qid_shape: The qid shape of the `state_probability`.
36
+
37
+ Returns:
38
+ State probabilities.
39
+ """
40
+ probs = state_probability.reshape((-1,))
41
+ not_measured = [i for i in range(len(qid_shape)) if i not in indices]
42
+ if linalg.can_numpy_support_shape(qid_shape):
43
+ # Use numpy transpose if we can since it's more efficient.
44
+ probs = probs.reshape(qid_shape)
45
+ probs = np.transpose(probs, list(indices) + not_measured)
46
+ probs = probs.reshape((-1,))
47
+ else:
48
+ # If we can't use numpy due to numpy/numpy#5744, use a slower method.
49
+ probs = linalg.transpose_flattened_array(probs, qid_shape, list(indices) + not_measured)
50
+
51
+ if len(not_measured):
52
+ # Not all qudits are measured.
53
+ volume = np.prod([qid_shape[i] for i in indices])
54
+ # Reshape into a 2D array in which each of the measured states correspond to a row.
55
+ probs = probs.reshape((volume, -1))
56
+ probs = np.sum(probs, axis=-1)
57
+
58
+ # To deal with rounding issues, ensure that the probabilities sum to 1.
59
+ return probs / np.sum(probs)
@@ -0,0 +1,32 @@
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
+ import pytest
15
+
16
+ import numpy as np
17
+
18
+ from cirq.sim import simulation_utils
19
+ from cirq import testing
20
+
21
+
22
+ @pytest.mark.parametrize('n,m', [(n, m) for n in range(1, 4) for m in range(1, n + 1)])
23
+ def test_state_probabilities_by_indices(n: int, m: int):
24
+ np.random.seed(0)
25
+ state = testing.random_superposition(1 << n)
26
+ d = (state.conj() * state).real
27
+ desired_axes = list(np.random.choice(n, m, replace=False))
28
+ not_wanted = [i for i in range(n) if i not in desired_axes]
29
+ got = simulation_utils.state_probabilities_by_indices(d, desired_axes, (2,) * n)
30
+ want = np.transpose(d.reshape((2,) * n), desired_axes + not_wanted)
31
+ want = np.sum(want.reshape((1 << len(desired_axes), -1)), axis=-1)
32
+ np.testing.assert_allclose(want, got)
cirq/sim/simulator.py CHANGED
@@ -452,6 +452,7 @@ class SimulatesExpectationValues(metaclass=value.ABCMetaImplementAnyOneOf):
452
452
  ValueError if 'program' has terminal measurement(s) and
453
453
  'permit_terminal_measurements' is False.
454
454
  """
455
+ raise NotImplementedError
455
456
 
456
457
 
457
458
  class SimulatesFinalState(
@@ -959,7 +960,7 @@ def check_all_resolved(circuit):
959
960
  unresolved = [op for moment in circuit for op in moment if protocols.is_parameterized(op)]
960
961
  raise ValueError(
961
962
  'Circuit contains ops whose symbols were not specified in '
962
- 'parameter sweep. Ops: {}'.format(unresolved)
963
+ f'parameter sweep. Ops: {unresolved}'
963
964
  )
964
965
 
965
966