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
@@ -11,6 +11,8 @@
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
+
15
+ from itertools import product
14
16
  import numpy as np
15
17
  import pytest
16
18
  import cirq
@@ -77,6 +79,43 @@ def test_CCNOT():
77
79
  np.testing.assert_equal(results, expected_results)
78
80
 
79
81
 
82
+ @pytest.mark.parametrize(['initial_state'], [(list(x),) for x in product([0, 1], repeat=4)])
83
+ def test_CCCX(initial_state):
84
+ CCCX = cirq.CCNOT.controlled()
85
+ qubits = cirq.LineQubit.range(4)
86
+
87
+ circuit = cirq.Circuit()
88
+ circuit.append(CCCX(*qubits))
89
+ circuit.append(cirq.measure(qubits, key='key'))
90
+
91
+ final_state = initial_state.copy()
92
+ final_state[-1] ^= all(final_state[:-1])
93
+
94
+ sim = cirq.ClassicalStateSimulator()
95
+ results = sim.simulate(circuit, initial_state=initial_state).measurements['key']
96
+ np.testing.assert_equal(results, final_state)
97
+
98
+
99
+ @pytest.mark.parametrize(['initial_state'], [(list(x),) for x in product([0, 1], repeat=3)])
100
+ def test_CSWAP(initial_state):
101
+ CSWAP = cirq.SWAP.controlled()
102
+ qubits = cirq.LineQubit.range(3)
103
+ circuit = cirq.Circuit()
104
+
105
+ circuit = cirq.Circuit()
106
+ circuit.append(CSWAP(*qubits))
107
+ circuit.append(cirq.measure(qubits, key='key'))
108
+
109
+ a, b, c = initial_state
110
+ if a:
111
+ b, c = c, b
112
+ final_state = [a, b, c]
113
+
114
+ sim = cirq.ClassicalStateSimulator()
115
+ results = sim.simulate(circuit, initial_state=initial_state).measurements['key']
116
+ np.testing.assert_equal(results, final_state)
117
+
118
+
80
119
  def test_measurement_gate():
81
120
  q0, q1 = cirq.LineQubit.range(2)
82
121
  circuit = cirq.Circuit()
@@ -205,3 +244,99 @@ def test_compatible_measurement():
205
244
  sim = cirq.ClassicalStateSimulator()
206
245
  res = sim.run(c, repetitions=3).records
207
246
  np.testing.assert_equal(res['key'], np.array([[[0, 0], [1, 1]]] * 3, dtype=np.uint8))
