cirq-core 1.3.0.dev20231201141002__py3-none-any.whl → 1.4.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 (157) hide show
  1. cirq/__init__.py +4 -0
  2. cirq/_compat.py +9 -11
  3. cirq/_compat_test.py +45 -56
  4. cirq/_version.py +31 -1
  5. cirq/_version_test.py +1 -1
  6. cirq/circuits/circuit.py +13 -8
  7. cirq/circuits/circuit_operation.py +2 -1
  8. cirq/circuits/circuit_test.py +2 -2
  9. cirq/circuits/frozen_circuit.py +3 -2
  10. cirq/circuits/moment.py +12 -10
  11. cirq/circuits/qasm_output.py +5 -1
  12. cirq/circuits/qasm_output_test.py +25 -10
  13. cirq/contrib/qcircuit/qcircuit_diagram_info.py +9 -7
  14. cirq/contrib/quimb/mps_simulator_test.py +1 -1
  15. cirq/contrib/quimb/state_vector.py +9 -2
  16. cirq/contrib/svg/svg.py +2 -1
  17. cirq/contrib/svg/svg_test.py +1 -0
  18. cirq/devices/grid_qubit.py +85 -32
  19. cirq/devices/grid_qubit_test.py +22 -4
  20. cirq/devices/line_qubit.py +74 -26
  21. cirq/devices/line_qubit_test.py +19 -0
  22. cirq/devices/noise_utils.py +33 -31
  23. cirq/devices/noise_utils_test.py +1 -84
  24. cirq/devices/superconducting_qubits_noise_properties.py +7 -6
  25. cirq/experiments/__init__.py +8 -0
  26. cirq/experiments/qubit_characterizations.py +288 -44
  27. cirq/experiments/qubit_characterizations_test.py +61 -7
  28. cirq/experiments/random_quantum_circuit_generation.py +1 -1
  29. cirq/experiments/single_qubit_readout_calibration.py +132 -6
  30. cirq/experiments/single_qubit_readout_calibration_test.py +3 -1
  31. cirq/experiments/t1_decay_experiment.py +14 -7
  32. cirq/experiments/t1_decay_experiment_test.py +14 -26
  33. cirq/experiments/two_qubit_xeb.py +483 -0
  34. cirq/experiments/two_qubit_xeb_test.py +304 -0
  35. cirq/json_resolver_cache.py +2 -0
  36. cirq/linalg/decompositions.py +11 -13
  37. cirq/linalg/decompositions_test.py +1 -3
  38. cirq/linalg/diagonalize.py +5 -4
  39. cirq/linalg/predicates.py +8 -6
  40. cirq/linalg/transformations.py +2 -1
  41. cirq/linalg/transformations_test.py +1 -1
  42. cirq/ops/__init__.py +2 -0
  43. cirq/ops/clifford_gate.py +59 -16
  44. cirq/ops/common_gates_test.py +1 -2
  45. cirq/ops/control_values.py +4 -3
  46. cirq/ops/controlled_gate_test.py +1 -3
  47. cirq/ops/gate_operation.py +10 -1
  48. cirq/ops/named_qubit.py +74 -28
  49. cirq/ops/named_qubit_test.py +19 -0
  50. cirq/ops/parity_gates.py +5 -0
  51. cirq/ops/parity_gates_test.py +2 -10
  52. cirq/ops/pauli_gates.py +5 -2
  53. cirq/ops/pauli_string.py +2 -2
  54. cirq/ops/permutation_gate.py +16 -18
  55. cirq/ops/phased_iswap_gate_test.py +1 -3
  56. cirq/ops/phased_x_gate.py +1 -1
  57. cirq/ops/phased_x_z_gate.py +17 -1
  58. cirq/ops/phased_x_z_gate_test.py +24 -0
  59. cirq/ops/qid_util.py +4 -8
  60. cirq/ops/qubit_manager.py +7 -4
  61. cirq/ops/qubit_manager_test.py +20 -0
  62. cirq/ops/raw_types.py +5 -2
  63. cirq/ops/raw_types_test.py +14 -15
  64. cirq/ops/uniform_superposition_gate.py +123 -0
  65. cirq/ops/uniform_superposition_gate_test.py +94 -0
  66. cirq/protocols/approximate_equality_protocol_test.py +2 -2
  67. cirq/protocols/circuit_diagram_info_protocol.py +6 -4
  68. cirq/protocols/commutes_protocol.py +2 -4
  69. cirq/protocols/decompose_protocol.py +7 -12
  70. cirq/protocols/decompose_protocol_test.py +7 -3
  71. cirq/protocols/has_stabilizer_effect_protocol.py +1 -5
  72. cirq/protocols/has_stabilizer_effect_protocol_test.py +13 -4
  73. cirq/protocols/json_serialization.py +51 -181
  74. cirq/protocols/json_serialization_test.py +13 -47
  75. cirq/protocols/json_test_data/CircuitOperation.json +131 -148
  76. cirq/protocols/json_test_data/CircuitOperation.json_inward +55 -0
  77. cirq/protocols/json_test_data/CircuitOperation.repr_inward +6 -0
  78. cirq/protocols/json_test_data/FrozenCircuit.json +196 -210
  79. cirq/protocols/json_test_data/FrozenCircuit.json_inward +35 -0
  80. cirq/protocols/json_test_data/FrozenCircuit.repr_inward +4 -0
  81. cirq/protocols/json_test_data/UniformSuperpositionGate.json +5 -0
  82. cirq/protocols/json_test_data/UniformSuperpositionGate.repr +1 -0
  83. cirq/protocols/json_test_data/cirq.MSGate.json +4 -0
  84. cirq/protocols/json_test_data/cirq.MSGate.repr +1 -0
  85. cirq/protocols/json_test_data/spec.py +2 -0
  86. cirq/protocols/pow_protocol_test.py +1 -3
  87. cirq/protocols/resolve_parameters.py +4 -2
  88. cirq/qis/__init__.py +10 -0
  89. cirq/qis/clifford_tableau.py +8 -2
  90. cirq/qis/noise_utils.py +123 -0
  91. cirq/qis/noise_utils_test.py +97 -0
  92. cirq/sim/classical_simulator.py +227 -87
  93. cirq/sim/classical_simulator_test.py +135 -0
  94. cirq/sim/clifford/clifford_simulator_test.py +4 -2
  95. cirq/sim/mux.py +5 -3
  96. cirq/sim/simulation_product_state.py +15 -10
  97. cirq/sim/simulation_state.py +1 -1
  98. cirq/sim/simulation_state_test.py +2 -2
  99. cirq/sim/simulator_base.py +3 -3
  100. cirq/sim/state_vector_simulation_state.py +4 -4
  101. cirq/sim/state_vector_simulator.py +17 -2
  102. cirq/study/__init__.py +1 -0
  103. cirq/study/result.py +14 -0
  104. cirq/study/result_test.py +6 -0
  105. cirq/study/sweeps.py +4 -2
  106. cirq/study/sweeps_test.py +8 -0
  107. cirq/testing/__init__.py +6 -1
  108. cirq/testing/_compat_test_data/__init__.py +3 -3
  109. cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
  110. cirq/testing/circuit_compare.py +1 -1
  111. cirq/testing/consistent_qasm.py +6 -0
  112. cirq/testing/gate_features.py +10 -0
  113. cirq/testing/lin_alg_utils.py +5 -3
  114. cirq/transformers/__init__.py +15 -0
  115. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +3 -1
  116. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +24 -0
  117. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +17 -0
  118. cirq/transformers/dynamical_decoupling.py +122 -0
  119. cirq/transformers/dynamical_decoupling_test.py +123 -0
  120. cirq/transformers/gauge_compiling/__init__.py +26 -0
  121. cirq/transformers/gauge_compiling/cz_gauge.py +46 -0
  122. cirq/transformers/gauge_compiling/cz_gauge_test.py +23 -0
  123. cirq/transformers/gauge_compiling/gauge_compiling.py +214 -0
  124. cirq/transformers/gauge_compiling/gauge_compiling_test.py +41 -0
  125. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +83 -0
  126. cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +52 -0
  127. cirq/transformers/gauge_compiling/iswap_gauge.py +105 -0
  128. cirq/transformers/gauge_compiling/iswap_gauge_test.py +23 -0
  129. cirq/transformers/gauge_compiling/spin_inversion_gauge.py +33 -0
  130. cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +37 -0
  131. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +64 -0
  132. cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +27 -0
  133. cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +94 -0
  134. cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +22 -0
  135. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -0
  136. cirq/transformers/merge_k_qubit_gates_test.py +23 -23
  137. cirq/transformers/merge_single_qubit_gates_test.py +14 -14
  138. cirq/transformers/optimize_for_target_gateset.py +39 -17
  139. cirq/transformers/optimize_for_target_gateset_test.py +189 -39
  140. cirq/transformers/qubit_management_transformers.py +1 -1
  141. cirq/transformers/routing/visualize_routed_circuit_test.py +17 -17
  142. cirq/transformers/stratify_test.py +13 -13
  143. cirq/transformers/target_gatesets/compilation_target_gateset.py +26 -2
  144. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +16 -16
  145. cirq/transformers/target_gatesets/cz_gateset.py +4 -0
  146. cirq/transformers/transformer_api.py +1 -2
  147. cirq/transformers/transformer_primitives.py +15 -14
  148. cirq/transformers/transformer_primitives_test.py +99 -72
  149. cirq/value/classical_data.py +6 -6
  150. cirq/value/value_equality_attr.py +4 -0
  151. cirq/work/sampler.py +3 -4
  152. cirq/work/sampler_test.py +25 -0
  153. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
  154. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
  155. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
  156. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
  157. {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
@@ -490,17 +490,17 @@ def test_cannot_remap_non_measurement_gate():
490
490
 
491
491
  def test_circuit_diagram():
492
492
  class TaggyTag:
493
- """Tag with a custom repr function to test circuit diagrams."""
493
+ """Tag with a custom str function to test circuit diagrams."""
494
494
 
495
- def __repr__(self):
496
- return 'TaggyTag()'
495
+ def __str__(self):
496
+ return '<taggy>'
497
497
 
498
498
  h = cirq.H(cirq.GridQubit(1, 1))
499
499
  tagged_h = h.with_tags('tag1')
500
500
  non_string_tag_h = h.with_tags(TaggyTag())
501
501
 
502
502
  expected = cirq.CircuitDiagramInfo(
503
- wire_symbols=("H['tag1']",),
503
+ wire_symbols=("H[tag1]",),
504
504
  exponent=1.0,
505
505
  connected=True,
506
506
  exponent_qubit_index=None,
@@ -511,14 +511,14 @@ def test_circuit_diagram():
511
511
  assert cirq.circuit_diagram_info(tagged_h, args) == cirq.circuit_diagram_info(h)
512
512
 
513
513
  c = cirq.Circuit(tagged_h)
514
- diagram_with_tags = "(1, 1): ───H['tag1']───"
514
+ diagram_with_tags = "(1, 1): ───H[tag1]───"
515
515
  diagram_without_tags = "(1, 1): ───H───"
516
516
  assert str(cirq.Circuit(tagged_h)) == diagram_with_tags
517
517
  assert c.to_text_diagram() == diagram_with_tags
518
518
  assert c.to_text_diagram(include_tags=False) == diagram_without_tags
519
519
 
520
520
  c = cirq.Circuit(non_string_tag_h)
521
- diagram_with_non_string_tag = "(1, 1): ───H[TaggyTag()]───"
521
+ diagram_with_non_string_tag = "(1, 1): ───H[<taggy>]───"
522
522
  assert c.to_text_diagram() == diagram_with_non_string_tag
523
523
  assert c.to_text_diagram(include_tags=False) == diagram_without_tags
524
524
 
@@ -531,7 +531,7 @@ def test_circuit_diagram_tagged_global_phase():
531
531
  # Just global phase in a circuit
532
532
  assert cirq.circuit_diagram_info(global_phase, default='default') == 'default'
533
533
  cirq.testing.assert_has_diagram(
534
- cirq.Circuit(global_phase), "\n\nglobal phase: π['tag0']", use_unicode_characters=True
534
+ cirq.Circuit(global_phase), "\n\nglobal phase: π[tag0]", use_unicode_characters=True
535
535
  )
536
536
  cirq.testing.assert_has_diagram(
537
537
  cirq.Circuit(global_phase),
@@ -558,9 +558,7 @@ def test_circuit_diagram_tagged_global_phase():
558
558
  no_wire_symbol_op = NoWireSymbols(coefficient=-1.0)().with_tags('tag0')
559
559
  assert cirq.circuit_diagram_info(no_wire_symbol_op, default='default') == expected
560
560
  cirq.testing.assert_has_diagram(
561
- cirq.Circuit(no_wire_symbol_op),
562
- "\n\nglobal phase: π['tag0']",
563
- use_unicode_characters=True,
561
+ cirq.Circuit(no_wire_symbol_op), "\n\nglobal phase: π[tag0]", use_unicode_characters=True
564
562
  )
565
563
 
566
564
  # Two global phases in one moment
@@ -570,9 +568,9 @@ def test_circuit_diagram_tagged_global_phase():
570
568
  cirq.testing.assert_has_diagram(
571
569
  c,
572
570
  """\
573
- a: ─────────────X───────────────────
571
+ a: ─────────────X───────────────
574
572
 
575
- global phase: π['tag1', 'tag2']""",
573
+ global phase: π[tag1, tag2]""",
576
574
  use_unicode_characters=True,
577
575
  precision=2,
578
576
  )
@@ -583,9 +581,9 @@ global phase: π['tag1', 'tag2']""",
583
581
  cirq.testing.assert_has_diagram(
584
582
  c,
585
583
  """\
586
- a: ─────────────X['x_tag']─────X──────────────
584
+ a: ─────────────X[x_tag]─────X────────────
587
585
 
588
- global phase: 0.5π['tag1'] 0.5π['tag2']
586
+ global phase: 0.5π[tag1] 0.5π[tag2]
589
587
  """,
590
588
  use_unicode_characters=True,
591
589
  include_tags=True,
@@ -603,7 +601,7 @@ def test_circuit_diagram_no_circuit_diagram():
603
601
  q = cirq.GridQubit(1, 1)
604
602
  expected = "(1, 1): ───guess-i-will-repr───"
605
603
  assert cirq.Circuit(NoCircuitDiagram()(q)).to_text_diagram() == expected
606
- expected = "(1, 1): ───guess-i-will-repr['taggy']───"
604
+ expected = "(1, 1): ───guess-i-will-repr[taggy]───"
607
605
  assert cirq.Circuit(NoCircuitDiagram()(q).with_tags('taggy')).to_text_diagram() == expected
608
606
 
609
607
 
@@ -761,6 +759,7 @@ def test_inverse_composite_standards():
761
759
  assert cirq.parameter_names(g) == {'a'}
762
760
  assert cirq.resolve_parameters(g, {a: 0}) == Gate(0) ** -1
763
761
  cirq.testing.assert_implements_consistent_protocols(g, global_vals={'C': Gate, 'a': a})
762
+ assert str(g) == 'C(a)†'
764
763
 
765
764
 
766
765
  def test_tagged_act_on():
@@ -0,0 +1,123 @@
1
+ # Copyright 2024 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
+ from typing import Sequence, Any, Dict, TYPE_CHECKING
16
+
17
+ import numpy as np
18
+ from cirq.ops.common_gates import H, ry
19
+ from cirq.ops.pauli_gates import X
20
+ from cirq.ops import raw_types
21
+
22
+
23
+ if TYPE_CHECKING:
24
+ import cirq
25
+
26
+
27
+ class UniformSuperpositionGate(raw_types.Gate):
28
+ r"""Creates a uniform superposition state on the states $[0, M)$
29
+ The gate creates the state $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$
30
+ (where $1\leq M \leq 2^n$), using n qubits, according to the Shukla-Vedula algorithm [SV24].
31
+ References:
32
+ [SV24]
33
+ [An efficient quantum algorithm for preparation of uniform quantum superposition
34
+ states](https://arxiv.org/abs/2306.11747)
35
+ """
36
+
37
+ def __init__(self, m_value: int, num_qubits: int) -> None:
38
+ """Initializes UniformSuperpositionGate.
39
+
40
+ Args:
41
+ m_value: The number of computational basis states.
42
+ num_qubits: The number of qubits used.
43
+
44
+ Raises:
45
+ ValueError: If `m_value` is not a positive integer, or
46
+ if `num_qubits` is not an integer greater than or equal to log2(m_value).
47
+ """
48
+ if not (isinstance(m_value, int) and (m_value > 0)):
49
+ raise ValueError("m_value must be a positive integer.")
50
+ log_two_m_value = m_value.bit_length()
51
+
52
+ if (m_value & (m_value - 1)) == 0:
53
+ log_two_m_value = log_two_m_value - 1
54
+ if not (isinstance(num_qubits, int) and (num_qubits >= log_two_m_value)):
55
+ raise ValueError(
56
+ "num_qubits must be an integer greater than or equal to log2(m_value)."
57
+ )
58
+ self._m_value = m_value
59
+ self._num_qubits = num_qubits
60
+
61
+ def _decompose_(self, qubits: Sequence["cirq.Qid"]) -> "cirq.OP_TREE":
62
+ """Decomposes the gate into a sequence of standard gates.
63
+ Implements the construction from https://arxiv.org/pdf/2306.11747.
64
+ """
65
+ qreg = list(qubits)
66
+ qreg.reverse()
67
+
68
+ if self._m_value == 1: # if m_value is 1, do nothing
69
+ return
70
+ if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2
71
+ m = self._m_value.bit_length() - 1
72
+ yield H.on_each(qreg[:m])
73
+ return
74
+ k = self._m_value.bit_length()
75
+ l_value = []
76
+ for i in range(self._m_value.bit_length()):
77
+ if (self._m_value >> i) & 1:
78
+ l_value.append(i) # Locations of '1's
79
+
80
+ yield X.on_each(qreg[q_bit] for q_bit in l_value[1:k])
81
+ m_current = 2 ** (l_value[0])
82
+ theta = -2 * np.arccos(np.sqrt(m_current / self._m_value))
83
+ if l_value[0] > 0: # if m_value is even
84
+ yield H.on_each(qreg[: l_value[0]])
85
+
86
+ yield ry(theta).on(qreg[l_value[1]])
87
+
88
+ for i in range(l_value[0], l_value[1]):
89
+ yield H(qreg[i]).controlled_by(qreg[l_value[1]], control_values=[False])
90
+
91
+ for m in range(1, len(l_value) - 1):
92
+ theta = -2 * np.arccos(np.sqrt(2 ** l_value[m] / (self._m_value - m_current)))
93
+ yield ry(theta).on(qreg[l_value[m + 1]]).controlled_by(
94
+ qreg[l_value[m]], control_values=[0]
95
+ )
96
+ for i in range(l_value[m], l_value[m + 1]):
97
+ yield H.on(qreg[i]).controlled_by(qreg[l_value[m + 1]], control_values=[0])
98
+
99
+ m_current = m_current + 2 ** (l_value[m])
100
+
101
+ def num_qubits(self) -> int:
102
+ return self._num_qubits
103
+
104
+ @property
105
+ def m_value(self) -> int:
106
+ return self._m_value
107
+
108
+ def __eq__(self, other):
109
+ if isinstance(other, UniformSuperpositionGate):
110
+ return (self._m_value == other._m_value) and (self._num_qubits == other._num_qubits)
111
+ return False
112
+
113
+ def __repr__(self) -> str:
114
+ return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})'
115
+
116
+ def _json_dict_(self) -> Dict[str, Any]:
117
+ d = {}
118
+ d['m_value'] = self._m_value
119
+ d['num_qubits'] = self._num_qubits
120
+ return d
121
+
122
+ def __str__(self) -> str:
123
+ return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})'
@@ -0,0 +1,94 @@
1
+ # Copyright 2024 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 numpy as np
16
+ import pytest
17
+ import cirq
18
+
19
+
20
+ @pytest.mark.parametrize(
21
+ ["m", "n"],
22
+ [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)]
23
+ + [(1, 2), (4, 2), (6, 3), (7, 3)],
24
+ )
25
+ def test_generated_unitary_is_uniform(m: int, n: int) -> None:
26
+ r"""The code checks that the unitary matrix corresponds to the generated uniform superposition
27
+ states (see uniform_superposition_gate.py). It is enough to check that the
28
+ first colum of the unitary matrix (which corresponds to the action of the gate on
29
+ $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$
30
+ entries are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the
31
+ remaining $2^n-M$ entries are all "0"s.
32
+ """
33
+ gate = cirq.UniformSuperpositionGate(m, n)
34
+ matrix = np.array(cirq.unitary(gate))
35
+ np.testing.assert_allclose(
36
+ matrix[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8
37
+ )
38
+
39
+
40
+ @pytest.mark.parametrize(["m", "n"], [(1, 1), (-2, 1), (-3.1, 2), (6, -4), (5, 6.1)])
41
+ def test_incompatible_m_value_and_qubit_args(m: int, n: int) -> None:
42
+ r"""The code checks that test errors are raised if the arguments m (number of
43
+ superposition states and n (number of qubits) are positive integers and are compatible
44
+ (i.e., n >= log2(m)).
45
+ """
46
+
47
+ if not (isinstance(m, int)):
48
+ with pytest.raises(ValueError, match="m_value must be a positive integer."):
49
+ cirq.UniformSuperpositionGate(m, n)
50
+ elif not (isinstance(n, int)):
51
+ with pytest.raises(
52
+ ValueError,
53
+ match="num_qubits must be an integer greater than or equal to log2\\(m_value\\).",
54
+ ):
55
+ cirq.UniformSuperpositionGate(m, n)
56
+ elif m < 1:
57
+ with pytest.raises(ValueError, match="m_value must be a positive integer."):
58
+ cirq.UniformSuperpositionGate(int(m), int(n))
59
+ elif n < np.log2(m):
60
+ with pytest.raises(
61
+ ValueError,
62
+ match="num_qubits must be an integer greater than or equal to log2\\(m_value\\).",
63
+ ):
64
+ cirq.UniformSuperpositionGate(m, n)
65
+
66
+
67
+ def test_repr():
68
+ assert (
69
+ repr(cirq.UniformSuperpositionGate(7, 3))
70
+ == 'UniformSuperpositionGate(m_value=7, num_qubits=3)'
71
+ )
72
+
73
+
74
+ def test_uniform_superposition_gate_json_dict():
75
+ assert cirq.UniformSuperpositionGate(7, 3)._json_dict_() == {'m_value': 7, 'num_qubits': 3}
76
+
77
+
78
+ def test_str():
79
+ assert (
80
+ str(cirq.UniformSuperpositionGate(7, 3))
81
+ == 'UniformSuperpositionGate(m_value=7, num_qubits=3)'
82
+ )
83
+
84
+
85
+ @pytest.mark.parametrize(["m", "n"], [(5, 3), (10, 4)])
86
+ def test_eq(m: int, n: int) -> None:
87
+ a = cirq.UniformSuperpositionGate(m, n)
88
+ b = cirq.UniformSuperpositionGate(m, n)
89
+ c = cirq.UniformSuperpositionGate(m + 1, n)
90
+ d = cirq.X
91
+ assert a.m_value == b.m_value
92
+ assert a.__eq__(b)
93
+ assert not (a.__eq__(c))
94
+ assert not (a.__eq__(d))
@@ -47,11 +47,11 @@ def test_approx_eq_mixed_primitives():
47
47
 
48
48
  def test_numpy_dtype_compatibility():
49
49
  i_a, i_b, i_c = 0, 1, 2
50
- i_types = [np.intc, np.intp, np.int0, np.int8, np.int16, np.int32, np.int64]
50
+ i_types = [np.intc, np.intp, np.int8, np.int16, np.int32, np.int64]
51
51
  for i_type in i_types:
52
52
  assert cirq.approx_eq(i_type(i_a), i_type(i_b), atol=1)
53
53
  assert not cirq.approx_eq(i_type(i_a), i_type(i_c), atol=1)
54
- u_types = [np.uint, np.uint0, np.uint8, np.uint16, np.uint32, np.uint64]
54
+ u_types = [np.uint, np.uintp, np.uint8, np.uint16, np.uint32, np.uint64]
55
55
  for u_type in u_types:
56
56
  assert cirq.approx_eq(u_type(i_a), u_type(i_b), atol=1)
57
57
  assert not cirq.approx_eq(u_type(i_a), u_type(i_c), atol=1)
@@ -221,9 +221,11 @@ class CircuitDiagramInfoArgs:
221
221
  self.known_qubit_count,
222
222
  self.use_unicode_characters,
223
223
  self.precision,
224
- None
225
- if self.label_map is None
226
- else tuple(sorted(self.label_map.items(), key=lambda e: e[0])),
224
+ (
225
+ None
226
+ if self.label_map is None
227
+ else tuple(sorted(self.label_map.items(), key=lambda e: e[0]))
228
+ ),
227
229
  self.include_tags,
228
230
  self.transpose,
229
231
  )
