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
@@ -0,0 +1,97 @@
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 abc
16
+ import dataclasses
17
+ from typing import Iterable, List, TYPE_CHECKING
18
+ from cirq.ops import raw_types
19
+
20
+ if TYPE_CHECKING:
21
+ import cirq
22
+
23
+
24
+ class QubitManager(metaclass=abc.ABCMeta):
25
+ @abc.abstractmethod
26
+ def qalloc(self, n: int, dim: int = 2) -> List['cirq.Qid']:
27
+ """Allocate `n` clean qubits, i.e. qubits guaranteed to be in state |0>."""
28
+
29
+ @abc.abstractmethod
30
+ def qborrow(self, n: int, dim: int = 2) -> List['cirq.Qid']:
31
+ """Allocate `n` dirty qubits, i.e. the returned qubits can be in any state."""
32
+
33
+ @abc.abstractmethod
34
+ def qfree(self, qubits: Iterable['cirq.Qid']) -> None:
35
+ """Free pre-allocated clean or dirty qubits managed by this qubit manager."""
36
+
37
+
38
+ @dataclasses.dataclass(frozen=True)
39
+ class _BaseAncillaQid(raw_types.Qid):
40
+ id: int
41
+ dim: int = 2
42
+ prefix: str = ''
43
+
44
+ def _comparison_key(self) -> int:
45
+ return self.id
46
+
47
+ @property
48
+ def dimension(self) -> int:
49
+ return self.dim
50
+
51
+ def __repr__(self) -> str:
52
+ dim_str = f', dim={self.dim}' if self.dim != 2 else ''
53
+ prefix_str = f', prefix={self.prefix}' if self.prefix != '' else ''
54
+ return f"cirq.ops.{type(self).__name__}({self.id}{dim_str}{prefix_str})"
55
+
56
+
57
+ class CleanQubit(_BaseAncillaQid):
58
+ """An internal qid type that represents a clean ancilla allocation."""
59
+
60
+ def __str__(self) -> str:
61
+ dim_str = f' (d={self.dimension})' if self.dim != 2 else ''
62
+ return f"{self.prefix}_c({self.id}){dim_str}"
63
+
64
+
65
+ class BorrowableQubit(_BaseAncillaQid):
66
+ """An internal qid type that represents a dirty ancilla allocation."""
67
+
68
+ def __str__(self) -> str:
69
+ dim_str = f' (d={self.dimension})' if self.dim != 2 else ''
70
+ return f"{self.prefix}_b({self.id}){dim_str}"
71
+
72
+
73
+ class SimpleQubitManager(QubitManager):
74
+ """Allocates a new `CleanQubit`/`BorrowableQubit` for every `qalloc`/`qborrow` request."""
75
+
76
+ def __init__(self, prefix: str = ''):
77
+ self._clean_id = 0
78
+ self._borrow_id = 0
79
+ self._prefix = prefix
80
+
81
+ def qalloc(self, n: int, dim: int = 2) -> List['cirq.Qid']:
82
+ self._clean_id += n
83
+ return [CleanQubit(i, dim, self._prefix) for i in range(self._clean_id - n, self._clean_id)]
84
+
85
+ def qborrow(self, n: int, dim: int = 2) -> List['cirq.Qid']:
86
+ self._borrow_id = self._borrow_id + n
87
+ return [
88
+ BorrowableQubit(i, dim, self._prefix)
89
+ for i in range(self._borrow_id - n, self._borrow_id)
90
+ ]
91
+
92
+ def qfree(self, qubits: Iterable['cirq.Qid']) -> None:
93
+ for q in qubits:
94
+ good = isinstance(q, CleanQubit) and q.id < self._clean_id
95
+ good |= isinstance(q, BorrowableQubit) and q.id < self._borrow_id
96
+ if not good:
97
+ raise ValueError(f"{q} was not allocated by {self}")
@@ -0,0 +1,66 @@
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
+ from cirq.ops import qubit_manager as cqi
17
+ import pytest
18
+
19
+
20
+ def test_clean_qubits():
21
+ q = cqi.CleanQubit(1)
22
+ assert q.id == 1
23
+ assert q.dimension == 2
24
+ assert str(q) == '_c(1)'
25
+ assert repr(q) == 'cirq.ops.CleanQubit(1)'
26
+
27
+ q = cqi.CleanQubit(2, dim=3)
28
+ assert q.id == 2
29
+ assert q.dimension == 3
30
+ assert str(q) == '_c(2) (d=3)'
31
+ assert repr(q) == 'cirq.ops.CleanQubit(2, dim=3)'
32
+
33
+ assert cqi.CleanQubit(1) < cqi.CleanQubit(2)
34
+
35
+
36
+ def test_borrow_qubits():
37
+ q = cqi.BorrowableQubit(10)
38
+ assert q.id == 10
39
+ assert q.dimension == 2
40
+ assert str(q) == '_b(10)'
41
+ assert repr(q) == 'cirq.ops.BorrowableQubit(10)'
42
+
43
+ q = cqi.BorrowableQubit(20, dim=4)
44
+ assert q.id == 20
45
+ assert q.dimension == 4
46
+ assert str(q) == '_b(20) (d=4)'
47
+ assert repr(q) == 'cirq.ops.BorrowableQubit(20, dim=4)'
48
+
49
+ assert cqi.BorrowableQubit(1) < cqi.BorrowableQubit(2)
50
+
51
+
52
+ @pytest.mark.parametrize('_', range(2))
53
+ def test_simple_qubit_manager(_):
54
+ qm = cirq.ops.SimpleQubitManager()
55
+ assert qm.qalloc(1) == [cqi.CleanQubit(0)]
56
+ assert qm.qalloc(2) == [cqi.CleanQubit(1), cqi.CleanQubit(2)]
57
+ assert qm.qalloc(1, dim=3) == [cqi.CleanQubit(3, dim=3)]
58
+ assert qm.qborrow(1) == [cqi.BorrowableQubit(0)]
59
+ assert qm.qborrow(2) == [cqi.BorrowableQubit(1), cqi.BorrowableQubit(2)]
60
+ assert qm.qborrow(1, dim=3) == [cqi.BorrowableQubit(3, dim=3)]
61
+ qm.qfree([cqi.CleanQubit(i) for i in range(3)] + [cqi.CleanQubit(3, dim=3)])
62
+ qm.qfree([cqi.BorrowableQubit(i) for i in range(3)] + [cqi.BorrowableQubit(3, dim=3)])
63
+ with pytest.raises(ValueError, match="not allocated"):
64
+ qm.qfree([cqi.CleanQubit(10)])
65
+ with pytest.raises(ValueError, match="not allocated"):
66
+ qm.qfree([cqi.BorrowableQubit(10)])
cirq/ops/raw_types.py CHANGED
@@ -17,6 +17,7 @@
17
17
  import abc