247
+
248
+
249
+ def test_simulate_sweeps_param_resolver():
250
+ q0, q1 = cirq.LineQubit.range(2)
251
+ simulator = cirq.ClassicalStateSimulator()
252
+ for b0 in [0, 1]:
253
+ for b1 in [0, 1]:
254
+ circuit = cirq.Circuit(
255
+ (cirq.X ** sympy.Symbol('b0'))(q0), (cirq.X ** sympy.Symbol('b1'))(q1)
256
+ )
257
+ params = [
258
+ cirq.ParamResolver({'b0': b0, 'b1': b1}),
259
+ cirq.ParamResolver({'b0': b1, 'b1': b0}),
260
+ ]
261
+ results = simulator.simulate_sweep(circuit, params=params)
262
+
263
+ assert results[0].params == params[0]
264
+ assert results[1].params == params[1]
265
+
266
+
267
+ def test_create_partial_simulation_state_from_int_with_no_qubits():
268
+ sim = cirq.ClassicalStateSimulator()
269
+ initial_state = 5
270
+ qs = None
271
+ classical_data = cirq.value.ClassicalDataDictionaryStore()
272
+ with pytest.raises(ValueError):
273
+ sim._create_partial_simulation_state(
274
+ initial_state=initial_state, qubits=qs, classical_data=classical_data
275
+ )
276
+
277
+
278
+ def test_create_partial_simulation_state_from_invalid_state():
279
+ sim = cirq.ClassicalStateSimulator()
280
+ initial_state = None
281
+ qs = cirq.LineQubit.range(2)
282
+ classical_data = cirq.value.ClassicalDataDictionaryStore()
283
+ with pytest.raises(ValueError):
284
+ sim._create_partial_simulation_state(
285
+ initial_state=initial_state, qubits=qs, classical_data=classical_data
286
+ )
287
+
288
+
289
+ def test_create_partial_simulation_state_from_int():
290
+ sim = cirq.ClassicalStateSimulator()
291
+ initial_state = 15
292
+ qs = cirq.LineQubit.range(4)
293
+ classical_data = cirq.value.ClassicalDataDictionaryStore()
294
+ expected_result = [1, 1, 1, 1]
295
+ result = sim._create_partial_simulation_state(
296
+ initial_state=initial_state, qubits=qs, classical_data=classical_data
297
+ )._state.basis
298
+ assert result == expected_result
299
+
300
+
301
+ def test_create_valid_partial_simulation_state_from_list():
302
+ sim = cirq.ClassicalStateSimulator()
303
+ initial_state = [1, 1, 1, 1]
304
+ qs = cirq.LineQubit.range(4)
305
+ classical_data = cirq.value.ClassicalDataDictionaryStore()
306
+ expected_result = [1, 1, 1, 1]
307
+ result = sim._create_partial_simulation_state(
308
+ initial_state=initial_state, qubits=qs, classical_data=classical_data
309
+ )._state.basis
310
+ assert result == expected_result
311
+
312
+
313
+ def test_create_valid_partial_simulation_state_from_np():
314
+ sim = cirq.ClassicalStateSimulator()
315
+ initial_state = np.array([1, 1])
316
+ qs = cirq.LineQubit.range(2)
317
+ classical_data = cirq.value.ClassicalDataDictionaryStore()
318
+ sim_state = sim._create_partial_simulation_state(
319
+ initial_state=initial_state, qubits=qs, classical_data=classical_data
320
+ )
321
+ sim_state._act_on_fallback_(action=cirq.CX, qubits=qs)
322
+ result = sim_state._state.basis
323
+ expected_result = np.array([1, 0])
324
+ np.testing.assert_equal(result, expected_result)
325
+
326
+
327
+ def test_create_invalid_partial_simulation_state_from_np():
328
+ initial_state = np.array([[1, 1], [1, 1]])
329
+ qs = cirq.LineQubit.range(2)
330
+ classical_data = cirq.value.ClassicalDataDictionaryStore()
331
+ sim = cirq.ClassicalStateSimulator()
332
+ sim_state = sim._create_partial_simulation_state(
333
+ initial_state=initial_state, qubits=qs, classical_data=classical_data
334
+ )
335
+ with pytest.raises(ValueError):
336
+ sim_state._act_on_fallback_(action=cirq.CX, qubits=qs)
337
+
338
+
339
+ def test_noise_model():
340
+ noise_model = cirq.NoiseModel.from_noise_model_like(cirq.depolarize(p=0.01))
341
+ with pytest.raises(ValueError):
342
+ cirq.ClassicalStateSimulator(noise=noise_model)
@@ -324,9 +324,11 @@ def test_clifford_circuit_SHSYSHS():
324
324
  clifford_simulator = cirq.CliffordSimulator()
325
325
  state_vector_simulator = cirq.Simulator()
326
326
 
327
+ # workaround until #6402 is resolved.
328
+ final_state_vector = state_vector_simulator.simulate(circuit).final_state_vector
329
+ final_state_vector /= np.linalg.norm(final_state_vector)
327
330
  np.testing.assert_almost_equal(
328
- clifford_simulator.simulate(circuit).final_state.state_vector(),
329
- state_vector_simulator.simulate(circuit).final_state_vector,
331
+ clifford_simulator.simulate(circuit).final_state.state_vector(), final_state_vector
330
332
  )
331
333
 
332
334
 
