cirq-core 1.2.0.dev20230717225858__py3-none-any.whl → 1.3.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 (158) hide show
  1. cirq/__init__.py +5 -0
  2. cirq/_compat.py +26 -11
  3. cirq/_compat_test.py +37 -3
  4. cirq/_version.py +31 -1
  5. cirq/_version_test.py +1 -1
  6. cirq/circuits/circuit.py +106 -32
  7. cirq/circuits/circuit_operation.py +2 -2
  8. cirq/circuits/circuit_operation_test.py +1 -1
  9. cirq/circuits/circuit_test.py +109 -3
  10. cirq/circuits/frozen_circuit.py +80 -5
  11. cirq/circuits/frozen_circuit_test.py +47 -2
  12. cirq/circuits/qasm_output_test.py +9 -9
  13. cirq/conftest.py +1 -2
  14. cirq/contrib/acquaintance/devices.py +1 -1
  15. cirq/contrib/hacks/disable_validation_test.py +1 -1
  16. cirq/contrib/noise_models/noise_models.py +1 -2
  17. cirq/contrib/paulistring/clifford_optimize.py +1 -1
  18. cirq/contrib/paulistring/clifford_target_gateset_test.py +4 -4
  19. cirq/contrib/qcircuit/qcircuit_pdf.py +1 -1
  20. cirq/contrib/quimb/density_matrix.py +2 -3
  21. cirq/contrib/quimb/grid_circuits.py +3 -3
  22. cirq/contrib/quimb/state_vector.py +3 -5
  23. cirq/contrib/routing/utils.py +1 -2
  24. cirq/contrib/svg/svg.py +4 -6
  25. cirq/devices/grid_qubit.py +49 -38
  26. cirq/devices/grid_qubit_test.py +1 -3
  27. cirq/devices/insertion_noise_model.py +21 -1
  28. cirq/devices/insertion_noise_model_test.py +6 -0
  29. cirq/devices/line_qubit.py +67 -40
  30. cirq/devices/named_topologies.py +8 -14
  31. cirq/devices/noise_properties.py +1 -1
  32. cirq/devices/noise_utils.py +7 -5
  33. cirq/devices/noise_utils_test.py +7 -0
  34. cirq/experiments/fidelity_estimation_test.py +1 -1
  35. cirq/experiments/qubit_characterizations.py +6 -5
  36. cirq/experiments/random_quantum_circuit_generation.py +1 -1
  37. cirq/experiments/random_quantum_circuit_generation_test.py +28 -1
  38. cirq/experiments/readout_confusion_matrix.py +6 -6
  39. cirq/experiments/xeb_fitting.py +3 -5
  40. cirq/experiments/xeb_fitting_test.py +2 -2
  41. cirq/experiments/xeb_sampling.py +1 -1
  42. cirq/interop/quirk/url_to_circuit.py +40 -38
  43. cirq/json_resolver_cache.py +2 -0
  44. cirq/linalg/decompositions.py +6 -5
  45. cirq/ops/__init__.py +2 -0
  46. cirq/ops/classically_controlled_operation.py +1 -1
  47. cirq/ops/clifford_gate.py +9 -9
  48. cirq/ops/clifford_gate_test.py +3 -4
  49. cirq/ops/common_channels.py +2 -5
  50. cirq/ops/common_channels_test.py +3 -5
  51. cirq/ops/common_gates_test.py +7 -7
  52. cirq/ops/controlled_operation_test.py +2 -2
  53. cirq/ops/dense_pauli_string.py +3 -0
  54. cirq/ops/eigen_gate_test.py +1 -3
  55. cirq/ops/fourier_transform.py +1 -2
  56. cirq/ops/fsim_gate.py +1 -1
  57. cirq/ops/gate_features_test.py +2 -2
  58. cirq/ops/gate_operation_test.py +1 -2
  59. cirq/ops/greedy_qubit_manager.py +86 -0
  60. cirq/ops/greedy_qubit_manager_test.py +98 -0
  61. cirq/ops/linear_combinations.py +1 -1
  62. cirq/ops/named_qubit.py +55 -18
  63. cirq/ops/parity_gates.py +65 -18
  64. cirq/ops/parity_gates_test.py +41 -2
  65. cirq/ops/pauli_gates.py +2 -2
  66. cirq/ops/pauli_string.py +3 -4
  67. cirq/ops/pauli_string_raw_types_test.py +3 -3
  68. cirq/ops/pauli_string_test.py +3 -4
  69. cirq/ops/random_gate_channel_test.py +3 -3
  70. cirq/ops/raw_types.py +1 -1
  71. cirq/ops/raw_types_test.py +5 -5
  72. cirq/ops/three_qubit_gates.py +12 -8
  73. cirq/protocols/act_on_protocol_test.py +9 -9
  74. cirq/protocols/apply_channel_protocol.py +9 -6
  75. cirq/protocols/apply_unitary_protocol_test.py +1 -1
  76. cirq/protocols/equal_up_to_global_phase_protocol_test.py +2 -2
  77. cirq/protocols/has_stabilizer_effect_protocol.py +52 -6
  78. cirq/protocols/has_stabilizer_effect_protocol_test.py +21 -8
  79. cirq/protocols/has_unitary_protocol_test.py +1 -3
  80. cirq/protocols/json_serialization.py +6 -6
  81. cirq/protocols/json_serialization_test.py +7 -14
  82. cirq/protocols/json_test_data/InsertionNoiseModel.json +91 -0
  83. cirq/protocols/json_test_data/InsertionNoiseModel.repr +4 -0
  84. cirq/protocols/json_test_data/OpIdentifier.json +45 -10
  85. cirq/protocols/json_test_data/OpIdentifier.repr +7 -1
  86. cirq/protocols/json_test_data/spec.py +4 -0
  87. cirq/protocols/measurement_key_protocol_test.py +1 -1
  88. cirq/protocols/unitary_protocol_test.py +13 -16
  89. cirq/qis/clifford_tableau.py +7 -8
  90. cirq/qis/measures.py +1 -1
  91. cirq/qis/states.py +2 -3
  92. cirq/sim/__init__.py +2 -0
  93. cirq/sim/classical_simulator.py +107 -0
  94. cirq/sim/classical_simulator_test.py +207 -0
  95. cirq/sim/clifford/clifford_simulator_test.py +7 -7
  96. cirq/sim/clifford/stabilizer_simulation_state.py +2 -2
  97. cirq/sim/clifford/stabilizer_state_ch_form.py +7 -7
  98. cirq/sim/density_matrix_simulation_state.py +19 -4
  99. cirq/sim/density_matrix_simulator_test.py +5 -13
  100. cirq/sim/simulation_state_test.py +13 -14
  101. cirq/sim/simulator_test.py +6 -9
  102. cirq/sim/state_vector_simulation_state.py +1 -1
  103. cirq/study/resolver.py +41 -41
  104. cirq/study/resolver_test.py +13 -12
  105. cirq/testing/__init__.py +4 -1
  106. cirq/testing/circuit_compare.py +1 -1
  107. cirq/testing/circuit_compare_test.py +11 -11
  108. cirq/testing/consistent_controlled_gate_op.py +15 -1
  109. cirq/testing/consistent_controlled_gate_op_test.py +12 -3
  110. cirq/testing/consistent_decomposition.py +0 -1
  111. cirq/testing/consistent_protocols.py +6 -1
  112. cirq/testing/consistent_protocols_test.py +5 -10
  113. cirq/testing/consistent_qasm.py +2 -4
  114. cirq/testing/consistent_qasm_test.py +2 -3
  115. cirq/testing/consistent_specified_has_unitary_test.py +1 -3
  116. cirq/testing/equals_tester.py +1 -1
  117. cirq/testing/equals_tester_test.py +5 -5
  118. cirq/testing/equivalent_repr_eval_test.py +1 -3
  119. cirq/testing/gate_features_test.py +6 -6
  120. cirq/testing/order_tester_test.py +1 -3
  121. cirq/testing/random_circuit_test.py +1 -3
  122. cirq/transformers/__init__.py +3 -0
  123. cirq/transformers/analytical_decompositions/__init__.py +1 -0
  124. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +1 -2
  125. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +2 -5
  126. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +38 -0
  127. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +18 -0
  128. cirq/transformers/expand_composite_test.py +4 -4
  129. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +1 -1
  130. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -2
  131. cirq/transformers/merge_k_qubit_gates_test.py +2 -2
  132. cirq/transformers/qubit_management_transformers.py +177 -0
  133. cirq/transformers/qubit_management_transformers_test.py +250 -0
  134. cirq/transformers/routing/route_circuit_cqc.py +23 -4
  135. cirq/transformers/routing/route_circuit_cqc_test.py +42 -0
  136. cirq/transformers/stratify.py +10 -11
  137. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +10 -10
  138. cirq/transformers/target_gatesets/cz_gateset_test.py +8 -10
  139. cirq/transformers/transformer_primitives.py +138 -28
  140. cirq/value/abc_alt_test.py +4 -4
  141. cirq/value/duration.py +68 -37
  142. cirq/value/duration_test.py +2 -0
  143. cirq/value/measurement_key_test.py +1 -1
  144. cirq/value/product_state.py +4 -8
  145. cirq/value/value_equality_attr.py +12 -5
  146. cirq/vis/heatmap.py +7 -4
  147. cirq/vis/heatmap_test.py +14 -4
  148. cirq/vis/histogram.py +4 -4
  149. cirq/vis/state_histogram.py +10 -6
  150. cirq/vis/state_histogram_test.py +2 -0
  151. cirq/work/observable_measurement_data_test.py +1 -1
  152. cirq/work/observable_measurement_test.py +2 -2
  153. cirq/work/zeros_sampler.py +1 -1
  154. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/METADATA +11 -19
  155. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/RECORD +158 -150
  156. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/WHEEL +1 -1
  157. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/LICENSE +0 -0
  158. {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/top_level.txt +0 -0
@@ -275,8 +275,7 @@ class CliffordTableau(StabilizerState):
275
275
 
276
276
  def __eq__(self, other):
277
277
  if not isinstance(other, type(self)):
278
- # coverage: ignore
279
- return NotImplemented
278
+ return NotImplemented # pragma: no cover
280
279
  return (
281
280
  self.n == other.n
282
281
  and np.array_equal(self.rs, other.rs)
@@ -551,7 +550,7 @@ class CliffordTableau(StabilizerState):
551
550
  if exponent % 2 == 0:
552
551
  return
553
552
  if exponent % 0.5 != 0.0:
554
- raise ValueError('X exponent must be half integer') # coverage: ignore
553
+ raise ValueError('X exponent must be half integer') # pragma: no cover
555
554
  effective_exponent = exponent % 2
556
555
  if effective_exponent == 0.5:
557
556
  self.xs[:, axis] ^= self.zs[:, axis]
@@ -566,7 +565,7 @@ class CliffordTableau(StabilizerState):
566
565
  if exponent % 2 == 0:
567
566
  return
568
567
  if exponent % 0.5 != 0.0:
569
- raise ValueError('Y exponent must be half integer') # coverage: ignore
568
+ raise ValueError('Y exponent must be half integer') # pragma: no cover
570
569
  effective_exponent = exponent % 2
571
570
  if effective_exponent == 0.5:
572
571
  self.rs[:] ^= self.xs[:, axis] & (~self.zs[:, axis])
@@ -587,7 +586,7 @@ class CliffordTableau(StabilizerState):
587
586
  if exponent % 2 == 0:
588
587
  return
589
588
  if exponent % 0.5 != 0.0:
590
- raise ValueError('Z exponent must be half integer') # coverage: ignore
589
+ raise ValueError('Z exponent must be half integer') # pragma: no cover
591
590
  effective_exponent = exponent % 2
592
591
  if effective_exponent == 0.5:
593
592
  self.rs[:] ^= self.xs[:, axis] & self.zs[:, axis]
@@ -602,7 +601,7 @@ class CliffordTableau(StabilizerState):
602
601
  if exponent % 2 == 0:
603
602
  return
604
603
  if exponent % 1 != 0:
605
- raise ValueError('H exponent must be integer') # coverage: ignore
604
+ raise ValueError('H exponent must be integer') # pragma: no cover
606
605
  self.apply_y(axis, 0.5)
607
606
  self.apply_x(axis)
608
607
 
@@ -612,7 +611,7 @@ class CliffordTableau(StabilizerState):
612
611
  if exponent % 2 == 0:
613
612
  return
614
613
  if exponent % 1 != 0:
615
- raise ValueError('CZ exponent must be integer') # coverage: ignore
614
+ raise ValueError('CZ exponent must be integer') # pragma: no cover
616
615
  (self.xs[:, target_axis], self.zs[:, target_axis]) = (
617
616
  self.zs[:, target_axis].copy(),
618
617
  self.xs[:, target_axis].copy(),
@@ -637,7 +636,7 @@ class CliffordTableau(StabilizerState):
637
636
  if exponent % 2 == 0:
638
637
  return
639
638
  if exponent % 1 != 0:
640
- raise ValueError('CX exponent must be integer') # coverage: ignore
639
+ raise ValueError('CX exponent must be integer') # pragma: no cover
641
640
  self.rs[:] ^= (
642
641
  self.xs[:, control_axis]
643
642
  & self.zs[:, target_axis]
cirq/qis/measures.py CHANGED
@@ -211,7 +211,7 @@ def _numpy_arrays_to_state_vectors_or_density_matrices(
211
211
  state2.shape[0] if state2.ndim == 2 else np.prod(state2.shape, dtype=np.int64).item()
212
212
  )
213
213
  if dim1 != dim2:
214
- raise ValueError('Mismatched dimensions in given states: ' f'{dim1} and {dim2}.')
214
+ raise ValueError(f'Mismatched dimensions in given states: {dim1} and {dim2}.')
215
215
  if qid_shape is None:
216
216
  qid_shape = (dim1,)
217
217
  else:
cirq/qis/states.py CHANGED
@@ -314,7 +314,7 @@ def density_matrix(
314
314
  ValueError: Invalid density matrix.
315
315
  """
316
316
  if state.ndim != 2 or state.shape[0] != state.shape[1]:
317
- raise ValueError('A density matrix must be a square matrix. ' f'Got shape {state.shape}.')
317
+ raise ValueError(f'A density matrix must be a square matrix. Got shape {state.shape}.')
318
318
  dim, _ = state.shape
319
319
  if qid_shape is None:
320
320
  qid_shape = _infer_qid_shape_from_dimension(dim)
@@ -524,8 +524,7 @@ class _QidShapeSet:
524
524
  'with the corresponding qudit dimensions being at least '
525
525
  f'{self.min_qudit_dimensions}.'
526
526
  )
527
- if len(self.explicit_qid_shapes) > 1:
528
- # coverage: ignore
527
+ if len(self.explicit_qid_shapes) > 1: # pragma: no cover
529
528
  raise ValueError(
530
529
  f'Qid shape is ambiguous: Could be any one of {self.explicit_qid_shapes}.'
531
530
  )
cirq/sim/__init__.py CHANGED
@@ -68,6 +68,8 @@ from cirq.sim.state_vector import measure_state_vector, sample_state_vector, Sta
68
68
 
69
69
  from cirq.sim.state_vector_simulation_state import StateVectorSimulationState
70
70
 
71
+ from cirq.sim.classical_simulator import ClassicalStateSimulator
72
+
71
73
  from cirq.sim.state_vector_simulator import (
72
74
  SimulatesIntermediateStateVector,
73
75
  StateVectorStepResult,
@@ -0,0 +1,107 @@
1
+ # Copyright 2023 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Dict
16
+ from collections import defaultdict
17
+ from cirq.sim.simulator import SimulatesSamples
18
+ from cirq import ops, protocols
19
+ from cirq.study.resolver import ParamResolver
20
+ from cirq.circuits.circuit import AbstractCircuit
21
+ from cirq.ops.raw_types import Qid
22
+ import numpy as np
23
+
24
+
25
+ def _is_identity(op: ops.Operation) -> bool:
26
+ if isinstance(op.gate, (ops.XPowGate, ops.CXPowGate, ops.CCXPowGate, ops.SwapPowGate)):
27
+ return op.gate.exponent % 2 == 0
28
+ return False
29
+
30
+
31
+ class ClassicalStateSimulator(SimulatesSamples):
32
+ """A simulator that accepts only gates with classical counterparts.
33
+
34
+ This simulator evolves a single state, using only gates that output a single state for each
35
+ input state. The simulator runs in linear time, at the cost of not supporting superposition.
36
+ It can be used to estimate costs and simulate circuits for simple non-quantum algorithms using
37
+ many more qubits than fully capable quantum simulators.
38
+
39
+ The supported gates are:
40
+ - cirq.X
41
+ - cirq.CNOT
42
+ - cirq.SWAP
43
+ - cirq.TOFFOLI
44
+ - cirq.measure
45
+
46
+ Args:
47
+ circuit: The circuit to simulate.
48
+ param_resolver: Parameters to run with the program.
49
+ repetitions: Number of times to repeat the run. It is expected that
50
+ this is validated greater than zero before calling this method.
51
+
52
+ Returns:
53
+ A dictionary mapping measurement keys to measurement results.
54
+
55
+ Raises:
56
+ ValueError: If
57
+ - one of the gates is not an X, CNOT, SWAP, TOFFOLI or a measurement.
58
+ - A measurement key is used for measurements on different numbers of qubits.
59
+ """
60
+
61
+ def _run(
62
+ self, circuit: AbstractCircuit, param_resolver: ParamResolver, repetitions: int
63
+ ) -> Dict[str, np.ndarray]:
64
+ results_dict: Dict[str, np.ndarray] = {}
65
+ values_dict: Dict[Qid, int] = defaultdict(int)
66
+ param_resolver = param_resolver or ParamResolver({})
67
+ resolved_circuit = protocols.resolve_parameters(circuit, param_resolver)
68
+
69
+ for moment in resolved_circuit:
70
+ for op in moment:
71
+ if _is_identity(op):
72
+ continue
73
+ if op.gate == ops.X:
74
+ (q,) = op.qubits
75
+ values_dict[q] ^= 1
76
+ elif op.gate == ops.CNOT:
77
+ c, q = op.qubits
78
+ values_dict[q] ^= values_dict[c]
79
+ elif op.gate == ops.SWAP:
80
+ a, b = op.qubits
81
+ values_dict[a], values_dict[b] = values_dict[b], values_dict[a]
82
+ elif op.gate == ops.TOFFOLI:
83
+ c1, c2, q = op.qubits
84
+ values_dict[q] ^= values_dict[c1] & values_dict[c2]
85
+ elif protocols.is_measurement(op):
86
+ measurement_values = np.array(
87
+ [[[values_dict[q] for q in op.qubits]]] * repetitions, dtype=np.uint8
88
+ )
89
+ key = op.gate.key # type: ignore
90
+ if key in results_dict:
91
+ if op._num_qubits_() != results_dict[key].shape[-1]:
92
+ raise ValueError(
93
+ f'Measurement shape {len(measurement_values)} does not match '
94
+ f'{results_dict[key].shape[-1]} in {key}.'
95
+ )
96
+ results_dict[key] = np.concatenate(
97
+ (results_dict[key], measurement_values), axis=1
98
+ )
99
+ else:
100
+ results_dict[key] = measurement_values
101
+ else:
102
+ raise ValueError(
103
+ f'{op} is not one of cirq.X, cirq.CNOT, cirq.SWAP, '
104
+ 'cirq.CCNOT, or a measurement'
105
+ )
106
+
107
+ return results_dict
@@ -0,0 +1,207 @@
1
+ # Copyright 2023 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import numpy as np
15
+ import pytest
16
+ import cirq
17
+ import sympy
18
+
19
+
20
+ def test_x_gate():
21
+ q0, q1 = cirq.LineQubit.range(2)
22
+ circuit = cirq.Circuit()
23
+ circuit.append(cirq.X(q0))
24
+ circuit.append(cirq.X(q1))
25
+ circuit.append(cirq.X(q1))
26
+ circuit.append(cirq.measure((q0, q1), key='key'))
27
+ expected_results = {'key': np.array([[[1, 0]]], dtype=np.uint8)}
28
+ sim = cirq.ClassicalStateSimulator()
29
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
30
+ np.testing.assert_equal(results, expected_results)
31
+
32
+
33
+ def test_CNOT():
34
+ q0, q1 = cirq.LineQubit.range(2)
35
+ circuit = cirq.Circuit()
36
+ circuit.append(cirq.X(q0))
37
+ circuit.append(cirq.CNOT(q0, q1))
38
+ circuit.append(cirq.measure(q1, key='key'))
39
+ expected_results = {'key': np.array([[[1]]], dtype=np.uint8)}
40
+ sim = cirq.ClassicalStateSimulator()
41
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
42
+ np.testing.assert_equal(results, expected_results)
43
+
44
+
45
+ def test_Swap():
46
+ q0, q1 = cirq.LineQubit.range(2)
47
+ circuit = cirq.Circuit()
48
+ circuit.append(cirq.X(q0))
49
+ circuit.append(cirq.SWAP(q0, q1))
50
+ circuit.append(cirq.measure((q0, q1), key='key'))
51
+ expected_results = {'key': np.array([[[0, 1]]], dtype=np.uint8)}
52
+ sim = cirq.ClassicalStateSimulator()
53
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
54
+ np.testing.assert_equal(results, expected_results)
55
+
56
+
57
+ def test_CCNOT():
58
+ q0, q1, q2 = cirq.LineQubit.range(3)
59
+ circuit = cirq.Circuit()
60
+ circuit.append(cirq.CCNOT(q0, q1, q2))
61
+ circuit.append(cirq.measure((q0, q1, q2), key='key'))
62
+ circuit.append(cirq.X(q0))
63
+ circuit.append(cirq.CCNOT(q0, q1, q2))
64
+ circuit.append(cirq.measure((q0, q1, q2), key='key'))
65
+ circuit.append(cirq.X(q1))
66
+ circuit.append(cirq.X(q0))
67
+ circuit.append(cirq.CCNOT(q0, q1, q2))
68
+ circuit.append(cirq.measure((q0, q1, q2), key='key'))
69
+ circuit.append(cirq.X(q0))
70
+ circuit.append(cirq.CCNOT(q0, q1, q2))
71
+ circuit.append(cirq.measure((q0, q1, q2), key='key'))
72
+ expected_results = {
73
+ 'key': np.array([[[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 1]]], dtype=np.uint8)
74
+ }
75
+ sim = cirq.ClassicalStateSimulator()
76
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
77
+ np.testing.assert_equal(results, expected_results)
78
+
79
+
80
+ def test_measurement_gate():
81
+ q0, q1 = cirq.LineQubit.range(2)
82
+ circuit = cirq.Circuit()
83
+ circuit.append(cirq.measure((q0, q1), key='key'))
84
+ expected_results = {'key': np.array([[[0, 0]]], dtype=np.uint8)}
85
+ sim = cirq.ClassicalStateSimulator()
86
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
87
+ np.testing.assert_equal(results, expected_results)
88
+
89
+
90
+ def test_qubit_order():
91
+ q0, q1 = cirq.LineQubit.range(2)
92
+ circuit = cirq.Circuit()
93
+ circuit.append(cirq.CNOT(q0, q1))
94
+ circuit.append(cirq.X(q0))
95
+ circuit.append(cirq.measure((q0, q1), key='key'))
96
+ expected_results = {'key': np.array([[[1, 0]]], dtype=np.uint8)}
97
+ sim = cirq.ClassicalStateSimulator()
98
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
99
+ np.testing.assert_equal(results, expected_results)
100
+
101
+
102
+ def test_same_key_instances():
103
+ q0, q1 = cirq.LineQubit.range(2)
104
+ circuit = cirq.Circuit()
105
+ circuit.append(cirq.measure((q0, q1), key='key'))
106
+ circuit.append(cirq.X(q0))
107
+ circuit.append(cirq.measure((q0, q1), key='key'))
108
+ expected_results = {'key': np.array([[[0, 0], [1, 0]]], dtype=np.uint8)}
109
+ sim = cirq.ClassicalStateSimulator()
110
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
111
+ np.testing.assert_equal(results, expected_results)
112
+
113
+
114
+ def test_same_key_instances_order():
115
+ q0, q1 = cirq.LineQubit.range(2)
116
+ circuit = cirq.Circuit()
117
+ circuit.append(cirq.X(q0))
118
+ circuit.append(cirq.measure((q0, q1), key='key'))
119
+ circuit.append(cirq.X(q0))
120
+ circuit.append(cirq.measure((q1, q0), key='key'))
121
+ expected_results = {'key': np.array([[[1, 0], [0, 0]]], dtype=np.uint8)}
122
+ sim = cirq.ClassicalStateSimulator()
123
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
124
+ np.testing.assert_equal(results, expected_results)
125
+
126
+
127
+ def test_repetitions():
128
+ q0 = cirq.LineQubit.range(1)
129
+ circuit = cirq.Circuit()
130
+ circuit.append(cirq.measure(q0, key='key'))
131
+ expected_results = {
132
+ 'key': np.array(
133
+ [[[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]], [[0]]], dtype=np.uint8
134
+ )
135
+ }
136
+ sim = cirq.ClassicalStateSimulator()
137
+ results = sim.run(circuit, param_resolver=None, repetitions=10).records
138
+ np.testing.assert_equal(results, expected_results)
139
+
140
+
141
+ def test_multiple_gates():
142
+ q0, q1 = cirq.LineQubit.range(2)
143
+ circuit = cirq.Circuit()
144
+ circuit.append(cirq.X(q0))
145
+ circuit.append(cirq.CNOT(q0, q1))
146
+ circuit.append(cirq.CNOT(q0, q1))
147
+ circuit.append(cirq.CNOT(q0, q1))
148
+ circuit.append(cirq.X(q1))
149
+ circuit.append(cirq.measure((q0, q1), key='key'))
150
+ expected_results = {'key': np.array([[[1, 0]]], dtype=np.uint8)}
151
+ sim = cirq.ClassicalStateSimulator()
152
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
153
+ np.testing.assert_equal(results, expected_results)
154
+
155
+
156
+ def test_multiple_gates_order():
157
+ q0, q1 = cirq.LineQubit.range(2)
158
+ circuit = cirq.Circuit()
159
+ circuit.append(cirq.X(q0))
160
+ circuit.append(cirq.CNOT(q0, q1))
161
+ circuit.append(cirq.CNOT(q1, q0))
162
+ circuit.append(cirq.measure((q0, q1), key='key'))
163
+ expected_results = {'key': np.array([[[0, 1]]], dtype=np.uint8)}
164
+ sim = cirq.ClassicalStateSimulator()
165
+ results = sim.run(circuit, param_resolver=None, repetitions=1).records
166
+ np.testing.assert_equal(results, expected_results)
167
+
168
+
169
+ def test_param_resolver():
170
+ gate = cirq.CNOT ** sympy.Symbol('t')
171
+ q0, q1 = cirq.LineQubit.range(2)
172
+ circuit = cirq.Circuit()
173
+ circuit.append(cirq.X(q0))
174
+ circuit.append(gate(q0, q1))
175
+ circuit.append(cirq.measure((q1), key='key'))
176
+ resolver = cirq.ParamResolver({'t': 0})
177
+ sim = cirq.ClassicalStateSimulator()
178
+ results_with_parameter_zero = sim.run(circuit, param_resolver=resolver, repetitions=1).records
179
+ resolver = cirq.ParamResolver({'t': 1})
180
+ results_with_parameter_one = sim.run(circuit, param_resolver=resolver, repetitions=1).records
181
+ np.testing.assert_equal(results_with_parameter_zero, {'key': np.array([[[0]]], dtype=np.uint8)})
182
+ np.testing.assert_equal(results_with_parameter_one, {'key': np.array([[[1]]], dtype=np.uint8)})
183
+
184
+
185
+ def test_unknown_gates():
186
+ gate = cirq.Y
187
+ q = cirq.LineQubit(0)
188
+ circuit = cirq.Circuit(gate(q), cirq.measure((q), key='key'))
189
+ sim = cirq.ClassicalStateSimulator()
190
+ with pytest.raises(ValueError):
191
+ _ = sim.run(circuit).records
192
+
193
+
194
+ def test_incompatible_measurements():
195
+ qs = cirq.LineQubit.range(2)
196
+ c = cirq.Circuit(cirq.measure(qs, key='key'), cirq.measure(qs[0], key='key'))
197
+ sim = cirq.ClassicalStateSimulator()
198
+ with pytest.raises(ValueError):
199
+ _ = sim.run(c)
200
+
201
+
202
+ def test_compatible_measurement():
203
+ qs = cirq.LineQubit.range(2)
204
+ c = cirq.Circuit(cirq.measure(qs, key='key'), cirq.X.on_each(qs), cirq.measure(qs, key='key'))
205
+ sim = cirq.ClassicalStateSimulator()
206
+ res = sim.run(c, repetitions=3).records
207
+ np.testing.assert_equal(res['key'], np.array([[[0, 0], [1, 1]]] * 3, dtype=np.uint8))
@@ -373,19 +373,19 @@ def test_clifford_circuit_2(qubits, split):
373
373
  x = np.random.randint(7)
374
374
 
375
375
  if x == 0:
376
- circuit.append(cirq.X(np.random.choice(qubits))) # coverage: ignore
376
+ circuit.append(cirq.X(np.random.choice(qubits))) # pragma: no cover
377
377
  elif x == 1:
378
- circuit.append(cirq.Z(np.random.choice(qubits))) # coverage: ignore
378
+ circuit.append(cirq.Z(np.random.choice(qubits))) # pragma: no cover
379
379
  elif x == 2:
380
- circuit.append(cirq.Y(np.random.choice(qubits))) # coverage: ignore
380
+ circuit.append(cirq.Y(np.random.choice(qubits))) # pragma: no cover
381
381
  elif x == 3:
382
- circuit.append(cirq.S(np.random.choice(qubits))) # coverage: ignore
382
+ circuit.append(cirq.S(np.random.choice(qubits))) # pragma: no cover
383
383
  elif x == 4:
384
- circuit.append(cirq.H(np.random.choice(qubits))) # coverage: ignore
384
+ circuit.append(cirq.H(np.random.choice(qubits))) # pragma: no cover
385
385
  elif x == 5:
386
- circuit.append(cirq.CNOT(qubits[0], qubits[1])) # coverage: ignore
386
+ circuit.append(cirq.CNOT(qubits[0], qubits[1])) # pragma: no cover
387
387
  elif x == 6:
388
- circuit.append(cirq.CZ(qubits[0], qubits[1])) # coverage: ignore
388
+ circuit.append(cirq.CZ(qubits[0], qubits[1])) # pragma: no cover
389
389
 
390
390
  circuit.append(cirq.measure(qubits[0]))
391
391
  result = cirq.CliffordSimulator(split_untangled_states=split).run(circuit, repetitions=100)
@@ -84,7 +84,7 @@ class StabilizerSimulationState(
84
84
  ):
85
85
  """Apply a SWAP gate"""
86
86
  if exponent % 1 != 0:
87
- raise ValueError('Swap exponent must be integer') # coverage: ignore
87
+ raise ValueError('Swap exponent must be integer') # pragma: no cover
88
88
  self._state.apply_cx(control_axis, target_axis)
89
89
  self._state.apply_cx(target_axis, control_axis, exponent, global_shift)
90
90
  self._state.apply_cx(control_axis, target_axis)
@@ -122,7 +122,7 @@ class StabilizerSimulationState(
122
122
  if mixture is None:
123
123
  return NotImplemented
124
124
  if not all(linalg.is_unitary(m) for _, m in mixture):
125
- return NotImplemented # coverage: ignore
125
+ return NotImplemented # pragma: no cover
126
126
  probabilities, unitaries = zip(*mixture)
127
127
  index = self.prng.choice(len(unitaries), p=probabilities)
128
128
  return self._strat_act_from_single_qubit_decompose(
@@ -54,7 +54,7 @@ class StabilizerStateChForm(qis.StabilizerState):
54
54
  self.omega: complex = 1
55
55
 
56
56
  # Apply X for every non-zero element of initial_state
57
- for (i, val) in enumerate(
57
+ for i, val in enumerate(
58
58
  big_endian_int_to_digits(initial_state, digit_count=num_qubits, base=2)
59
59
  ):
60
60
  if val:
@@ -295,7 +295,7 @@ class StabilizerStateChForm(qis.StabilizerState):
295
295
  def apply_x(self, axis: int, exponent: float = 1, global_shift: float = 0):
296
296
  if exponent % 2 != 0:
297
297
  if exponent % 0.5 != 0.0:
298
- raise ValueError('X exponent must be half integer') # coverage: ignore
298
+ raise ValueError('X exponent must be half integer') # pragma: no cover
299
299
  self.apply_h(axis)
300
300
  self.apply_z(axis, exponent)
301
301
  self.apply_h(axis)
@@ -303,7 +303,7 @@ class StabilizerStateChForm(qis.StabilizerState):
303
303
 
304
304
  def apply_y(self, axis: int, exponent: float = 1, global_shift: float = 0):
305
305
  if exponent % 0.5 != 0.0:
306
- raise ValueError('Y exponent must be half integer') # coverage: ignore
306
+ raise ValueError('Y exponent must be half integer') # pragma: no cover
307
307
  shift = _phase(exponent, global_shift)
308
308
  if exponent % 2 == 0:
309
309
  self.omega *= shift
@@ -325,7 +325,7 @@ class StabilizerStateChForm(qis.StabilizerState):
325
325
  def apply_z(self, axis: int, exponent: float = 1, global_shift: float = 0):
326
326
  if exponent % 2 != 0:
327
327
  if exponent % 0.5 != 0.0:
328
- raise ValueError('Z exponent must be half integer') # coverage: ignore
328
+ raise ValueError('Z exponent must be half integer') # pragma: no cover
329
329
  effective_exponent = exponent % 2
330
330
  for _ in range(int(effective_exponent * 2)):
331
331
  # Prescription for S left multiplication.
@@ -337,7 +337,7 @@ class StabilizerStateChForm(qis.StabilizerState):
337
337
  def apply_h(self, axis: int, exponent: float = 1, global_shift: float = 0):
338
338
  if exponent % 2 != 0:
339
339
  if exponent % 1 != 0:
340
- raise ValueError('H exponent must be integer') # coverage: ignore
340
+ raise ValueError('H exponent must be integer') # pragma: no cover
341
341
  # Prescription for H left multiplication
342
342
  # Reference: https://arxiv.org/abs/1808.00128
343
343
  # Equations 48, 49 and Proposition 4
@@ -357,7 +357,7 @@ class StabilizerStateChForm(qis.StabilizerState):
357
357
  ):
358
358
  if exponent % 2 != 0:
359
359
  if exponent % 1 != 0:
360
- raise ValueError('CZ exponent must be integer') # coverage: ignore
360
+ raise ValueError('CZ exponent must be integer') # pragma: no cover
361
361
  # Prescription for CZ left multiplication.
362
362
  # Reference: https://arxiv.org/abs/1808.00128 Proposition 4 end
363
363
  self.M[control_axis, :] ^= self.G[target_axis, :]
@@ -369,7 +369,7 @@ class StabilizerStateChForm(qis.StabilizerState):
369
369
  ):
370
370
  if exponent % 2 != 0:
371
371
  if exponent % 1 != 0:
372
- raise ValueError('CX exponent must be integer') # coverage: ignore
372
+ raise ValueError('CX exponent must be integer') # pragma: no cover
373
373
  # Prescription for CX left multiplication.
374
374
  # Reference: https://arxiv.org/abs/1808.00128 Proposition 4 end
375
375
  self.gamma[control_axis] = (
@@ -47,8 +47,7 @@ class _BufferedDensityMatrix(qis.QuantumStateRepresentation):
47
47
  if buffer is None:
48
48
  buffer = [np.empty_like(density_matrix) for _ in range(3)]
49
49
  self._buffer = buffer
50
- if len(density_matrix.shape) % 2 != 0:
51
- # coverage: ignore
50
+ if len(density_matrix.shape) % 2 != 0: # pragma: no cover
52
51
  raise ValueError('The dimension of target_tensor is not divisible by 2.')
53
52
  self._qid_shape = density_matrix.shape[: len(density_matrix.shape) // 2]
54
53
 
@@ -86,7 +85,7 @@ class _BufferedDensityMatrix(qis.QuantumStateRepresentation):
86
85
  initial_state, len(qid_shape), qid_shape=qid_shape, dtype=dtype
87
86
  ).reshape(qid_shape * 2)
88
87
  else:
89
- density_matrix = initial_state # coverage: ignore
88
+ density_matrix = initial_state # pragma: no cover
90
89
  if np.may_share_memory(density_matrix, initial_state):
91
90
  density_matrix = density_matrix.copy()
92
91
  density_matrix = density_matrix.astype(dtype, copy=False)
@@ -286,6 +285,22 @@ class DensityMatrixSimulationState(SimulationState[_BufferedDensityMatrix]):
286
285
  )
287
286
  super().__init__(state=state, prng=prng, qubits=qubits, classical_data=classical_data)
288
287
 
288
+ def add_qubits(self, qubits: Sequence['cirq.Qid']):
289
+ ret = super().add_qubits(qubits)
290
+ return (
291
+ self.kronecker_product(type(self)(qubits=qubits), inplace=True)
292
+ if ret is NotImplemented
293
+ else ret
294
+ )
295
+
296
+ def remove_qubits(self, qubits: Sequence['cirq.Qid']):
297
+ ret = super().remove_qubits(qubits)
298
+ if ret is not NotImplemented:
299
+ return ret
300
+ extracted, remainder = self.factor(qubits, inplace=True)
301
+ remainder._state._density_matrix *= extracted._state._density_matrix.reshape(-1)[0]
302
+ return remainder
303
+
289
304
  def _act_on_fallback_(
290
305
  self, action: Any, qubits: Sequence['cirq.Qid'], allow_decompose: bool = True
291
306
  ) -> bool:
@@ -299,7 +314,7 @@ class DensityMatrixSimulationState(SimulationState[_BufferedDensityMatrix]):
299
314
  for strat in strats:
300
315
  result = strat(action, self, qubits)
301
316
  if result is False:
302
- break # coverage: ignore
317
+ break # pragma: no cover
303
318
  if result is True:
304
319
  return True
305
320
  assert result is NotImplemented, str(result)
@@ -139,8 +139,7 @@ def test_run_not_channel_op(dtype: Type[np.complexfloating], split: bool):
139
139
  def qubits(self):
140
140
  return self._qubits
141
141
 
142
- def with_qubits(self, *new_qubits):
143
- # coverage: ignore
142
+ def with_qubits(self, *new_qubits): # pragma: no cover
144
143
  return BadOp(self._qubits)
145
144
 
146
145
  q0 = cirq.LineQubit(0)
@@ -1050,39 +1049,32 @@ def test_density_matrix_trial_result_repr():
1050
1049
 
1051
1050
  class XAsOp(cirq.Operation):
1052
1051
  def __init__(self, q):
1053
- # coverage: ignore
1054
- self.q = q
1052
+ self.q = q # pragma: no cover
1055
1053
 
1056
1054
  @property
1057
1055
  def qubits(self):
1058
- # coverage: ignore
1059
- return (self.q,)
1056
+ return (self.q,) # pragma: no cover
1060
1057
 
1061
1058
  def with_qubits(self, *new_qubits):
1062
- # coverage: ignore
1063
- return XAsOp(new_qubits[0])
1059
+ return XAsOp(new_qubits[0]) # pragma: no cover
1064
1060
 
1065
1061
  def _kraus_(self):
1066
- # coverage: ignore
1067
- return cirq.kraus(cirq.X)
1062
+ return cirq.kraus(cirq.X) # pragma: no cover
1068
1063
 
1069
1064
 
1070
1065
  def test_works_on_operation():
1071
1066
  class XAsOp(cirq.Operation):
1072
1067
  def __init__(self, q):
1073
- # coverage: ignore
1074
1068
  self.q = q
1075
1069
 
1076
1070
  @property
1077
1071
  def qubits(self):
1078
- # coverage: ignore
1079
1072
  return (self.q,)
1080
1073
 
1081
1074
  def with_qubits(self, *new_qubits):
1082
1075
  raise NotImplementedError()
1083
1076
 
1084
1077
  def _kraus_(self):
1085
- # coverage: ignore
1086
1078
  return cirq.kraus(cirq.X)
1087
1079
 
1088
1080
  s = cirq.DensityMatrixSimulator()