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,123 @@
1
+ # Copyright 2021 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import numpy as np
16
+
17
+
18
+ # TODO: expose all from top-level cirq?
19
+ def decay_constant_to_xeb_fidelity(decay_constant: float, num_qubits: int = 2) -> float:
20
+ """Calculates the XEB fidelity from the depolarization decay constant.
21
+
22
+ Args:
23
+ decay_constant: Depolarization decay constant.
24
+ num_qubits: Number of qubits.
25
+
26
+ Returns:
27
+ Calculated XEB fidelity.
28
+ """
29
+ N = 2**num_qubits
30
+ return 1 - ((1 - decay_constant) * (1 - 1 / N))
31
+
32
+
33
+ def decay_constant_to_pauli_error(decay_constant: float, num_qubits: int = 1) -> float:
34
+ """Calculates pauli error from the depolarization decay constant.
35
+
36
+ Args:
37
+ decay_constant: Depolarization decay constant.
38
+ num_qubits: Number of qubits.
39
+
40
+ Returns:
41
+ Calculated Pauli error.
42
+ """
43
+ N = 2**num_qubits
44
+ return (1 - decay_constant) * (1 - 1 / N / N)
45
+
46
+
47
+ def pauli_error_to_decay_constant(pauli_error: float, num_qubits: int = 1) -> float:
48
+ """Calculates depolarization decay constant from pauli error.
49
+
50
+ Args:
51
+ pauli_error: The pauli error.
52
+ num_qubits: Number of qubits.
53
+
54
+ Returns:
55
+ Calculated depolarization decay constant.
56
+ """
57
+ N = 2**num_qubits
58
+ return 1 - (pauli_error / (1 - 1 / N / N))
59
+
60
+
61
+ def xeb_fidelity_to_decay_constant(xeb_fidelity: float, num_qubits: int = 2) -> float:
62
+ """Calculates the depolarization decay constant from XEB fidelity.
63
+
64
+ Args:
65
+ xeb_fidelity: The XEB fidelity.
66
+ num_qubits: Number of qubits.
67
+
68
+ Returns:
69
+ Calculated depolarization decay constant.
70
+ """
71
+ N = 2**num_qubits
72
+ return 1 - (1 - xeb_fidelity) / (1 - 1 / N)
73
+
74
+
75
+ def pauli_error_from_t1(t_ns: float, t1_ns: float) -> float:
76
+ """Calculates the pauli error from T1 decay constant.
77
+
78
+ This computes error for a specific duration, `t`.
79
+
80
+ Args:
81
+ t_ns: The duration of the gate in ns.
82
+ t1_ns: The T1 decay constant in ns.
83
+
84
+ Returns:
85
+ Calculated Pauli error resulting from T1 decay.
86
+ """
87
+ t2 = 2 * t1_ns
88
+ return (1 - np.exp(-t_ns / t2)) / 2 + (1 - np.exp(-t_ns / t1_ns)) / 4
89
+
90
+
91
+ def average_error(decay_constant: float, num_qubits: int = 1) -> float:
92
+ """Calculates the average error from the depolarization decay constant.
93
+
94
+ Args:
95
+ decay_constant: Depolarization decay constant.
96
+ num_qubits: Number of qubits.
97
+
98
+ Returns:
99
+ Calculated average error.
100
+ """
101
+ N = 2**num_qubits
102
+ return (1 - decay_constant) * (1 - 1 / N)
103
+
104
+
105
+ def decoherence_pauli_error(t1_ns: float, tphi_ns: float, gate_time_ns: float) -> float:
106
+ """The component of Pauli error caused by decoherence on a single qubit.
107
+
108
+ Args:
109
+ t1_ns: T1 time in nanoseconds.
110
+ tphi_ns: Tphi time in nanoseconds.
111
+ gate_time_ns: Duration in nanoseconds of the gate affected by this error.
112
+
113
+ Returns:
114
+ Calculated Pauli error resulting from decoherence.
115
+ """
116
+ gamma_2 = (1 / (2 * t1_ns)) + 1 / tphi_ns
117
+
118
+ exp1 = np.exp(-gate_time_ns / t1_ns)
119
+ exp2 = np.exp(-gate_time_ns * gamma_2)
120
+ px = 0.25 * (1 - exp1)
121
+ py = px
122
+ pz = 0.5 * (1 - exp2) - px
123
+ return px + py + pz
@@ -0,0 +1,97 @@
1
+ # Copyright 2021 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import numpy as np
16
+ import pytest
17
+
18
+ from cirq.qis.noise_utils import (
19
+ decay_constant_to_xeb_fidelity,
20
+ decay_constant_to_pauli_error,
21
+ pauli_error_to_decay_constant,
22
+ xeb_fidelity_to_decay_constant,
23
+ pauli_error_from_t1,
24
+ average_error,
25
+ decoherence_pauli_error,
26
+ )
27
+
28
+
29
+ @pytest.mark.parametrize(
30
+ 'decay_constant,num_qubits,expected_output',
31
+ [(0.01, 1, 1 - (0.99 * 1 / 2)), (0.05, 2, 1 - (0.95 * 3 / 4))],
32
+ )
33
+ def test_decay_constant_to_xeb_fidelity(decay_constant, num_qubits, expected_output):
34
+ val = decay_constant_to_xeb_fidelity(decay_constant, num_qubits)
35
+ assert val == expected_output
36
+
37
+
38
+ @pytest.mark.parametrize(
39
+ 'decay_constant,num_qubits,expected_output',
40
+ [(0.01, 1, 0.99 * 3 / 4), (0.05, 2, 0.95 * 15 / 16)],
41
+ )
42
+ def test_decay_constant_to_pauli_error(decay_constant, num_qubits, expected_output):
43
+ val = decay_constant_to_pauli_error(decay_constant, num_qubits)
44
+ assert val == expected_output
45
+
46
+
47
+ @pytest.mark.parametrize(
48
+ 'pauli_error,num_qubits,expected_output',
49
+ [(0.01, 1, 1 - (0.01 / (3 / 4))), (0.05, 2, 1 - (0.05 / (15 / 16)))],
50
+ )
51
+ def test_pauli_error_to_decay_constant(pauli_error, num_qubits, expected_output):
52
+ val = pauli_error_to_decay_constant(pauli_error, num_qubits)
53
+ assert val == expected_output
54
+
55
+
56
+ @pytest.mark.parametrize(
57
+ 'xeb_fidelity,num_qubits,expected_output',
58
+ [(0.01, 1, 1 - 0.99 / (1 / 2)), (0.05, 2, 1 - 0.95 / (3 / 4))],
59
+ )
60
+ def test_xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits, expected_output):
61
+ val = xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits)
62
+ assert val == expected_output
63
+
64
+
65
+ @pytest.mark.parametrize(
66
+ 't,t1_ns,expected_output',
67
+ [
68
+ (20, 1e5, (1 - np.exp(-20 / 2e5)) / 2 + (1 - np.exp(-20 / 1e5)) / 4),
69
+ (4000, 1e4, (1 - np.exp(-4000 / 2e4)) / 2 + (1 - np.exp(-4000 / 1e4)) / 4),
70
+ ],
71
+ )
72
+ def test_pauli_error_from_t1(t, t1_ns, expected_output):
73
+ val = pauli_error_from_t1(t, t1_ns)
74
+ assert val == expected_output
75
+
76
+
77
+ @pytest.mark.parametrize(
78
+ 'decay_constant,num_qubits,expected_output', [(0.01, 1, 0.99 * 1 / 2), (0.05, 2, 0.95 * 3 / 4)]
79
+ )
80
+ def test_average_error(decay_constant, num_qubits, expected_output):
81
+ val = average_error(decay_constant, num_qubits)
82
+ assert val == expected_output
83
+
84
+
85
+ @pytest.mark.parametrize(
86
+ 'T1_ns,Tphi_ns,gate_time_ns', [(1e4, 2e4, 25), (1e5, 2e3, 25), (1e4, 2e4, 4000)]
87
+ )
88
+ def test_decoherence_pauli_error(T1_ns, Tphi_ns, gate_time_ns):
89
+ val = decoherence_pauli_error(T1_ns, Tphi_ns, gate_time_ns)
90
+ # Expected value is of the form:
91
+ #
92
+ # (1/4) * [1 - e^(-t/T1)] + (1/2) * [1 - e^(-t/(2*T1) - t/Tphi]
93
+ #
94
+ expected_output = 0.25 * (1 - np.exp(-gate_time_ns / T1_ns)) + 0.5 * (
95
+ 1 - np.exp(-gate_time_ns * ((1 / (2 * T1_ns)) + 1 / Tphi_ns))
96
+ )
97
+ assert val == expected_output
@@ -12,96 +12,236 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
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
15
+
16
+ from typing import Dict, Generic, Any, Sequence, List, Optional, Union, TYPE_CHECKING
17
+ from copy import deepcopy, copy
18
+ from cirq import ops, qis
19
+ from cirq.value import big_endian_int_to_bits
20
+ from cirq import sim
21
+ from cirq.sim.simulation_state import TSimulationState, SimulationState
22
22
  import numpy as np