18
18
  import functools
19
19
  from typing import (
20
+ cast,
20
21
  AbstractSet,
21
22
  Any,
22
23
  Callable,
@@ -30,16 +31,17 @@ from typing import (
30
31
  Optional,
31
32
  Sequence,
32
33
  Tuple,
33
- TypeVar,
34
34
  TYPE_CHECKING,
35
35
  Union,
36
36
  )
37
+ from typing_extensions import Self
37
38
 
38
39
  import numpy as np
39
40
  import sympy
40
41
 
41
42
  from cirq import protocols, value
42
43
  from cirq._import import LazyLoader
44
+ from cirq._compat import __cirq_debug__, cached_method
43
45
  from cirq.type_workarounds import NotImplementedType
44
46
  from cirq.ops import control_values as cv
45
47
 
@@ -109,7 +111,8 @@ class Qid(metaclass=abc.ABCMeta):
109
111
  def _cmp_tuple(self):
110
112
  return (type(self).__name__, repr(type(self)), self._comparison_key(), self.dimension)
111
113
 
112
- def __hash__(self):
114
+ @cached_method
115
+ def __hash__(self) -> int:
113
116
  return hash((Qid, self._comparison_key()))
114
117
 
115
118
  def __eq__(self, other):
@@ -215,7 +218,8 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
215
218
  Raises:
216
219
  ValueError: The gate can't be applied to the qubits.
217
220
  """
218
- _validate_qid_shape(self, qubits)
221
+ if __cirq_debug__.get():
222
+ _validate_qid_shape(self, qubits)
219
223
 
220
224
  def on(self, *qubits: Qid) -> 'Operation':
221
225
  """Returns an application of this gate to the given qubits.
@@ -254,19 +258,33 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
254
258
  raise TypeError(f'{targets[0]} object is not iterable.')
255
259
  t0 = list(targets[0])
256
260
  iterator = [t0] if t0 and isinstance(t0[0], Qid) else t0
257
- for target in iterator:
258
- if not isinstance(target, Sequence):
259
- raise ValueError(
260
- f'Inputs to multi-qubit gates must be Sequence[Qid].'
261
- f' Type: {type(target)}'
262
- )
263
- if not all(isinstance(x, Qid) for x in target):
264
- raise ValueError(f'All values in sequence should be Qids, but got {target}')
265
- if len(target) != self._num_qubits_():
266
- raise ValueError(f'Expected {self._num_qubits_()} qubits, got {target}')
267
- operations.append(self.on(*target))
261
+ if __cirq_debug__.get():
262
+ for target in iterator:
263
+ if not isinstance(target, Sequence):
264
+ raise ValueError(
265
+ f'Inputs to multi-qubit gates must be Sequence[Qid].'
266
+ f' Type: {type(target)}'
267
+ )
268
+ if not all(isinstance(x, Qid) for x in target):
269
+ raise ValueError(f'All values in sequence should be Qids, but got {target}')
270
+ if len(target) != self._num_qubits_():
271
+ raise ValueError(f'Expected {self._num_qubits_()} qubits, got {target}')
272
+ operations.append(self.on(*target))
273
+ else:
274
+ operations = [self.on(*target) for target in iterator]
268
275
  return operations
269
276
 
277
+ if not __cirq_debug__.get():
278
+ return [
279
+ op
280
+ for q in targets
281
+ for op in (
282
+ self.on_each(*q)
283
+ if isinstance(q, Iterable) and not isinstance(q, str)
284
+ else [self.on(cast('cirq.Qid', q))]
285
+ )
286
+ ]
287
+
270
288
  for target in targets:
271
289
  if isinstance(target, Qid):
272
290
  operations.append(self.on(target))
@@ -342,7 +360,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
342
360
  return self.on(*qubits)
343
361
 
344
362
  def with_probability(self, probability: 'cirq.TParamVal') -> 'cirq.Gate':
345
- """Creates a probabalistic channel with this gate.
363
+ """Creates a probabilistic channel with this gate.
346
364
 
347
365
  Args:
348
366
  probability: floating point value between 0 and 1, giving the
@@ -358,7 +376,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
358
376
 
359
377
  def controlled(
360
378
  self,
361
- num_controls: int = None,
379
+ num_controls: Optional[int] = None,
362
380
  control_values: Optional[
363
381
  Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
364
382
  ] = None,
@@ -406,6 +424,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
406
424
  @value.alternative(requires='_num_qubits_', implementation=_backwards_compatibility_num_qubits)
407
425
  def num_qubits(self) -> int:
408
426
  """The number of qubits this gate acts on."""
427
+ raise NotImplementedError
409
428
 
410
429
  def _num_qubits_from_shape(self) -> int:
411
430
  shape = self._qid_shape_()
@@ -420,6 +439,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
420
439
  @value.alternative(requires='_qid_shape_', implementation=_num_qubits_from_shape)
421
440
  def _num_qubits_(self) -> int:
422
441
  """The number of qubits this gate acts on."""
442
+ raise NotImplementedError
423
443
 
424
444
  def _default_shape_from_num_qubits(self) -> Tuple[int, ...]:
425
445
  num_qubits = self._num_qubits_()
@@ -433,6 +453,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
433
453
  the gate acts on. E.g. (2, 2, 2) for the three-qubit CCZ gate and
434
454
  (3, 3) for a 2-qutrit ternary gate.
435
455
  """
456
+ raise NotImplementedError
436
457
 
437
458
  def _commutes_on_qids_(
438
459
  self, qids: 'Sequence[cirq.Qid]', other: Any, *, atol: float = 1e-8
@@ -462,9 +483,6 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
462
483
  return protocols.obj_to_dict_helper(self, attribute_names=[])
463
484
 
464
485
 
465
- TSelf = TypeVar('TSelf', bound='Operation')
466
-
467
-
468
486
  class Operation(metaclass=abc.ABCMeta):
469
487
  """An effect applied to a collection of qubits.
470
488
 
@@ -488,11 +506,12 @@ class Operation(metaclass=abc.ABCMeta):
488
506
  """
489
507
  return len(self.qubits)
490
508
 
509
+ @cached_method
491
510
  def _qid_shape_(self) -> Tuple[int, ...]:
492
511
  return protocols.qid_shape(self.qubits)
493
512
 
494
513
  @abc.abstractmethod
495
- def with_qubits(self: TSelf, *new_qubits: 'cirq.Qid') -> TSelf:
514
+ def with_qubits(self, *new_qubits: 'cirq.Qid') -> Self:
496
515
  """Returns the same operation, but applied to different qubits.
497
516
 
498
517
  Args:
@@ -534,9 +553,8 @@ class Operation(metaclass=abc.ABCMeta):
534
553
  return TaggedOperation(self, *new_tags)
535
554
 
536
555
  def transform_qubits(
537
- self: TSelf,
538
- qubit_map: Union[Dict['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']],
539
- ) -> TSelf:
556
+ self, qubit_map: Union[Dict['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']]
557
+ ) -> Self:
540
558
  """Returns the same operation, but with different qubits.
541
559
 
542
560
  Args:
@@ -583,7 +601,7 @@ class Operation(metaclass=abc.ABCMeta):
583
601
  return ops.controlled_operation.ControlledOperation(control_qubits, self, control_values)
584
602
 
585
603
  def with_probability(self, probability: 'cirq.TParamVal') -> 'cirq.Operation':
586
- """Creates a probabalistic channel with this operation.
604
+ """Creates a probabilistic channel with this operation.
587
605
 
588
606
  Args:
589
607
  probability: floating point value between 0 and 1, giving the
@@ -617,7 +635,8 @@ class Operation(metaclass=abc.ABCMeta):
617
635
  Raises:
618
636
  ValueError: The operation had qids that don't match it's qid shape.
619
637
  """
620
- _validate_qid_shape(self, qubits)
638
+ if __cirq_debug__.get():
639
+ _validate_qid_shape(self, qubits)
621
640
 
622
641
  def _commutes_(
623
642
  self, other: Any, *, atol: float = 1e-8
@@ -811,7 +830,14 @@ class TaggedOperation(Operation):
811
830
  return protocols.obj_to_dict_helper(self, ['sub_operation', 'tags'])
812
831
 
813
832
  def _decompose_(self) -> 'cirq.OP_TREE':
814
- return protocols.decompose_once(self.sub_operation, default=None)
833
+ return self._decompose_with_context_()
834
+
835
+ def _decompose_with_context_(
836
+ self, context: Optional['cirq.DecompositionContext'] = None
837
+ ) -> 'cirq.OP_TREE':
838
+ return protocols.decompose_once(
839
+ self.sub_operation, default=None, flatten=False, context=context
840
+ )
815
841
 
816
842
  def _pauli_expansion_(self) -> value.LinearDict[str]:
817
843
  return protocols.pauli_expansion(self.sub_operation)
@@ -821,6 +847,7 @@ class TaggedOperation(Operation):
821
847
  ) -> Union[np.ndarray, None, NotImplementedType]:
822
848
  return protocols.apply_unitary(self.sub_operation, args, default=None)
823
849
 
850
+ @cached_method
824
851
  def _has_unitary_(self) -> bool:
825
852
  return protocols.has_unitary(self.sub_operation)
826
853
 
@@ -832,30 +859,36 @@ class TaggedOperation(Operation):
832
859
  ) -> Union[bool, NotImplementedType, None]:
