cirq-core 1.3.0.dev20231201164435__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.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
  154. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
  155. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
  156. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
  157. {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,304 @@
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
+ """Wraps Parallel Two Qubit XEB into a few convenience methods."""
15
+ from typing import Optional, Sequence, Dict
16
+ import itertools
17
+ import io
18
+
19
+ import matplotlib.pyplot as plt
20
+
21
+ import numpy as np
22
+ import networkx as nx
23
+ import pandas as pd
24
+ import pytest
25
+
26
+ import cirq
27
+ from cirq.experiments.qubit_characterizations import ParallelRandomizedBenchmarkingResult
28
+
29
+
30
+ def _manhattan_distance(qubit1: 'cirq.GridQubit', qubit2: 'cirq.GridQubit') -> int:
31
+ return abs(qubit1.row - qubit2.row) + abs(qubit1.col - qubit2.col)
32
+
33
+
34
+ class MockDevice(cirq.Device):
35
+ @property
36
+ def metadata(self):
37
+ qubits = cirq.GridQubit.rect(3, 2, 4, 3)
38
+ graph = nx.Graph(
39
+ pair for pair in itertools.combinations(qubits, 2) if _manhattan_distance(*pair) == 1
40
+ )
41
+ return cirq.DeviceMetadata(qubits, graph)
42
+
43
+
44
+ class MockProcessor:
45
+ def get_device(self):
46
+ return MockDevice()
47
+
48
+
49
+ class DensityMatrixSimulatorWithProcessor(cirq.DensityMatrixSimulator):
50
+ @property
51
+ def processor(self):
52
+ return MockProcessor()
53
+
54
+
55
+ def test_parallel_two_qubit_xeb_simulator_without_processor_fails():
56
+ sampler = (
57
+ cirq.DensityMatrixSimulator(
58
+ seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
59
+ ),
60
+ )
61
+
62
+ with pytest.raises(ValueError):
63
+ _ = cirq.experiments.parallel_two_qubit_xeb(
64
+ sampler=sampler,
65
+ n_repetitions=1,
66
+ n_combinations=1,
67
+ n_circuits=1,
68
+ cycle_depths=[3, 4, 5],
69
+ random_state=0,
70
+ )
71
+
72
+
73
+ @pytest.mark.parametrize(
74
+ 'sampler,qubits',
75
+ [
76
+ (
77
+ cirq.DensityMatrixSimulator(
78
+ seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
79
+ ),
80
+ cirq.GridQubit.rect(3, 2, 4, 3),
81
+ ),
82
+ (
83
+ DensityMatrixSimulatorWithProcessor(
84
+ seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
85
+ ),
86
+ None,
87
+ ),
88
+ ],
89
+ )
90
+ def test_parallel_two_qubit_xeb(sampler: cirq.Sampler, qubits: Optional[Sequence[cirq.GridQubit]]):
91
+ res = cirq.experiments.parallel_two_qubit_xeb(
92
+ sampler=sampler,
93
+ qubits=qubits,
94
+ n_repetitions=100,
95
+ n_combinations=1,
96
+ n_circuits=1,
97
+ cycle_depths=[3, 4, 5],
98
+ random_state=0,
99
+ )
100
+
101
+ got = [res.xeb_error(*reversed(pair)) for pair in res.all_qubit_pairs]
102
+ np.testing.assert_allclose(got, 0.1, atol=1e-1)
103
+
104
+
105
+ @pytest.mark.usefixtures('closefigures')
106
+ @pytest.mark.parametrize(
107
+ 'sampler,qubits',
108
+ [
109
+ (cirq.DensityMatrixSimulator(seed=0), cirq.GridQubit.rect(3, 2, 4, 3)),
110
+ (DensityMatrixSimulatorWithProcessor(seed=0), None),
111
+ ],
112
+ )
113
+ @pytest.mark.parametrize('ax', [None, plt.subplots(1, 1, figsize=(8, 8))[1]])
114
+ def test_plotting(sampler, qubits, ax):
115
+ res = cirq.experiments.parallel_two_qubit_xeb(
116
+ sampler=sampler,
117
+ qubits=qubits,
118
+ n_repetitions=1,
119
+ n_combinations=1,
120
+ n_circuits=1,
121
+ cycle_depths=[3, 4, 5],
122
+ random_state=0,
123
+ ax=ax,
124
+ )
125
+ res.plot_heatmap(ax=ax)
126
+ res.plot_fitted_exponential(cirq.GridQubit(4, 4), cirq.GridQubit(4, 3), ax=ax)
127
+ res.plot_histogram(ax=ax)
128
+
129
+
130
+ _TEST_RESULT = cirq.experiments.TwoQubitXEBResult(
131
+ pd.read_csv(
132
+ io.StringIO(
133
+ """layer_i,pair_i,pair,a,layer_fid,cycle_depths,fidelities,a_std,layer_fid_std
134
+ 0,0,"(cirq.GridQubit(4, 4), cirq.GridQubit(5, 4))",,0.9,[],[],,
135
+ 0,1,"(cirq.GridQubit(5, 3), cirq.GridQubit(6, 3))",,0.8,[],[],,
136
+ 1,0,"(cirq.GridQubit(4, 3), cirq.GridQubit(5, 3))",,0.3,[],[],,
137
+ 1,1,"(cirq.GridQubit(5, 4), cirq.GridQubit(6, 4))",,0.2,[],[],,
138
+ 2,0,"(cirq.GridQubit(4, 3), cirq.GridQubit(4, 4))",,0.1,[],[],,
139
+ 2,1,"(cirq.GridQubit(6, 3), cirq.GridQubit(6, 4))",,0.5,[],[],,
140
+ 3,0,"(cirq.GridQubit(5, 3), cirq.GridQubit(5, 4))",,0.4,[],[],"""
141
+ ),
142
+ index_col=[0, 1, 2],
143
+ converters={2: lambda s: eval(s)},
144
+ )
145
+ )
146
+
147
+
148
+ @pytest.mark.parametrize(
149
+ 'q0,q1,pauli',
150
+ [
151
+ (cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 1 / 8),
152
+ (cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 1 / 4),
153
+ (cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.8 + 3 / 40),
154
+ (cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 5 / 8),
155
+ ],
156
+ )
157
+ def test_pauli_error(q0: cirq.GridQubit, q1: cirq.GridQubit, pauli: float):
158
+ assert _TEST_RESULT.pauli_error()[(q0, q1)] == pytest.approx(pauli)
159
+
160
+
161
+ class MockParallelRandomizedBenchmarkingResult(ParallelRandomizedBenchmarkingResult):
162
+ def pauli_error(self) -> Dict[cirq.Qid, float]:
163
+ return {
164
+ cirq.GridQubit(4, 4): 0.01,
165
+ cirq.GridQubit(5, 4): 0.02,
166
+ cirq.GridQubit(5, 3): 0.03,
167
+ cirq.GridQubit(5, 6): 0.04,
168
+ cirq.GridQubit(4, 3): 0.05,
169
+ cirq.GridQubit(6, 3): 0.06,
170
+ cirq.GridQubit(6, 4): 0.07,
171
+ }
172
+
173
+
174
+ @pytest.mark.parametrize(
175
+ 'q0,q1,pauli',
176
+ [
177
+ (cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 1 / 8 - 0.03),
178
+ (cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 1 / 4 - 0.09),
179
+ (cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.8 + 3 / 40 - 0.08),
180
+ (cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 5 / 8 - 0.13),
181
+ ],
182
+ )
183
+ def test_inferred_pauli_error(q0: cirq.GridQubit, q1: cirq.GridQubit, pauli: float):
184
+ combined_results = cirq.experiments.InferredXEBResult(
185
+ rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
186
+ )
187
+
188
+ assert combined_results.inferred_pauli_error()[(q0, q1)] == pytest.approx(pauli)
189
+
190
+
191
+ @pytest.mark.parametrize(
192
+ 'q0,q1,xeb',
193
+ [
194
+ (cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 0.076),
195
+ (cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 0.128),
196
+ (cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.636),
197
+ (cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 0.396),
198
+ ],
199
+ )
200
+ def test_inferred_xeb_error(q0: cirq.GridQubit, q1: cirq.GridQubit, xeb: float):
201
+ combined_results = cirq.experiments.InferredXEBResult(
202
+ rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
203
+ )
204
+
205
+ assert combined_results.inferred_xeb_error()[(q0, q1)] == pytest.approx(xeb)
206
+
207
+
208
+ def test_inferred_single_qubit_pauli():
209
+ combined_results = cirq.experiments.InferredXEBResult(
210
+ rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
211
+ )
212
+
213
+ assert combined_results.single_qubit_pauli_error() == {
214
+ cirq.GridQubit(4, 4): 0.01,
215
+ cirq.GridQubit(5, 4): 0.02,
216
+ cirq.GridQubit(5, 3): 0.03,
217
+ cirq.GridQubit(5, 6): 0.04,
218
+ cirq.GridQubit(4, 3): 0.05,
219
+ cirq.GridQubit(6, 3): 0.06,
220
+ cirq.GridQubit(6, 4): 0.07,
221
+ }
222
+
223
+
224
+ @pytest.mark.parametrize(
225
+ 'q0,q1,pauli',
226
+ [
227
+ (cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 1 / 8),
228
+ (cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 1 / 4),
229
+ (cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.8 + 3 / 40),
230
+ (cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 5 / 8),
231
+ ],
232
+ )
233
+ def test_inferred_two_qubit_pauli(q0: cirq.GridQubit, q1: cirq.GridQubit, pauli: float):
234
+ combined_results = cirq.experiments.InferredXEBResult(
235
+ rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
236
+ )
237
+ assert combined_results.two_qubit_pauli_error()[(q0, q1)] == pytest.approx(pauli)
238
+
239
+
240
+ @pytest.mark.parametrize('ax', [None, plt.subplots(1, 1, figsize=(8, 8))[1]])
241
+ @pytest.mark.parametrize('target_error', ['pauli', 'xeb', 'decay_constant'])
242
+ @pytest.mark.parametrize('kind', ['single_qubit', 'two_qubit', 'both', ''])
243
+ def test_inferred_plots(ax, target_error, kind):
244
+ combined_results = cirq.experiments.InferredXEBResult(
245
+ rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
246
+ )
247
+
248
+ combined_results.plot_heatmap(target_error=target_error, ax=ax)
249
+
250
+ raise_error = False
251
+ if kind not in ('single_qubit', 'two_qubit', 'both'):
252
+ raise_error = True
253
+ if kind != 'two_qubit' and target_error != 'pauli':
254
+ raise_error = True
255
+
256
+ if raise_error:
257
+ with pytest.raises(ValueError):
258
+ combined_results.plot_histogram(target_error=target_error, kind=kind, ax=ax)
259
+ else:
260
+ combined_results.plot_histogram(target_error=target_error, kind=kind, ax=ax)
261
+
262
+
263
+ @pytest.mark.parametrize(
264
+ 'sampler,qubits',
265
+ [
266
+ (
267
+ cirq.DensityMatrixSimulator(
268
+ seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
269
+ ),
270
+ cirq.GridQubit.rect(3, 2, 4, 3),
271
+ ),
272
+ (
273
+ DensityMatrixSimulatorWithProcessor(
274
+ seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
275
+ ),
276
+ None,
277
+ ),
278
+ ],
279
+ )
280
+ def test_run_rb_and_xeb(sampler: cirq.Sampler, qubits: Optional[Sequence[cirq.GridQubit]]):
281
+ res = cirq.experiments.run_rb_and_xeb(
282
+ sampler=sampler,
283
+ qubits=qubits,
284
+ repetitions=100,
285
+ num_clifford_range=tuple(np.arange(3, 10, 1)),
286
+ xeb_combinations=1,
287
+ num_circuits=1,
288
+ depths_xeb=(3, 4, 5),
289
+ random_state=0,
290
+ )
291
+ np.testing.assert_allclose(
292
+ [res.xeb_result.xeb_error(*pair) for pair in res.all_qubit_pairs], 0.1, atol=1e-1
293
+ )
294
+
295
+
296
+ def test_run_rb_and_xeb_without_processor_fails():
297
+ sampler = (
298
+ cirq.DensityMatrixSimulator(
299
+ seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
300
+ ),
301
+ )
302
+
303
+ with pytest.raises(ValueError):
304
+ _ = cirq.experiments.run_rb_and_xeb(sampler=sampler)
@@ -157,6 +157,7 @@ def _class_resolver_dictionary() -> Dict[str, ObjectFactory]:
157
157
  'LineTopology': cirq.LineTopology,
158
158
  'Linspace': cirq.Linspace,
159
159
  'ListSweep': cirq.ListSweep,
160
+ 'cirq.MSGate': cirq.MSGate,
160
161
  'MatrixGate': cirq.MatrixGate,
161
162
  'MixedUnitaryChannel': cirq.MixedUnitaryChannel,
162
163
  'MeasurementKey': cirq.MeasurementKey,
@@ -246,6 +247,7 @@ def _class_resolver_dictionary() -> Dict[str, ObjectFactory]:
246
247
  'ZipLongest': cirq.ZipLongest,
247
248
  'ZPowGate': cirq.ZPowGate,
248
249
  'ZZPowGate': cirq.ZZPowGate,
250
+ 'UniformSuperpositionGate': cirq.UniformSuperpositionGate,
249
251
  # Old types, only supported for backwards-compatibility
250
252
  'BooleanHamiltonian': _boolean_hamiltonian_gate_op, # Removed in v0.15
251
253
  'CrossEntropyResult': _cross_entropy_result, # Removed in v0.16
@@ -222,8 +222,9 @@ def kron_factor_4x4_to_2x2s(matrix: np.ndarray) -> Tuple[complex, np.ndarray, np
222
222
  f2[(a & 1) ^ i, (b & 1) ^ j] = matrix[a ^ i, b ^ j]
223
223
 
224
224
  # Rescale factors to have unit determinants.
225
- f1 /= np.sqrt(np.linalg.det(f1)) or 1
226
- f2 /= np.sqrt(np.linalg.det(f2)) or 1
225
+ with np.errstate(divide="ignore", invalid="ignore"):
226
+ f1 /= np.sqrt(np.linalg.det(f1)) or 1
227
+ f2 /= np.sqrt(np.linalg.det(f2)) or 1
227
228
 
228
229
  # Determine global phase.
229
230
  g = matrix[a, b] / (f1[a >> 1, b >> 1] * f2[a & 1, b & 1])
@@ -451,18 +452,14 @@ class KakDecomposition:
451
452
  single_qubit_operations_after: a0, a1 from the above equation.
452
453
  """
453
454
  self.global_phase: complex = global_phase
454
- self.single_qubit_operations_before: Tuple[
455
- np.ndarray, np.ndarray
456
- ] = single_qubit_operations_before or (
457
- np.eye(2, dtype=np.complex64),
458
- np.eye(2, dtype=np.complex64),
455
+ self.single_qubit_operations_before: Tuple[np.ndarray, np.ndarray] = (
456
+ single_qubit_operations_before
457
+ or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
459
458
  )
460
459
  self.interaction_coefficients = interaction_coefficients
461
- self.single_qubit_operations_after: Tuple[
462
- np.ndarray, np.ndarray
463
- ] = single_qubit_operations_after or (
464
- np.eye(2, dtype=np.complex64),
465
- np.eye(2, dtype=np.complex64),
460
+ self.single_qubit_operations_after: Tuple[np.ndarray, np.ndarray] = (
461
+ single_qubit_operations_after
462
+ or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
466
463
  )
467
464
 
468
465
  def _value_equality_values_(self) -> Any:
@@ -969,7 +966,8 @@ def kak_vector(
969
966
  # The algorithm in the appendix mentioned above is slightly incorrect in
970
967
  # that it only works for elements of SU(4). A phase correction must be
971
968
  # added to deal with U(4).
972
- phases = np.log(-1j * np.linalg.det(unitary)).imag + np.pi / 2
969
+ with np.errstate(divide="ignore", invalid="ignore"):
970
+ phases = np.log(-1j * np.linalg.det(unitary)).imag + np.pi / 2
973
971
  evals *= np.exp(-1j * phases / 2)[..., np.newaxis]
974
972
 
975
973
  # The following steps follow the appendix exactly.
@@ -422,9 +422,7 @@ def test_axis_angle_decomposition_str():
422
422
  assert (
423
423
  str(
424
424
  cirq.axis_angle(
425
- cirq.unitary(cirq.X**0.25)
426
- @ cirq.unitary(cirq.Y**0.25)
427
- @ cirq.unitary(cirq.Z**0.25)
425
+ cirq.unitary(cirq.X**0.25) @ cirq.unitary(cirq.Y**0.25) @ cirq.unitary(cirq.Z**0.25)
428
426
  )
429
427
  )
430
428
  == '0.477*π around 0.679*X+0.281*Y+0.679*Z'
@@ -255,10 +255,11 @@ def bidiagonalize_unitary_with_special_orthogonals(
255
255
  )
256
256
 
257
257
  # Convert to special orthogonal w/o breaking diagonalization.
258
- if np.linalg.det(left) < 0:
259
- left[0, :] *= -1
260
- if np.linalg.det(right) < 0:
261
- right[:, 0] *= -1
258
+ with np.errstate(divide="ignore", invalid="ignore"):
259
+ if np.linalg.det(left) < 0:
260
+ left[0, :] *= -1
261
+ if np.linalg.det(right) < 0:
262
+ right[:, 0] *= -1
262
263
 
263
264
  diag = combinators.dot(left, mat, right)
264
265
 
cirq/linalg/predicates.py CHANGED
@@ -91,9 +91,10 @@ def is_special_orthogonal(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float
91
91
  Returns:
92
92
  Whether the matrix is special orthogonal within the given tolerance.
93
93
  """
94
- return is_orthogonal(matrix, rtol=rtol, atol=atol) and (
95
- matrix.shape[0] == 0 or np.allclose(np.linalg.det(matrix), 1, rtol=rtol, atol=atol)
96
- )
94
+ with np.errstate(divide="ignore", invalid="ignore"):
95
+ return is_orthogonal(matrix, rtol=rtol, atol=atol) and (
96
+ matrix.shape[0] == 0 or np.allclose(np.linalg.det(matrix), 1, rtol=rtol, atol=atol)
97
+ )
97
98
 
98
99
 
99
100
  def is_unitary(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8) -> bool:
@@ -128,9 +129,10 @@ def is_special_unitary(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float =
128
129
  Whether the matrix is unitary with unit determinant within the given
129
130
  tolerance.
130
131
  """
131
- return is_unitary(matrix, rtol=rtol, atol=atol) and (
132
- matrix.shape[0] == 0 or np.allclose(np.linalg.det(matrix), 1, rtol=rtol, atol=atol)
133
- )
132
+ with np.errstate(divide="ignore", invalid="ignore"):
133
+ return is_unitary(matrix, rtol=rtol, atol=atol) and (
134
+ matrix.shape[0] == 0 or np.allclose(np.linalg.det(matrix), 1, rtol=rtol, atol=atol)
135
+ )
134
136
 
135
137
 
136
138
  def is_normal(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8) -> bool:
@@ -592,7 +592,8 @@ def to_special(u: np.ndarray) -> np.ndarray:
592
592
  Returns:
593
593
  the special unitary matrix
594
594
  """
595
- return u * (np.linalg.det(u) ** (-1 / len(u)))
595
+ with np.errstate(divide="ignore", invalid="ignore"):
596
+ return u * (np.linalg.det(u) ** (-1 / len(u)))
596
597
 
597
598
 
598
599
  def state_vector_kronecker_product(t1: np.ndarray, t2: np.ndarray) -> np.ndarray:
@@ -584,7 +584,7 @@ def test_partial_trace_of_state_vector_as_mixture_mixed_result():
584
584
  (0.5, np.array([1, 0, 0, 0]).reshape((2, 2))),
585
585
  (0.5, np.array([0, 0, 0, 1]).reshape((2, 2))),
586
586
  )
587
- for (q1, q2) in [(0, 1), (0, 2), (1, 2)]:
587
+ for q1, q2 in [(0, 1), (0, 2), (1, 2)]:
588
588
  mixture = cirq.partial_trace_of_state_vector_as_mixture(state, [q1, q2], atol=1e-8)
589
589
  assert mixtures_equal(mixture, truth)
590
590
 
cirq/ops/__init__.py CHANGED
@@ -217,3 +217,5 @@ from cirq.ops.wait_gate import wait, WaitGate
217
217
  from cirq.ops.state_preparation_channel import StatePreparationChannel
218
218
 
219
219
  from cirq.ops.control_values import AbstractControlValues, ProductOfSums, SumOfProducts
220
+
221
+ from cirq.ops.uniform_superposition_gate import UniformSuperpositionGate
cirq/ops/clifford_gate.py CHANGED
@@ -14,11 +14,13 @@
14
14
 
15
15
  from typing import Any, Dict, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
16
16
 
17
-
17
+ import functools
18
+ from dataclasses import dataclass
18
19
  import numpy as np
19
20
 
20
21
  from cirq import protocols, value, linalg, qis
21
22
  from cirq._import import LazyLoader
23
+ from cirq._compat import cached_method
22
24
  from cirq.ops import common_gates, named_qubit, raw_types, pauli_gates, phased_x_z_gate
23
25
  from cirq.ops.pauli_gates import Pauli
24
26
  from cirq.type_workarounds import NotImplementedType
@@ -356,6 +358,8 @@ class CommonCliffordGates(metaclass=CommonCliffordGateMetaClass):
356
358
  class CliffordGate(raw_types.Gate, CommonCliffordGates):
357
359
  """Clifford rotation for N-qubit."""
358
360
 
361
+ _clifford_tableau: qis.CliffordTableau
362
+
359
363
  def __init__(self, *, _clifford_tableau: qis.CliffordTableau) -> None:
360
364
  # We use the Clifford tableau to represent a Clifford gate.
361
365
  # It is crucial to note that the meaning of tableau here is different
@@ -376,7 +380,7 @@ class CliffordGate(raw_types.Gate, CommonCliffordGates):
376
380
  # more precisely the conjugate transformation of ZI by this gate, becomes -ZI.
377
381
  # (Note the real clifford tableau has to satify the Symplectic property.
378
382
  # here is just for illustration)
379
- self._clifford_tableau = _clifford_tableau.copy()
383
+ object.__setattr__(self, '_clifford_tableau', _clifford_tableau.copy())
380
384
 
381
385
  @property
382
386
  def clifford_tableau(self):
@@ -396,21 +400,37 @@ class CliffordGate(raw_types.Gate, CommonCliffordGates):
396
400
  # By definition, Clifford Gate should always return True.
397
401
  return True
398
402
 
399
- def __pow__(self, exponent) -> 'CliffordGate':
403
+ def __pow__(self, exponent: float) -> 'CliffordGate':
404
+ if exponent != int(exponent):
405
+ return NotImplemented
406
+ exponent = int(exponent)
407
+
400
408
  if exponent == -1:
401
409
  return CliffordGate.from_clifford_tableau(self.clifford_tableau.inverse())
402
- if exponent > 0 and int(exponent) == exponent:
403
- base_tableau = self.clifford_tableau.copy()
404
- for _ in range(int(exponent) - 1):
405
- base_tableau = base_tableau.then(self.clifford_tableau)
406
- return CliffordGate.from_clifford_tableau(base_tableau)
407
- if exponent < 0 and int(exponent) == exponent:
408
- base_tableau = self.clifford_tableau.copy()
409
- for _ in range(int(-exponent) - 1):
410
- base_tableau = base_tableau.then(self.clifford_tableau)
411
- return CliffordGate.from_clifford_tableau(base_tableau.inverse())
412
-
413
- return NotImplemented
410
+ if exponent == 0:
411
+ return CliffordGate.from_clifford_tableau(
412
+ qis.CliffordTableau(num_qubits=self._num_qubits_())
413
+ )
414
+ if exponent == 1:
415
+ return self
416
+
417
+ base_tableau = self.clifford_tableau.copy()
418
+ if exponent < 0:
419
+ base_tableau = base_tableau.inverse()
420
+ exponent = abs(exponent)
421
+
422
+ # https://cp-algorithms.com/algebra/binary-exp.html
423
+ aux = qis.CliffordTableau(
424
+ num_qubits=self.clifford_tableau.n
425
+ ) # this tableau collects the odd terms
426
+ while exponent > 1:
427
+ if exponent & 1:
428
+ aux = aux.then(base_tableau)
429
+ base_tableau = base_tableau.then(base_tableau)
430
+ exponent >>= 1
431
+
432
+ base_tableau = base_tableau.then(aux)
433
+ return CliffordGate.from_clifford_tableau(base_tableau)
414
434
 
415
435
  def __repr__(self) -> str:
416
436
  return f"Clifford Gate with Tableau:\n {self.clifford_tableau._str_full_()}"
@@ -457,6 +477,7 @@ class CliffordGate(raw_types.Gate, CommonCliffordGates):
457
477
  return NotImplemented
458
478
 
459
479
 
480
+ @dataclass(frozen=True, init=False, eq=False, repr=False)
460
481
  @value.value_equality(manual_cls=True)
461
482
  class SingleQubitCliffordGate(CliffordGate):
462
483
  """Any single qubit Clifford rotation."""
@@ -468,6 +489,7 @@ class SingleQubitCliffordGate(CliffordGate):
468
489
  return 1
469
490
 
470
491
  @staticmethod
492
+ @functools.cache
471
493
  def from_clifford_tableau(tableau: qis.CliffordTableau) -> 'SingleQubitCliffordGate':
472
494
  if not isinstance(tableau, qis.CliffordTableau):
473
495
  raise ValueError('Input argument has to be a CliffordTableau instance.')
@@ -679,6 +701,10 @@ class SingleQubitCliffordGate(CliffordGate):
679
701
  * {middle point of xyz in 4 Quadrant} * 120 is [[0, 1], [1, 1]]
680
702
  * {middle point of xyz in 4 Quadrant} * 240 is [[1, 1], [1, 0]]
681
703
  """
704
+ return self._to_phased_xz_gate
705
+
706
+ @functools.cached_property
707
+ def _to_phased_xz_gate(self) -> phased_x_z_gate.PhasedXZGate:
682
708
  x_to_flip, z_to_flip = self.clifford_tableau.rs
683
709
  flip_index = int(z_to_flip) * 2 + x_to_flip
684
710
  a, x, z = 0.0, 0.0, 0.0
@@ -716,7 +742,7 @@ class SingleQubitCliffordGate(CliffordGate):
716
742
  z = -0.5 if x_to_flip else 0.5
717
743
  return phased_x_z_gate.PhasedXZGate(x_exponent=x, z_exponent=z, axis_phase_exponent=a)
718
744
 
719
- def __pow__(self, exponent) -> 'SingleQubitCliffordGate':
745
+ def __pow__(self, exponent: Union[float, int]) -> 'SingleQubitCliffordGate':
720
746
  # First to check if we can get the sqrt and negative sqrt Clifford.
721
747
  if self._get_sqrt_map().get(exponent, None):
722
748
  pow_gate = self._get_sqrt_map()[exponent].get(self, None)
@@ -761,6 +787,7 @@ class SingleQubitCliffordGate(CliffordGate):
761
787
  to, flip = self.pauli_tuple(pauli)
762
788
  return to == pauli and not flip
763
789
 
790
+ @cached_method
764
791
  def merged_with(self, second: 'SingleQubitCliffordGate') -> 'SingleQubitCliffordGate':
765
792
  """Returns a SingleQubitCliffordGate such that the circuits
766
793
  --output-- and --self--second--
@@ -773,6 +800,10 @@ class SingleQubitCliffordGate(CliffordGate):
773
800
  return True
774
801
 
775
802
  def _unitary_(self) -> np.ndarray:
803
+ return self._unitary
804
+
805
+ @functools.cached_property
806
+ def _unitary(self) -> np.ndarray:
776
807
  mat = np.eye(2)
777
808
  qubit = named_qubit.NamedQubit('arbitrary')
778
809
  for op in protocols.decompose_once_with_qubits(self, (qubit,)):
@@ -787,6 +818,10 @@ class SingleQubitCliffordGate(CliffordGate):
787
818
  clifford gate if applied in order. This decomposition agrees with
788
819
  cirq.unitary(self), including global phase.
789
820
  """
821
+ return self._decompose_gate
822
+
823
+ @functools.cached_property
824
+ def _decompose_gate(self) -> Sequence['cirq.Gate']:
790
825
  if self == SingleQubitCliffordGate.H:
791
826
  return [common_gates.H]
792
827
  rotations = self.decompose_rotation()
@@ -802,6 +837,10 @@ class SingleQubitCliffordGate(CliffordGate):
802
837
  Note that the combined unitary effect of these rotations may
803
838
  differ from cirq.unitary(self) by a global phase.
804
839
  """
840
+ return self._decompose_rotation
841
+
842
+ @functools.cached_property
843
+ def _decompose_rotation(self) -> Sequence[Tuple[Pauli, int]]:
805
844
  x_rot = self.pauli_tuple(pauli_gates.X)
806
845
  y_rot = self.pauli_tuple(pauli_gates.Y)
807
846
  z_rot = self.pauli_tuple(pauli_gates.Z)
@@ -895,6 +934,10 @@ class SingleQubitCliffordGate(CliffordGate):
895
934
  )
896
935
 
897
936
  def _value_equality_values_(self):
937
+ return self._value_equality_values
938
+
939
+ @functools.cached_property
940
+ def _value_equality_values(self):
898
941
  return self._clifford_tableau.matrix().tobytes() + self._clifford_tableau.rs.tobytes()
899
942
 
900
943
  def _value_equality_values_cls_(self):
@@ -87,8 +87,7 @@ def test_cz_unitary():
87
87
  )