23
23
 
24
+ if TYPE_CHECKING:
25
+ import cirq
26
+
24
27
 
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
+ def _is_identity(action) -> bool:
29
+ """Check if the given action is equivalent to an identity."""
30
+ gate = action.gate if isinstance(action, ops.Operation) else action
31
+ if isinstance(gate, (ops.XPowGate, ops.CXPowGate, ops.CCXPowGate, ops.SwapPowGate)):
32
+ return gate.exponent % 2 == 0
28
33
  return False
29
34
 
30
35
 
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
36
+ class ClassicalBasisState(qis.QuantumStateRepresentation):
37
+ """Represents a classical basis state for efficient state evolution."""
38
+
39
+ def __init__(self, initial_state: Union[List[int], np.ndarray]):
40
+ """Initializes the ClassicalBasisState object.
41
+
42
+ Args:
43
+ initial_state: The initial state in the computational basis.
44
+ """
45
+ self.basis = initial_state
46
+
47
+ def copy(self, deep_copy_buffers: bool = True) -> 'ClassicalBasisState':
48
+ """Creates a copy of the ClassicalBasisState object.
49
+
50
+ Args:
51
+ deep_copy_buffers: Whether to deep copy the internal buffers.
52
+ Returns:
53
+ A copy of the ClassicalBasisState object.
54
+ """
55
+ return ClassicalBasisState(
56
+ initial_state=deepcopy(self.basis) if deep_copy_buffers else copy(self.basis)
57
+ )
58
+
59
+ def measure(
60
+ self, axes: Sequence[int], seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None
61
+ ) -> List[int]:
62
+ """Measures the density matrix.
63
+
64
+ Args:
65
+ axes: The axes to measure.
66
+ seed: The random number seed to use.
67
+ Returns:
68
+ The measurements in order.
69
+ """
70
+ return [self.basis[i] for i in axes]
71
+
72
+
73
+ class ClassicalBasisSimState(SimulationState[ClassicalBasisState]):
74
+ """Represents the state of a quantum simulation using classical basis states."""
75
+
76
+ def __init__(
77
+ self,
78
+ initial_state: Union[int, List[int]] = 0,
79
+ qubits: Optional[Sequence['cirq.Qid']] = None,
80
+ classical_data: Optional['cirq.ClassicalDataStore'] = None,
81
+ ):
82
+ """Initializes the ClassicalBasisSimState object.
83
+
84
+ Args:
85
+ qubits: The qubits to simulate.
86
+ initial_state: The initial state for the simulation.
87
+ classical_data: The classical data container for the simulation.
88
+
89
+ Raises:
90
+ ValueError: If qubits not provided and initial_state is int.
91
+ If initial_state is not an int, List[int], or np.ndarray.
92
+
93
+ An initial_state value of type integer is parsed in big endian order.
94
+ """
95
+ if isinstance(initial_state, int):
96
+ if qubits is None:
97
+ raise ValueError('qubits must be provided if initial_state is not List[int]')
98
+ state = ClassicalBasisState(
99
+ big_endian_int_to_bits(initial_state, bit_count=len(qubits))
100
+ )
101
+ elif isinstance(initial_state, (list, np.ndarray)):
102
+ state = ClassicalBasisState(initial_state)
103
+ else:
104
+ raise ValueError('initial_state must be an int or List[int] or np.ndarray')
105
+ super().__init__(state=state, qubits=qubits, classical_data=classical_data)
106
+
107
+ def _act_on_fallback_(self, action, qubits: Sequence['cirq.Qid'], allow_decompose: bool = True):
108
+ """Acts on the state with a given operation.
109
+
110
+ Args:
111
+ action: The operation to apply.
112
+ qubits: The qubits to apply the operation to.
113
+ allow_decompose: Whether to allow decomposition of the operation.
114
+
115
+ Returns:
116
+ True if the operation was applied successfully.
117
+
118
+ Raises:
119
+ ValueError: If initial_state shape for type np.ndarray is not equal to 1.
120
+ If gate is not one of X, SWAP, a controlled version of X or SWAP,
121
+ or a measurement.
122
+ """
123
+ if isinstance(self._state.basis, np.ndarray) and len(self._state.basis.shape) != 1:
124
+ raise ValueError('initial_state shape for type np.ndarray is not equal to 1')
125
+ gate = action.gate if isinstance(action, ops.Operation) else action
126
+ mapped_qubits = [self.qubit_map[i] for i in qubits]
127
+
128
+ if isinstance(gate, ops.ControlledGate):
129
+ control_qubits = mapped_qubits[: gate.num_controls()]
130
+ mapped_qubits = mapped_qubits[gate.num_controls() :]
131
+
132
+ controls_state = tuple(self._state.basis[c] for c in control_qubits)
133
+ if controls_state not in gate.control_values.expand():
134
+ # gate has no effect; controls were off
135
+ return True
136
+
137
+ gate = gate.sub_gate
138
+
139
+ if _is_identity(gate):
140
+ pass
141
+ elif gate == ops.X:
142
+ (q,) = mapped_qubits
143
+ self._state.basis[q] ^= 1
144
+ elif gate == ops.CNOT:
145
+ c, q = mapped_qubits
146
+ self._state.basis[q] ^= self._state.basis[c]
147
+ elif gate == ops.SWAP:
148
+ a, b = mapped_qubits
149
+ self._state.basis[a], self._state.basis[b] = self._state.basis[b], self._state.basis[a]
150
+ elif gate == ops.TOFFOLI:
151
+ c1, c2, q = mapped_qubits
152
+ self._state.basis[q] ^= self._state.basis[c1] & self._state.basis[c2]
153
+ else:
154
+ raise ValueError(
155
+ f'{gate} is not one of X, SWAP; a controlled version '
156
+ 'of X or SWAP; or a measurement'
157
+ )
158
+ return True
159
+
160
+
161
+ class ClassicalStateStepResult(
162
+ sim.StepResultBase['ClassicalBasisSimState'], Generic[TSimulationState]
163
+ ):
164
+ """The step result provided by `ClassicalStateSimulator.simulate_moment_steps`."""
165
+
166
+
167
+ class ClassicalStateTrialResult(
168
+ sim.SimulationTrialResultBase['ClassicalBasisSimState'], Generic[TSimulationState]
169
+ ):
170
+ """The trial result provided by `ClassicalStateSimulator.simulate`."""
171
+
172
+
173
+ class ClassicalStateSimulator(
174
+ sim.SimulatorBase[
175
+ ClassicalStateStepResult['ClassicalBasisSimState'],
176
+ ClassicalStateTrialResult['ClassicalBasisSimState'],
177
+ 'ClassicalBasisSimState',
178
+ ],
179
+ Generic[TSimulationState],
180
+ ):
181
+ """A simulator that accepts only gates with classical counterparts."""
182
+
183
+ def __init__(
184
+ self, *, noise: 'cirq.NOISE_MODEL_LIKE' = None, split_untangled_states: bool = False
185
+ ):
186
+ """Initializes a ClassicalStateSimulator.
187
+
188
+ Args:
189
+ noise: The noise model used by the simulator.
190
+ split_untangled_states: Whether to run the simulation as a product state.
191
+
192
+ Raises:
193
+ ValueError: If noise_model is not None.
194
+ """
195
+ if noise is not None:
196
+ raise ValueError(f'{noise=} is not supported')
197
+ super().__init__(noise=noise, split_untangled_states=split_untangled_states)
198
+
199
+ def _create_simulator_trial_result(
200
+ self,
201
+ params: 'cirq.ParamResolver',
202
+ measurements: Dict[str, np.ndarray],
203
+ final_simulator_state: 'cirq.SimulationStateBase[ClassicalBasisSimState]',
204
+ ) -> 'ClassicalStateTrialResult[ClassicalBasisSimState]':
205
+ """Creates a trial result for the simulator.
206
+
207
+ Args:
208
+ params: The parameter resolver for the simulation.
209
+ measurements: The measurement results.
210
+ final_simulator_state: The final state of the simulator.
211
+ Returns:
212
+ A trial result for the simulator.
213
+ """
214
+ return ClassicalStateTrialResult(
215
+ params, measurements, final_simulator_state=final_simulator_state
216
+ )
217
+
218
+ def _create_step_result(
219
+ self, sim_state: 'cirq.SimulationStateBase[ClassicalBasisSimState]'
220
+ ) -> 'ClassicalStateStepResult[ClassicalBasisSimState]':
221
+ """Creates a step result for the simulator.
222
+
223
+ Args:
224
+ sim_state: The current state of the simulator.
225
+ Returns:
226
+ A step result for the simulator.
227
+ """
228
+ return ClassicalStateStepResult(sim_state)
229
+
230
+ def _create_partial_simulation_state(
231
+ self,
232
+ initial_state: Any,
233
+ qubits: Sequence['cirq.Qid'],
234
+ classical_data: 'cirq.ClassicalDataStore',
235
+ ) -> 'ClassicalBasisSimState':
236
+ """Creates a partial simulation state for the simulator.
237
+
238
+ Args:
239
+ initial_state: The initial state for the simulation.
240
+ qubits: The qubits associated with the state.
241
+ classical_data: The shared classical data container for this simulation.
242
+ Returns:
243
+ A partial simulation state.
244
+ """
245
+ return ClassicalBasisSimState(
246
+ initial_state=initial_state, qubits=qubits, classical_data=classical_data
247
+ )