833
860
  return protocols.commutes(self.sub_operation, other, atol=atol)
834
861
 
862
+ @cached_method
835
863
  def _has_mixture_(self) -> bool:
836
864
  return protocols.has_mixture(self.sub_operation)
837
865
 
838
866
  def _mixture_(self) -> Sequence[Tuple[float, Any]]:
839
867
  return protocols.mixture(self.sub_operation, NotImplemented)
840
868
 
869
+ @cached_method
841
870
  def _has_kraus_(self) -> bool:
842
871
  return protocols.has_kraus(self.sub_operation)
843
872
 
844
873
  def _kraus_(self) -> Union[Tuple[np.ndarray], NotImplementedType]:
845
874
  return protocols.kraus(self.sub_operation, NotImplemented)
846
875
 
876
+ @cached_method
847
877
  def _measurement_key_names_(self) -> FrozenSet[str]:
848
878
  return protocols.measurement_key_names(self.sub_operation)
849
879
 
880
+ @cached_method
850
881
  def _measurement_key_objs_(self) -> FrozenSet['cirq.MeasurementKey']:
851
882
  return protocols.measurement_key_objs(self.sub_operation)
852
883
 
884
+ @cached_method
853
885
  def _is_measurement_(self) -> bool:
854
886
  sub = getattr(self.sub_operation, "_is_measurement_", None)