@@ -354,7 +356,7 @@ def _op_info_with_fallback(
354
356
 
355
357
  # Add tags onto the representation, if they exist
356
358
  if op.tags:
357
- name += f'{list(op.tags)}'
359
+ name += f"[{', '.join(map(str, op.tags))}]"
358
360
 
359
361
  # Include ordering in the qubit labels.
360
362
  symbols = (name,) + tuple(f'#{i + 1}' for i in range(1, len(op.qubits)))
@@ -74,15 +74,13 @@ class SupportsCommutes(Protocol):
74
74
 
75
75
 
76
76
  @overload
77
- def commutes(v1: Any, v2: Any, *, atol: Union[int, float] = 1e-8) -> bool:
78
- ...
77
+ def commutes(v1: Any, v2: Any, *, atol: Union[int, float] = 1e-8) -> bool: ...
79
78
 
80
79
 
81
80
  @overload
82
81
  def commutes(
83
82
  v1: Any, v2: Any, *, atol: Union[int, float] = 1e-8, default: TDefault
84
- ) -> Union[bool, TDefault]:
85
- ...
83
+ ) -> Union[bool, TDefault]: ...
86
84
 
87
85
 
88
86
  def commutes(
@@ -57,8 +57,7 @@ _CONTEXT_COUNTER = itertools.count() # Use _reset_context_counter() to reset th
57
57
  class OpDecomposerWithContext(Protocol):
58
58
  def __call__(
59
59
  self, __op: 'cirq.Operation', *, context: Optional['cirq.DecompositionContext'] = None
60
- ) -> DecomposeResult:
61
- ...
60
+ ) -> DecomposeResult: ...
62
61
 