88
88
 
89
89
  assert np.allclose(
90
- cirq.unitary(cirq.CZ**0),
91
- np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]),
90
+ cirq.unitary(cirq.CZ**0), np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
92
91
  )
93
92
 
94
93
  assert np.allclose(
@@ -12,10 +12,11 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  import abc
15
+ from functools import cached_property
15
16
  from typing import Collection, Tuple, TYPE_CHECKING, Any, Dict, Iterator, Optional, Sequence, Union
16
17
  import itertools
17
18
 
18
- from cirq import protocols, value, _compat
19
+ from cirq import protocols, value
19
20
 
20
21
  if TYPE_CHECKING:
21
22
  import cirq
@@ -144,7 +145,7 @@ class ProductOfSums(AbstractControlValues):
144
145
  (cv,) if isinstance(cv, int) else tuple(sorted(set(cv))) for cv in data
145
146
  )
146
147
 
147
- @_compat.cached_property
148
+ @cached_property
148
149
  def is_trivial(self) -> bool:
149
150
  return self._qubit_sums == ((1,),) * self._num_qubits_()
150
151
 
@@ -252,7 +253,7 @@ class SumOfProducts(AbstractControlValues):
252
253
  if not all(len(p) == num_qubits for p in self._conjunctions):
253
254
  raise ValueError(f'Each term of {self._conjunctions} should be of length {num_qubits}.')
254
255
 
255
- @_compat.cached_property
256
+ @cached_property
256
257
  def is_trivial(self) -> bool:
257
258
  return self._conjunctions == ((1,) * self._num_qubits_(),)
258
259
 
@@ -452,9 +452,7 @@ def test_extrapolatable_effect():
452
452
 
453
453
  assert cirq.ControlledGate(cirq.Z) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5)
454
454
 
455
- assert cirq.ControlledGate(cirq.Z).on(a, b) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5).on(
456
- a, b
457
- )
455
+ assert cirq.ControlledGate(cirq.Z).on(a, b) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5).on(a, b)
458
456
 
459
457
  assert cirq.ControlledGate(cirq.Z) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5)
460
458