855
887
  if sub is not None:
856
888
  return sub()
857
889
  return NotImplemented
858
890
 
891
+ @cached_method
859
892
  def _is_parameterized_(self) -> bool:
860
893
  return protocols.is_parameterized(self.sub_operation) or any(
861
894
  protocols.is_parameterized(tag) for tag in self.tags
@@ -867,6 +900,7 @@ class TaggedOperation(Operation):
867
900
  return sub(sim_state)
868
901
  return NotImplemented
869
902
 
903
+ @cached_method
870
904
  def _parameter_names_(self) -> AbstractSet[str]:
871
905
  tag_params = {name for tag in self.tags for name in protocols.parameter_names(tag)}
872
906
  return protocols.parameter_names(self.sub_operation) | tag_params
@@ -891,6 +925,7 @@ class TaggedOperation(Operation):
891
925
  ) + sub_op_info.wire_symbols[1:]
892
926
  return sub_op_info
893
927
 
928
+ @cached_method
894
929
  def _trace_distance_bound_(self) -> float:
895
930
  return protocols.trace_distance_bound(self.sub_operation)
896
931
 
@@ -951,7 +986,14 @@ class _InverseCompositeGate(Gate):
951
986
  return NotImplemented
952
987
 
953
988
  def _decompose_(self, qubits):