63
62
 
64
63
  OpDecomposer = Union[Callable[['cirq.Operation'], DecomposeResult], OpDecomposerWithContext]
@@ -93,16 +92,12 @@ class SupportsDecompose(Protocol):
93
92
  """An object that can be decomposed into simpler operations.
94
93
 
95
94
  All decomposition methods should ultimately terminate on basic 1-qubit and
96
- 2-qubit gates included by default in Cirq. Cirq does not make any guarantees
97
- about what the final gate set is. Currently, decompositions within Cirq
98
- happen to converge towards the X, Y, Z, CZ, PhasedX, specified-matrix gates,
99
- and others. This set will vary from release to release. Because of this
100
- variability, it is important for consumers of decomposition to look for
101
- generic properties of gates, such as "two qubit gate with a unitary matrix",
102
- instead of specific gate types such as CZ gates (though a consumer is
103
- of course free to handle CZ gates in a special way, and consumers can
104
- give an `intercepting_decomposer` to `cirq.decompose` that attempts to
105
- target a specific gate set).
95
+ 2-qubit gates included by default in Cirq. If a custom decomposition is not
96
+ specified, Cirq will decompose all operations to XPow/YPow/ZPow/CZPow/Measurement
97
+ + Global phase gateset. However, the default decomposition in Cirq should be a last resort
98
+ fallback and it is recommended for consumers of decomposition to either not depend
99
+ upon a specific target gateset, or give an `intercepting_decomposer` to `cirq.decompose`
100
+ that attempts to target a specific gate set.
106
101
 
107
102
  For example, `cirq.TOFFOLI` has a `_decompose_` method that returns a pair
108
103
  of Hadamard gates surrounding a `cirq.CCZ`. Although `cirq.CCZ` is not a
@@ -346,9 +346,13 @@ class RecursiveDecompose(cirq.Gate):
346
346
 
347
347
  def _decompose_impl(self, qubits, mock_qm: mock.Mock):
348
348
  mock_qm.qalloc(self.recurse)
349
- yield RecursiveDecompose(
350
- recurse=False, mock_qm=self.mock_qm, with_context=self.with_context
351
- ).on(*qubits) if self.recurse else cirq.Z.on_each(*qubits)
349
+ yield (
350
+ RecursiveDecompose(
351
+ recurse=False, mock_qm=self.mock_qm, with_context=self.with_context
352
+ ).on(*qubits)
353
+ if self.recurse
354
+ else cirq.Z.on_each(*qubits)
355
+ )
352
356
  mock_qm.qfree(self.recurse)
353
357
 
354
358
  def _decompose_(self, qubits):
@@ -102,11 +102,7 @@ def _strat_has_stabilizer_effect_from_unitary(val: Any) -> Optional[bool]:
102
102
 
103
103
 
104
104
  def _strat_has_stabilizer_effect_from_decompose(val: Any) -> Optional[bool]:
105
- qid_shape = qid_shape_protocol.qid_shape(val, default=None)
106
- if qid_shape is None or len(qid_shape) <= 3:
107
- return None
108
-
109
- decomposition = decompose_protocol.decompose_once(val, default=None)
105
+ decomposition, _, _ = decompose_protocol._try_decompose_into_operations_and_qubits(val)
110
106
  if decomposition is None:
111
107
  return None
112
108
  for op in decomposition:
@@ -41,15 +41,15 @@ class Yes:
41
41
  return True
42
42
 
43
43
 
44
- q = cirq.LineQubit(0)
45
-
46
-
47
44
  class EmptyOp(cirq.Operation):
48
45
  """A trivial operation."""
49
46
 
47
+ def __init__(self, q: cirq.Qid = cirq.LineQubit(0)):
48
+ self.q = q
49
+
50
50
  @property
51
51
  def qubits(self):
52
- return (q,)
52
+ return (self.q,)
53
53
 
54
54
  def with_qubits(self, *new_qubits): # pragma: no cover
55
55
  return self
@@ -97,6 +97,14 @@ class OpWithUnitary(EmptyOp):
97
97
  return cirq.LineQubit.range(self.unitary.shape[0].bit_length() - 1)
98
98
 
99
99
 
100
+ class GateDecomposes(cirq.Gate):
101
+ def _num_qubits_(self):
102
+ return 1
103
+
104
+ def _decompose_(self, qubits):
105
+ yield YesOp(*qubits)
106
+
107
+
100
108
  def test_inconclusive():
101
109
  assert not cirq.has_stabilizer_effect(object())
102
110
  assert not cirq.has_stabilizer_effect('boo')
@@ -146,3 +154,4 @@ def test_via_decompose():
146
154
  assert not cirq.has_stabilizer_effect(
147
155
  OpWithUnitary(cirq.unitary(cirq.Circuit(cirq.T.on_each(cirq.LineQubit.range(4)))))
148
156
  )
157
+ assert cirq.has_stabilizer_effect(GateDecomposes())