cirq/sim/mux.py CHANGED
@@ -292,9 +292,11 @@ def final_density_matrix(
292
292
  density_result = density_matrix_simulator.DensityMatrixSimulator(
293
293
  dtype=dtype, noise=noise, seed=seed
294
294
  ).simulate(
295
- program=measurement_transformers.dephase_measurements(circuit_like)
296
- if ignore_measurement_results
297
- else circuit_like,
295
+ program=(
296
+ measurement_transformers.dephase_measurements(circuit_like)
297
+ if ignore_measurement_results
298
+ else circuit_like
299
+ ),
298
300
  initial_state=initial_state,
299
301
  qubit_order=qubit_order,
300
302
  param_resolver=param_resolver,
@@ -63,12 +63,19 @@ class SimulationProductState(
63
63
  return self._split_untangled_states
64
64
 
65
65
  def create_merged_state(self) -> TSimulationState:
66
+ merged_state = self.sim_states[None]
66
67
  if not self.split_untangled_states:
67
- return self.sim_states[None]
68
- final_args = self.sim_states[None]
69
- for args in set([self.sim_states[k] for k in self.sim_states.keys() if k is not None]):
70
- final_args = final_args.kronecker_product(args)
71
- return final_args.transpose_to_qubit_order(self.qubits)
68
+ return merged_state
69
+ extra_states = set([self.sim_states[k] for k in self.sim_states.keys() if k is not None])
70
+ if not extra_states:
71
+ return merged_state
72
+
73
+ # This comes from a member variable so we need to copy it if we're going to modify inplace
74
+ # before returning. We're not running a step currently, so no need to copy buffers.
75
+ merged_state = merged_state.copy(deep_copy_buffers=False)
76
+ for state in extra_states:
77
+ merged_state.kronecker_product(state, inplace=True)
78
+ return merged_state.transpose_to_qubit_order(self.qubits, inplace=True)
72
79
 
73
80
  def _act_on_fallback_(
74
81
  self, action: Any, qubits: Sequence['cirq.Qid'], allow_decompose: bool = True
@@ -76,9 +83,7 @@ class SimulationProductState(
76
83
  gate_opt = (
77
84
  action
78
85
  if isinstance(action, ops.Gate)
79
- else action.gate
80
- if isinstance(action, ops.Operation)
81
- else None
86
+ else action.gate if isinstance(action, ops.Operation) else None
82
87
  )
83
88
 
84
89
  if isinstance(gate_opt, ops.IdentityGate):
@@ -106,7 +111,7 @@ class SimulationProductState(
106
111
  if op_args_opt is None:
107
112
  op_args_opt = self.sim_states[q]
108
113
  elif q not in op_args_opt.qubits:
109
- op_args_opt = op_args_opt.kronecker_product(self.sim_states[q])
114
+ op_args_opt.kronecker_product(self.sim_states[q], inplace=True)
110
115
  op_args = op_args_opt or self.sim_states[None]
111
116
 
112
117
  # (Backfill the args map with the new value)
@@ -123,7 +128,7 @@ class SimulationProductState(
123
128
  ):
124
129
  for q in qubits:
125
130
  if op_args.allows_factoring and len(op_args.qubits) > 1:
126
- q_args, op_args = op_args.factor((q,), validate=False)
131
+ q_args, _ = op_args.factor((q,), validate=False, inplace=True)
127
132
  self._sim_states[q] = q_args
128
133
 
129
134
  # (Backfill the args map with the new value)
@@ -111,7 +111,7 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
111
111
  return [self.qubit_map[q] for q in qubits]
112
112
 
113
113
  def _perform_measurement(self, qubits: Sequence['cirq.Qid']) -> List[int]:
114
- """Delegates the call to measure the density matrix."""
114
+ """Delegates the call to measure the `QuantumStateRepresentation`."""
115
115
  if self._state is not None:
116
116
  return self._state.measure(self.get_axes(qubits), self.prng)
117
117
  raise NotImplementedError()
@@ -43,8 +43,8 @@ class ExampleSimulationState(cirq.SimulationState):
43
43
  return True
44
44
 
45
45
  def add_qubits(self, qubits):
46
- ret = super().add_qubits(qubits)
47
- return self if NotImplemented else ret
46
+ super().add_qubits(qubits)
47
+ return self
48
48
 
49
49
 
50
50
  class DelegatingAncillaZ(cirq.Gate):
@@ -261,9 +261,9 @@ class SimulatorBase(
261
261
  for i in range(repetitions):
262
262
  for step_result in self._core_iterator(
263
263
  general_suffix,
264
- sim_state=sim_state.copy(deep_copy_buffers=False)
265
- if i < repetitions - 1
266
- else sim_state,
264
+ sim_state=(
265
+ sim_state.copy(deep_copy_buffers=False) if i < repetitions - 1 else sim_state
266
+ ),
267
267
  ):
268
268
  pass
269
269
  for k, r in step_result._classical_data.records.items():
@@ -60,11 +60,11 @@ class _BufferedStateVector(qis.QuantumStateRepresentation):
60
60
  This initializer creates the buffer if necessary.
61
61
 
62
62
  Args:
63
- initial_state: The density matrix, must be correctly formatted. The data is not
63
+ initial_state: The state vector, must be correctly formatted. The data is not
64
64
  checked for validity here due to performance concerns.
65
- qid_shape: The shape of the density matrix, if the initial state is provided as an int.
66
- dtype: The dtype of the density matrix, if the initial state is provided as an int.
67
- buffer: Optional, must be length 3 and same shape as the density matrix. If not
65
+ qid_shape: The shape of the state vector, if the initial state is provided as an int.
66
+ dtype: The dtype of the state vector, if the initial state is provided as an int.
67
+ buffer: Optional, must be length 3 and same shape as the state vector. If not
68
68
  provided, a buffer will be created automatically.
69
69
  Raises:
70
70
  ValueError: If initial state is provided as integer, but qid_shape is not provided.
@@ -14,7 +14,9 @@
14
14
  """Abstract classes for simulations which keep track of state vector."""
15
15
 
16
16
  import abc
17
+ from functools import cached_property
17
18
  from typing import Any, Dict, Iterator, Sequence, Type, TYPE_CHECKING, Generic, TypeVar
19
+ import warnings
18
20
 
19
21
  import numpy as np
20
22
 
@@ -121,9 +123,22 @@ class StateVectorTrialResult(
121
123
  qubit_map=final_simulator_state.qubit_map,
122
124
  )
123
125
 
124
- @_compat.cached_property
126
+ @cached_property
125
127
  def final_state_vector(self) -> np.ndarray:
126
- return self._get_merged_sim_state().target_tensor.reshape(-1)
128
+ ret = self._get_merged_sim_state().target_tensor.reshape(-1)
129
+ norm = np.linalg.norm(ret)
130
+ if abs(norm - 1) > np.sqrt(np.finfo(ret.dtype).eps):
131
+ warnings.warn(
132
+ f"final state vector's {norm=} is too far from 1,"
133
+ f" {abs(norm-1)} > {np.sqrt(np.finfo(ret.dtype).eps)}."
134
+ "skipping renormalization"
135
+ )
136
+ return ret
137
+ # normalize only if doing so improves the round-off on total probability
138
+ ret_norm = ret / norm
139
+ round_off_change = abs(np.vdot(ret_norm, ret_norm) - 1) - abs(np.vdot(ret, ret) - 1)
140
+ result = ret_norm if round_off_change < 0 else ret
141
+ return result
127
142
 
128
143
  def state_vector(self, copy: bool = False) -> np.ndarray:
129
144
  """Return the state vector at the end of the computation.
cirq/study/__init__.py CHANGED
@@ -36,6 +36,7 @@ from cirq.study.sweeps import (
36
36
  Points,
37
37
  Product,
38
38
  Sweep,
39
+ UNIT_SWEEP,
39
40
  UnitSweep,
40
41
  Zip,
41
42
  ZipLongest,
cirq/study/result.py CHANGED
@@ -74,6 +74,18 @@ def _keyed_repeated_bitstrings(vals: Mapping[str, np.ndarray]) -> str:
74
74
  return '\n'.join(keyed_bitstrings)
75
75
 
76
76
 
77
+ def _keyed_repeated_records(vals: Mapping[str, np.ndarray]) -> str:
78
+ keyed_bitstrings = []
79
+ for key in sorted(vals.keys()):
80
+ reps = vals[key]
81
+ n = reps.shape[2]
82
+ num_records = reps.shape[1]
83
+ for j in range(num_records):
84
+ all_bits = ', '.join(_bitstring(reps[:, j, i]) for i in range(n))
85
+ keyed_bitstrings.append(f'{key}={all_bits}')
86
+ return '\n'.join(keyed_bitstrings)
87
+
88
+
77
89
  def _key_to_str(key: TMeasurementKey) -> str:
78
90
  if isinstance(key, str):
79
91
  return key
@@ -388,6 +400,8 @@ class ResultDict(Result):
388
400
  p.text(str(self))
389
401
 
390
402
  def __str__(self) -> str:
403
+ if self._records:
404
+ return _keyed_repeated_records(self.records)
391
405
  return _keyed_repeated_bitstrings(self.measurements)
392
406
 
393
407
  def _json_dict_(self):
cirq/study/result_test.py CHANGED
@@ -127,6 +127,12 @@ def test_str():
127
127
  )
128
128
  assert str(result) == 'ab=13579, 2 4 6 8 10\nc=01234'
129
129
 
130
+ result = cirq.ResultDict(records={'c': np.array([[[True], [True]]])})
131
+ assert str(result) == 'c=1\nc=1'
132
+
133
+ result = cirq.ResultDict(records={'c': np.array([[[True, False], [False, True]]])})
134
+ assert str(result) == 'c=1, 0\nc=0, 1'
135
+
130
136
 
131
137
  def test_df():
132
138
  result = cirq.ResultDict(
cirq/study/sweeps.py CHANGED
@@ -205,6 +205,10 @@ class _Unit(Sweep):
205
205
  UnitSweep = _Unit()
206
206
  document(UnitSweep, """The singleton sweep with no parameters.""")
207
207
 
208
+ # Alternate name to designate as a constant.
209
+ UNIT_SWEEP = UnitSweep
210
+ document(UNIT_SWEEP, """The singleton sweep with no parameters.""")
211
+
208
212
 
209
213
  class Product(Sweep):
210
214
  """Cartesian product of one or more sweeps.
@@ -232,8 +236,6 @@ class Product(Sweep):
232
236
  return sum((factor.keys for factor in self.factors), [])
233
237
 
234
238
  def __len__(self) -> int:
235
- if not self.factors:
236
- return 0
237
239
  length = 1
238
240
  for factor in self.factors:
239
241
  length *= len(factor)
cirq/study/sweeps_test.py CHANGED
@@ -142,6 +142,11 @@ def test_product():
142
142
  assert _values(sweep, 'b') == [4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7]
143
143
 
144
144
 
145
+ def test_empty_product():
146
+ sweep = cirq.Product()
147
+ assert len(sweep) == len(list(sweep)) == 1
148
+
149
+
145
150
  def test_slice_access_error():
146
151
  sweep = cirq.Points('a', [1, 2, 3])
147
152
  with pytest.raises(TypeError, match='<class \'str\'>'):
@@ -232,6 +237,9 @@ def test_equality():
232
237
 
233
238
  et.add_equality_group(cirq.UnitSweep, cirq.UnitSweep)
234
239
 
240
+ # Test singleton
241
+ assert cirq.UNIT_SWEEP is cirq.UnitSweep
242
+
235
243
  # Simple sweeps with the same key are equal to themselves, but different
236
244
  # from each other even if they happen to contain the same points.
237
245
  et.make_equality_group(lambda: cirq.Linspace('a', 0, 10, 11))
cirq/testing/__init__.py CHANGED
@@ -69,7 +69,12 @@ from cirq.testing.equivalent_basis_map import assert_equivalent_computational_ba
69
69
 
70
70
  from cirq.testing.equivalent_repr_eval import assert_equivalent_repr
71
71
 
72
- from cirq.testing.gate_features import SingleQubitGate, TwoQubitGate, ThreeQubitGate
72
+ from cirq.testing.gate_features import (
73
+ SingleQubitGate,
74
+ TwoQubitGate,
75
+ ThreeQubitGate,
76
+ DoesNotSupportSerializationGate,
77
+ )
73
78
 
74
79
  from cirq.testing.json import assert_json_roundtrip_works
75
80
 
@@ -3,11 +3,11 @@
3
3
  See cirq/_compat_test.py for the tests.
4
4
  This module contains example deprecations for modules.
5
5
  """
6
- import sys
7
- from logging import info
6
+ import logging
7
+
8
8
  from cirq import _compat
9
9
 
10
- info("init:compat_test_data")
10
+ logging.info("init:compat_test_data")
11
11
 
12
12
  # simulates a rename of a child module
13
13
  # fake_a -> module_a
@@ -1,7 +1,7 @@
1
1
  # pylint: disable=wrong-or-nonexistent-copyright-notice
2
2
  """module_a for module deprecation tests"""
3
3
 
4
- from logging import info
4
+ import logging
5
5
 
6
6
  from cirq.testing._compat_test_data.module_a import module_b
7
7
 
@@ -11,4 +11,4 @@ from cirq.testing._compat_test_data.module_a.types import SampleType
11
11
 
12
12
  MODULE_A_ATTRIBUTE = "module_a"
13
13
 
14
- info("init:module_a")
14
+ logging.info("init:module_a")
@@ -226,7 +226,7 @@ def assert_circuits_have_same_unitary_given_final_permutation(
226
226
  expected: circuits.AbstractCircuit,
227
227
  qubit_map: Dict[ops.Qid, ops.Qid],
228
228
  ) -> None:
229
- """Asserts two circuits have the same unitary up to a final permuation of qubits.
229
+ """Asserts two circuits have the same unitary up to a final permutation of qubits.
230
230
 
231
231
  Args:
232
232
  actual: A circuit computed by some code under test.
@@ -42,6 +42,7 @@ def assert_qasm_is_consistent_with_unitary(val: Any):
42
42
  if isinstance(val, ops.Operation):
43
43
  qubits: Sequence[ops.Qid] = val.qubits
44
44
  op = val
45
+ gate = val.gate
45
46
  elif isinstance(val, ops.Gate):
46
47
  qid_shape = protocols.qid_shape(val)
47
48
  remaining_shape = list(qid_shape)
@@ -52,9 +53,14 @@ def assert_qasm_is_consistent_with_unitary(val: Any):
52
53
  remaining_shape.pop(i)
53
54
  qubits = devices.LineQid.for_qid_shape(remaining_shape)
54
55
  op = val.on(*qubits)
56
+ gate = val
55
57
  else:
56
58
  raise NotImplementedError(f"Don't know how to test {val!r}")
57
59
 
60
+ if isinstance(gate, ops.GlobalPhaseGate):
61
+ # OpenQASM 2.0 does not support global phase gates.
62
+ return
63
+
58
64
  args = protocols.QasmArgs(qubit_id_map={q: f'q[{i}]' for i, q in enumerate(qubits)})
59
65
  qasm = protocols.qasm(op, args=args, default=None)
60
66
  if qasm is None:
@@ -36,3 +36,13 @@ class ThreeQubitGate(raw_types.Gate):
36
36
 
37
37
  def _num_qubits_(self) -> int:
38
38
  return 3
39
+
40
+
41
+ class DoesNotSupportSerializationGate(raw_types.Gate):
42
+ """A gate that can't be serialized."""
43
+
44
+ def __init__(self, n_qubits: int = 1):
45
+ self.n_qubits = n_qubits
46
+
47
+ def _num_qubits_(self) -> int:
48
+ return self.n_qubits
@@ -133,7 +133,8 @@ def random_special_unitary(
133
133
  The sampled special unitary.
134
134
  """
135
135
  r = random_unitary(dim, random_state=random_state)
136
- r[0, :] /= np.linalg.det(r)
136
+ with np.errstate(divide="ignore", invalid="ignore"):
137
+ r[0, :] /= np.linalg.det(r)
137
138
  return r
138
139
 
139
140
 
@@ -152,8 +153,9 @@ def random_special_orthogonal(
152
153
  The sampled special orthogonal matrix.
153
154
  """
154
155
  m = random_orthogonal(dim, random_state=random_state)
155
- if np.linalg.det(m) < 0:
156
- m[0, :] *= -1
156
+ with np.errstate(divide="ignore", invalid="ignore"):
157
+ if np.linalg.det(m) < 0:
158
+ m[0, :] *= -1
157
159
  return m
158
160
 
159
161
 
@@ -78,6 +78,8 @@ from cirq.transformers.drop_empty_moments import drop_empty_moments
78
78
 
79
79
  from cirq.transformers.drop_negligible_operations import drop_negligible_operations
80
80
 
81
+ from cirq.transformers.dynamical_decoupling import add_dynamical_decoupling
82
+
81
83
  from cirq.transformers.eject_z import eject_z
82
84
 
83
85
  from cirq.transformers.measurement_transformers import (
@@ -119,3 +121,16 @@ from cirq.transformers.transformer_primitives import (
119
121
  unroll_circuit_op_greedy_earliest,
120
122
  unroll_circuit_op_greedy_frontier,
121
123
  )
124
+
125
+
126
+ from cirq.transformers.gauge_compiling import (
127
+ CZGaugeTransformer,
128
+ ConstantGauge,
129
+ Gauge,
130
+ GaugeSelector,
131
+ GaugeTransformer,
132
+ ISWAPGaugeTransformer,
133
+ SpinInversionGaugeTransformer,
134
+ SqrtCZGaugeTransformer,
135
+ SqrtISWAPGaugeTransformer,
136
+ )
@@ -47,7 +47,9 @@ def _decompose_abc(matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarr
47
47
  See [1], chapter 4.
48
48
  """
49
49
  assert matrix.shape == (2, 2)
50
- delta = np.angle(np.linalg.det(matrix)) * 0.5
50
+ with np.errstate(divide="ignore", invalid="ignore"):
51
+ # On MacOS, np.linalg.det emits superflous warnings
52
+ delta = np.angle(np.linalg.det(matrix)) * 0.5
51
53
  alpha = np.angle(matrix[0, 0]) + np.angle(matrix[0, 1]) - 2 * delta
52
54
  beta = np.angle(matrix[0, 0]) - np.angle(matrix[0, 1])
53
55
 
@@ -31,6 +31,24 @@ if TYPE_CHECKING:
31
31
  import cirq
32
32
 
33
33
 
34
+ def _remove_partial_czs_or_fail(
35
+ operations: Iterable['cirq.Operation'], atol: float
36
+ ) -> List['cirq.Operation']:
37
+ result = []
38
+ for op in operations:
39
+ if isinstance(op.gate, ops.CZPowGate):
40
+ t = op.gate.exponent % 2 # CZ^t is periodic with period 2.
41
+ if t < atol:
42
+ continue # Identity.
43
+ elif abs(t - 1) < atol:
44
+ result.append(ops.CZ(*op.qubits)) # Was either CZ or CZ**-1.
45
+ else:
46
+ raise ValueError(f'CZ^t is not allowed for t={t}')
47
+ else:
48
+ result.append(op)
49
+ return result
50
+
51
+
34
52
  def two_qubit_matrix_to_cz_operations(
35
53
  q0: 'cirq.Qid',
36
54
  q1: 'cirq.Qid',
@@ -53,10 +71,16 @@ def two_qubit_matrix_to_cz_operations(
53
71
 
54
72
  Returns:
55
73
  A list of operations implementing the matrix.
74
+
75
+ Raises:
76
+ ValueError: If allow_partial_czs=False and the matrix requires partial CZs.
56
77
  """
57
78
  kak = linalg.kak_decomposition(mat, atol=atol)
58
79
  operations = _kak_decomposition_to_operations(q0, q1, kak, allow_partial_czs, atol=atol)
59
80
  if clean_operations:
81
+ if not allow_partial_czs:
82
+ # CZ^t is not allowed for any $t$ except $t=1$.
83
+ return _remove_partial_czs_or_fail(cleanup_operations(operations), atol=atol)
60
84
  return cleanup_operations(operations)
61
85
  return operations
62
86
 
@@ -257,3 +257,20 @@ def test_decompose_to_diagonal_and_circuit(v):
257
257
  combined_circuit = cirq.Circuit(cirq.MatrixGate(diagonal)(b, c), ops)
258
258
  circuit_unitary = combined_circuit.unitary(qubits_that_should_be_present=[b, c])
259
259
  cirq.testing.assert_allclose_up_to_global_phase(circuit_unitary, v, atol=2e-6)
260
+
261
+
262
+ def test_remove_partial_czs_or_fail():
263
+ CZ = cirq.CZ(*cirq.LineQubit.range(2))
264
+ assert (
265
+ cirq.transformers.analytical_decompositions.two_qubit_to_cz._remove_partial_czs_or_fail(
266
+ [CZ**1e-15], atol=1e-9
267
+ )
268
+ == []
269
+ )
270
+ assert cirq.transformers.analytical_decompositions.two_qubit_to_cz._remove_partial_czs_or_fail(
271
+ [CZ**-1, CZ], atol=1e-9
272
+ ) == [CZ, CZ]
273
+ with pytest.raises(ValueError):
274
+ _ = cirq.transformers.analytical_decompositions.two_qubit_to_cz._remove_partial_czs_or_fail(
275
+ [CZ**-0.5], atol=1e-9
276
+ )