954
- return protocols.inverse(protocols.decompose_once_with_qubits(self._original, qubits))
989
+ return self._decompose_with_context_(qubits)
990
+
991
+ def _decompose_with_context_(
992
+ self, qubits: Sequence['cirq.Qid'], context: Optional['cirq.DecompositionContext'] = None
993
+ ) -> 'cirq.OP_TREE':
994
+ return protocols.inverse(
995
+ protocols.decompose_once_with_qubits(self._original, qubits, context=context)
996
+ )
955
997
 
956
998
  def _has_unitary_(self):
957
999
  from cirq import protocols, devices
@@ -962,9 +1004,11 @@ class _InverseCompositeGate(Gate):
962
1004
  for op in protocols.decompose_once_with_qubits(self._original, qubits)
963
1005
  )
964
1006
 
1007
+ @cached_method
965
1008
  def _is_parameterized_(self) -> bool:
966
1009
  return protocols.is_parameterized(self._original)
967
1010
 
1011
+ @cached_method
968
1012
  def _parameter_names_(self) -> AbstractSet[str]:
969
1013
  return protocols.parameter_names(self._original)
970
1014
 
@@ -998,15 +1042,13 @@ def _validate_qid_shape(val: Any, qubits: Sequence['cirq.Qid']) -> None:
998
1042
  qid_shape = protocols.qid_shape(val)
999
1043
  if len(qubits) != len(qid_shape):
1000
1044
  raise ValueError(
1001
- 'Wrong number of qubits for <{!r}>. '
1002
- 'Expected {} qubits but got <{!r}>.'.format(val, len(qid_shape), qubits)
1045
+ f'Wrong number of qubits for <{val!r}>. '
1046
+ f'Expected {len(qid_shape)} qubits but got <{qubits!r}>.'
1003
1047
  )
1004
1048
  if any(qid.dimension != dimension for qid, dimension in zip(qubits, qid_shape)):
1005
1049
  raise ValueError(
1006
- 'Wrong shape of qids for <{!r}>. '
1007
- 'Expected {} but got {} <{!r}>.'.format(
1008
- val, qid_shape, tuple(qid.dimension for qid in qubits), qubits
1009
- )
1050
+ f'Wrong shape of qids for <{val!r}>. '
1051
+ f'Expected {qid_shape} but got {tuple(qid.dimension for qid in qubits)} <{qubits!r}>.'
1010
1052
  )
1011
1053
  if len(set(qubits)) != len(qubits):
1012
1054
  raise ValueError(
@@ -151,6 +151,29 @@ def test_op_validate():
151
151
  op2.validate_args([cirq.LineQid(1, 2), cirq.LineQid(1, 2)])
152
152
 
153
153
 
154
+ def test_disable_op_validation():
155
+ q0, q1 = cirq.LineQubit.range(2)
156
+ h_op = cirq.H(q0)
157
+
158
+ # Fails normally.
159
+ with pytest.raises(ValueError, match='Wrong number'):
160
+ _ = cirq.H(q0, q1)
161
+ with pytest.raises(ValueError, match='Wrong number'):
162
+ h_op.validate_args([q0, q1])
163
+
164
+ # Passes, skipping validation.
165
+ with cirq.with_debug(False):
166
+ op = cirq.H(q0, q1)
167
+ assert op.qubits == (q0, q1)
168
+ h_op.validate_args([q0, q1])
169
+
170
+ # Fails again when validation is re-enabled.
171
+ with pytest.raises(ValueError, match='Wrong number'):
172
+ _ = cirq.H(q0, q1)
173
+ with pytest.raises(ValueError, match='Wrong number'):
174
+ h_op.validate_args([q0, q1])
175
+
176
+
154
177
  def test_default_validation_and_inverse():
155
178
  class TestGate(cirq.Gate):
156
179
  def _num_qubits_(self):
@@ -178,6 +201,8 @@ def test_default_validation_and_inverse():
178
201
  assert i**-1 == t
179
202
  assert t**-1 == i
180
203
  assert cirq.decompose(i) == [cirq.X(a), cirq.S(b) ** -1, cirq.Z(a)]
204
+ assert [*i._decompose_()] == [cirq.X(a), cirq.S(b) ** -1, cirq.Z(a)]
205
+ assert [*i.gate._decompose_([a, b])] == [cirq.X(a), cirq.S(b) ** -1, cirq.Z(a)]
181
206
  cirq.testing.assert_allclose_up_to_global_phase(
182
207
  cirq.unitary(i), cirq.unitary(t).conj().T, atol=1e-8
183
208
  )
@@ -595,6 +620,7 @@ def test_tagged_operation_forwards_protocols():
595
620
  np.testing.assert_equal(cirq.unitary(tagged_h), cirq.unitary(h))
596
621
  assert cirq.has_unitary(tagged_h)
597
622
  assert cirq.decompose(tagged_h) == cirq.decompose(h)
623
+ assert [*tagged_h._decompose_()] == cirq.decompose(h)
598
624
  assert cirq.pauli_expansion(tagged_h) == cirq.pauli_expansion(h)
599
625
  assert cirq.equal_up_to_global_phase(h, tagged_h)
600
626
  assert np.isclose(cirq.kraus(h), cirq.kraus(tagged_h)).all()
@@ -787,6 +813,10 @@ def test_single_qubit_gate_validates_on_each():
787
813
  test_non_qubits = [str(i) for i in range(3)]
788
814
  with pytest.raises(ValueError):
789
815
  _ = g.on_each(*test_non_qubits)
816
+
817
+ with cirq.with_debug(False):
818
+ assert g.on_each(*test_non_qubits)[0].qubits == ('0',)
819
+
790
820
  with pytest.raises(ValueError):
791
821
  _ = g.on_each(*test_non_qubits)
792
822
 
@@ -853,6 +883,10 @@ def test_on_each_two_qubits():
853
883
  g.on_each([(a,)])
854
884
  with pytest.raises(ValueError, match='Expected 2 qubits'):
855
885
  g.on_each([(a, b, a)])
886
+
887
+ with cirq.with_debug(False):
888
+ assert g.on_each([(a, b, a)])[0].qubits == (a, b, a)
889
+
856
890
  with pytest.raises(ValueError, match='Expected 2 qubits'):
857
891
  g.on_each(zip([a, a]))
858
892
  with pytest.raises(ValueError, match='Expected 2 qubits'):
@@ -176,8 +176,9 @@ class CCZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
176
176
  if self._exponent == 1:
177
177
  return 'cirq.CCZ'
178
178
  return f'(cirq.CCZ**{proper_repr(self._exponent)})'
179
- return 'cirq.CCZPowGate(exponent={}, global_shift={!r})'.format(
180
- proper_repr(self._exponent), self._global_shift
179
+ return (
180
+ f'cirq.CCZPowGate(exponent={proper_repr(self._exponent)}, '
181
+ f'global_shift={self._global_shift!r})'
181
182
  )
182
183
 
183
184
  def __str__(self) -> str:
@@ -190,7 +191,7 @@ class CCZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
190
191
 
191
192
  def controlled(
192
193
  self,
193
- num_controls: int = None,
194
+ num_controls: Optional[int] = None,
194
195
  control_values: Optional[
195
196
  Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
196
197
  ] = None,
@@ -383,9 +384,8 @@ class ThreeQubitDiagonalGate(raw_types.Gate):
383
384
  return protocols.obj_to_dict_helper(self, attribute_names=["diag_angles_radians"])
384
385
 
385
386
  def __repr__(self) -> str:
386
- return 'cirq.ThreeQubitDiagonalGate([{}])'.format(
387
- ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
388
- )
387
+ angles = ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
388
+ return f'cirq.ThreeQubitDiagonalGate([{angles}])'
389
389
 
390
390
  def _num_qubits_(self) -> int:
391
391
  return 3
@@ -488,8 +488,9 @@ class CCXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
488
488
  if self._exponent == 1:
489
489
  return 'cirq.TOFFOLI'
490
490
  return f'(cirq.TOFFOLI**{proper_repr(self._exponent)})'
491
- return 'cirq.CCXPowGate(exponent={}, global_shift={!r})'.format(
492
- proper_repr(self._exponent), self._global_shift
491
+ return (
492
+ f'cirq.CCXPowGate(exponent={proper_repr(self._exponent)}, '
493
+ f'global_shift={self._global_shift!r})'
493
494
  )
494
495
 
495
496
  def __str__(self) -> str:
@@ -502,7 +503,7 @@ class CCXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
502
503
 
503
504
  def controlled(
504
505
  self,
505
- num_controls: int = None,
506
+ num_controls: Optional[int] = None,
506
507
  control_values: Optional[
507
508
  Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
508
509
  ] = None,
@@ -661,6 +662,11 @@ class CSwapGate(gate_features.InterchangeableQubitsGate, raw_types.Gate):
661
662
  def _value_equality_values_(self):
662
663
  return ()
663
664
 
665
+ def __pow__(self, power):
666
+ if power == 1 or power == -1:
667
+ return self
668
+ return NotImplemented
669
+
664
670
  def __str__(self) -> str:
665
671
  return 'FREDKIN'
666
672
 
@@ -672,7 +678,7 @@ class CSwapGate(gate_features.InterchangeableQubitsGate, raw_types.Gate):
672
678
 
673
679
  def controlled(
674
680
  self,
675
- num_controls: int = None,
681
+ num_controls: Optional[int] = None,
676
682
  control_values: Optional[
677
683
  Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
678
684
  ] = None,
@@ -94,8 +94,9 @@ def test_unitary():
94
94
  )
95
95
 
96
96
  assert cirq.has_unitary(cirq.CSWAP)
97
+ u = cirq.unitary(cirq.CSWAP)
97
98
  np.testing.assert_allclose(
98
- cirq.unitary(cirq.CSWAP),
99
+ u,
99
100
  np.array(
100
101
  [
101
102
  [1, 0, 0, 0, 0, 0, 0, 0],
@@ -110,6 +111,7 @@ def test_unitary():
110
111
  ),
111
112
  atol=1e-8,
112
113
  )
114
+ np.testing.assert_allclose(u @ u, np.eye(8))
113
115
 
114
116
  diagonal_angles = [2, 3, 5, 7, 11, 13, 17, 19]
115
117
  assert cirq.has_unitary(cirq.ThreeQubitDiagonalGate(diagonal_angles))
@@ -156,7 +158,7 @@ def test_eq():
156
158
  eq.add_equality_group(cirq.TOFFOLI(a, b, c), cirq.CCX(a, b, c))
157
159
  eq.add_equality_group(cirq.TOFFOLI(a, c, b), cirq.TOFFOLI(c, a, b))
158
160
  eq.add_equality_group(cirq.TOFFOLI(a, b, d))
159
- eq.add_equality_group(cirq.CSWAP(a, b, c), cirq.FREDKIN(a, b, c))
161
+ eq.add_equality_group(cirq.CSWAP(a, b, c), cirq.FREDKIN(a, b, c), cirq.FREDKIN(a, b, c) ** -1)
160
162
  eq.add_equality_group(cirq.CSWAP(b, a, c), cirq.CSWAP(b, c, a))
161
163
 
162
164
 
@@ -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
  """Creates the gate instance for a two qubit diagonal gate.
15
16
 
16
17
  The gate is used to create a 4x4 matrix with the diagonal elements
@@ -134,9 +135,8 @@ class TwoQubitDiagonalGate(raw_types.Gate):
134
135
  return tuple(self._diag_angles_radians)
135
136
 
136
137
  def __repr__(self) -> str:
137
- return 'cirq.TwoQubitDiagonalGate([{}])'.format(
138
- ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
139
- )
138
+ angles = ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
139
+ return f'cirq.TwoQubitDiagonalGate([{angles}])'
140
140
 
141
141
  def _json_dict_(self) -> Dict[str, Any]:
142
142
  return protocols.obj_to_dict_helper(self, attribute_names=["diag_angles_radians"])
cirq/ops/wait_gate.py CHANGED
@@ -34,7 +34,7 @@ class WaitGate(raw_types.Gate):
34
34
  self,
35
35
  duration: 'cirq.DURATION_LIKE',
36
36
  num_qubits: Optional[int] = None,
37
- qid_shape: Tuple[int, ...] = None,
37
+ qid_shape: Optional[Tuple[int, ...]] = None,
38
38
  ) -> None:
39
39
  """Initialize a wait gate with the given duration.
40
40
 
@@ -50,6 +50,7 @@ from cirq.protocols.decompose_protocol import (
50
50
  decompose,
51
51
  decompose_once,
52
52
  decompose_once_with_qubits,
53
+ DecompositionContext,
53
54
  SupportsDecompose,
54
55
  SupportsDecomposeWithQubits,
55
56
  )