cirq-core 1.1.0.dev20221220224914__py3-none-any.whl → 1.2.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.
- cirq/__init__.py +8 -0
- cirq/_compat.py +29 -4
- cirq/_compat_test.py +24 -26
- cirq/_version.py +32 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/_block_diagram_drawer_test.py +4 -3
- cirq/circuits/circuit.py +109 -63
- cirq/circuits/circuit_operation.py +2 -3
- cirq/circuits/circuit_operation_test.py +4 -4
- cirq/circuits/circuit_test.py +11 -0
- cirq/circuits/frozen_circuit.py +13 -1
- cirq/circuits/frozen_circuit_test.py +5 -1
- cirq/circuits/moment.py +39 -14
- cirq/circuits/moment_test.py +7 -0
- cirq/circuits/text_diagram_drawer.py +1 -1
- cirq/circuits/text_diagram_drawer_test.py +3 -7
- cirq/contrib/acquaintance/bipartite.py +1 -1
- cirq/contrib/acquaintance/devices.py +2 -2
- cirq/contrib/acquaintance/executor.py +5 -2
- cirq/contrib/acquaintance/gates.py +3 -2
- cirq/contrib/acquaintance/permutation.py +13 -2
- cirq/contrib/acquaintance/testing.py +3 -5
- cirq/contrib/paulistring/recombine.py +3 -6
- cirq/contrib/qasm_import/_parser.py +17 -21
- cirq/contrib/qasm_import/_parser_test.py +30 -45
- cirq/contrib/qcircuit/qcircuit_test.py +3 -7
- cirq/contrib/quantum_volume/quantum_volume.py +3 -3
- cirq/contrib/quimb/mps_simulator.py +1 -1
- cirq/contrib/quimb/state_vector.py +2 -0
- cirq/contrib/quirk/quirk_gate.py +1 -0
- cirq/contrib/svg/svg.py +4 -7
- cirq/contrib/svg/svg_test.py +29 -1
- cirq/devices/grid_qubit.py +26 -28
- cirq/devices/grid_qubit_test.py +21 -5
- cirq/devices/line_qubit.py +10 -12
- cirq/devices/line_qubit_test.py +9 -2
- cirq/devices/named_topologies.py +1 -1
- cirq/devices/noise_model.py +4 -1
- cirq/devices/superconducting_qubits_noise_properties.py +1 -3
- cirq/experiments/n_qubit_tomography.py +1 -1
- cirq/experiments/qubit_characterizations.py +2 -2
- cirq/experiments/single_qubit_readout_calibration.py +1 -1
- cirq/experiments/t2_decay_experiment.py +1 -1
- cirq/experiments/xeb_simulation_test.py +2 -2
- cirq/interop/quirk/cells/testing.py +1 -1
- cirq/json_resolver_cache.py +1 -0
- cirq/linalg/__init__.py +2 -0
- cirq/linalg/decompositions_test.py +4 -4
- cirq/linalg/diagonalize_test.py +5 -6
- cirq/linalg/transformations.py +72 -9
- cirq/linalg/transformations_test.py +23 -7
- cirq/ops/__init__.py +4 -0
- cirq/ops/arithmetic_operation.py +4 -6
- cirq/ops/classically_controlled_operation.py +10 -3
- cirq/ops/clifford_gate.py +1 -7
- cirq/ops/common_channels.py +21 -15
- cirq/ops/common_gate_families.py +2 -3
- cirq/ops/common_gates.py +48 -11
- cirq/ops/common_gates_test.py +4 -0
- cirq/ops/controlled_gate.py +44 -18
- cirq/ops/controlled_operation.py +13 -5
- cirq/ops/dense_pauli_string.py +14 -19
- cirq/ops/diagonal_gate.py +3 -4
- cirq/ops/eigen_gate.py +8 -10
- cirq/ops/eigen_gate_test.py +6 -0
- cirq/ops/gate_operation.py +11 -6
- cirq/ops/gate_operation_test.py +11 -2
- cirq/ops/gateset.py +2 -1
- cirq/ops/gateset_test.py +38 -5
- cirq/ops/global_phase_op.py +28 -2
- cirq/ops/global_phase_op_test.py +21 -0
- cirq/ops/identity.py +1 -1
- cirq/ops/kraus_channel_test.py +2 -2
- cirq/ops/linear_combinations.py +7 -6
- cirq/ops/linear_combinations_test.py +26 -10
- cirq/ops/matrix_gates.py +8 -4
- cirq/ops/matrix_gates_test.py +25 -3
- cirq/ops/measure_util.py +13 -5
- cirq/ops/measure_util_test.py +8 -2
- cirq/ops/measurement_gate.py +1 -1
- cirq/ops/measurement_gate_test.py +9 -4
- cirq/ops/mixed_unitary_channel_test.py +4 -4
- cirq/ops/named_qubit.py +2 -4
- cirq/ops/parity_gates.py +5 -1
- cirq/ops/parity_gates_test.py +6 -0
- cirq/ops/pauli_gates.py +9 -9
- cirq/ops/pauli_string.py +4 -2
- cirq/ops/pauli_string_raw_types.py +4 -11
- cirq/ops/pauli_string_test.py +13 -13
- cirq/ops/pauli_sum_exponential.py +6 -1
- cirq/ops/qubit_manager.py +97 -0
- cirq/ops/qubit_manager_test.py +66 -0
- cirq/ops/raw_types.py +75 -33
- cirq/ops/raw_types_test.py +34 -0
- cirq/ops/three_qubit_gates.py +16 -10
- cirq/ops/three_qubit_gates_test.py +4 -2
- cirq/ops/two_qubit_diagonal_gate.py +3 -3
- cirq/ops/wait_gate.py +1 -1
- cirq/protocols/__init__.py +1 -0
- cirq/protocols/act_on_protocol.py +3 -3
- cirq/protocols/act_on_protocol_test.py +5 -5
- cirq/protocols/apply_channel_protocol.py +9 -8
- cirq/protocols/apply_mixture_protocol.py +8 -8
- cirq/protocols/apply_mixture_protocol_test.py +1 -1
- cirq/protocols/apply_unitary_protocol.py +66 -19
- cirq/protocols/apply_unitary_protocol_test.py +50 -0
- cirq/protocols/circuit_diagram_info_protocol.py +7 -9
- cirq/protocols/decompose_protocol.py +167 -125
- cirq/protocols/decompose_protocol_test.py +132 -2
- cirq/protocols/has_stabilizer_effect_protocol.py +2 -1
- cirq/protocols/inverse_protocol.py +2 -2
- cirq/protocols/json_serialization_test.py +3 -3
- cirq/protocols/json_test_data/Linspace.json +20 -7
- cirq/protocols/json_test_data/Linspace.repr +4 -1
- cirq/protocols/json_test_data/Points.json +19 -8
- cirq/protocols/json_test_data/Points.repr +4 -1
- cirq/protocols/json_test_data/Result.repr_inward +1 -1
- cirq/protocols/json_test_data/ResultDict.repr +1 -1
- cirq/protocols/json_test_data/ResultDict.repr_inward +1 -1
- cirq/protocols/json_test_data/TrialResult.repr_inward +1 -1
- cirq/protocols/json_test_data/XPowGate.json +13 -5
- cirq/protocols/json_test_data/XPowGate.repr +1 -1
- cirq/protocols/json_test_data/ZPowGate.json +13 -5
- cirq/protocols/json_test_data/ZPowGate.repr +1 -1
- cirq/protocols/json_test_data/ZipLongest.json +19 -0
- cirq/protocols/json_test_data/ZipLongest.repr +1 -0
- cirq/protocols/json_test_data/spec.py +1 -0
- cirq/protocols/kraus_protocol.py +3 -4
- cirq/protocols/measurement_key_protocol.py +3 -1
- cirq/protocols/mixture_protocol.py +3 -2
- cirq/protocols/phase_protocol.py +3 -3
- cirq/protocols/pow_protocol.py +1 -2
- cirq/protocols/qasm.py +4 -4
- cirq/protocols/qid_shape_protocol.py +8 -8
- cirq/protocols/resolve_parameters.py +8 -3
- cirq/protocols/resolve_parameters_test.py +3 -3
- cirq/protocols/unitary_protocol.py +19 -11
- cirq/protocols/unitary_protocol_test.py +37 -0
- cirq/qis/channels.py +1 -1
- cirq/qis/clifford_tableau.py +4 -5
- cirq/qis/quantum_state_representation.py +7 -9
- cirq/qis/states.py +21 -13
- cirq/qis/states_test.py +7 -0
- cirq/sim/clifford/clifford_simulator.py +3 -3
- cirq/sim/density_matrix_simulation_state.py +2 -1
- cirq/sim/density_matrix_simulator.py +1 -1
- cirq/sim/density_matrix_simulator_test.py +9 -5
- cirq/sim/density_matrix_utils.py +7 -32
- cirq/sim/mux.py +2 -2
- cirq/sim/simulation_state.py +58 -18
- cirq/sim/simulation_state_base.py +5 -2
- cirq/sim/simulation_state_test.py +121 -9
- cirq/sim/simulation_utils.py +59 -0
- cirq/sim/simulation_utils_test.py +32 -0
- cirq/sim/simulator.py +2 -1
- cirq/sim/simulator_base_test.py +3 -3
- cirq/sim/sparse_simulator.py +1 -1
- cirq/sim/sparse_simulator_test.py +5 -5
- cirq/sim/state_vector.py +7 -36
- cirq/sim/state_vector_simulation_state.py +18 -1
- cirq/sim/state_vector_simulator.py +3 -2
- cirq/sim/state_vector_simulator_test.py +24 -2
- cirq/sim/state_vector_test.py +46 -15
- cirq/study/__init__.py +1 -0
- cirq/study/flatten_expressions.py +2 -2
- cirq/study/resolver.py +2 -0
- cirq/study/resolver_test.py +1 -1
- cirq/study/result.py +1 -1
- cirq/study/sweeps.py +103 -9
- cirq/study/sweeps_test.py +64 -0
- cirq/testing/__init__.py +4 -0
- cirq/testing/circuit_compare.py +15 -18
- cirq/testing/consistent_act_on.py +4 -4
- cirq/testing/consistent_controlled_gate_op_test.py +1 -1
- cirq/testing/consistent_decomposition.py +11 -2
- cirq/testing/consistent_decomposition_test.py +8 -1
- cirq/testing/consistent_protocols.py +2 -0
- cirq/testing/consistent_protocols_test.py +8 -4
- cirq/testing/consistent_qasm.py +8 -15
- cirq/testing/consistent_specified_has_unitary.py +1 -1
- cirq/testing/consistent_unitary.py +85 -0
- cirq/testing/consistent_unitary_test.py +96 -0
- cirq/testing/equivalent_repr_eval.py +10 -10
- cirq/testing/json.py +3 -3
- cirq/testing/logs.py +1 -1
- cirq/testing/order_tester.py +4 -5
- cirq/testing/random_circuit.py +3 -5
- cirq/testing/sample_gates.py +79 -0
- cirq/testing/sample_gates_test.py +59 -0
- cirq/transformers/__init__.py +2 -0
- cirq/transformers/analytical_decompositions/__init__.py +8 -0
- cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +130 -0
- cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +58 -0
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +230 -0
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +112 -0
- cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -3
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
- cirq/transformers/expand_composite.py +1 -1
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +4 -4
- cirq/transformers/measurement_transformers.py +4 -4
- cirq/transformers/merge_single_qubit_gates.py +17 -4
- cirq/transformers/routing/route_circuit_cqc.py +2 -2
- cirq/transformers/stratify.py +125 -62
- cirq/transformers/stratify_test.py +20 -16
- cirq/transformers/transformer_api.py +1 -1
- cirq/transformers/transformer_primitives.py +3 -2
- cirq/transformers/transformer_primitives_test.py +11 -0
- cirq/value/abc_alt.py +3 -2
- cirq/value/abc_alt_test.py +1 -0
- cirq/value/classical_data.py +10 -10
- cirq/value/digits.py +2 -2
- cirq/value/linear_dict.py +18 -19
- cirq/value/product_state.py +7 -6
- cirq/value/value_equality_attr.py +2 -2
- cirq/vis/heatmap.py +1 -1
- cirq/vis/heatmap_test.py +2 -2
- cirq/work/collector.py +2 -2
- cirq/work/observable_measurement_data.py +5 -5
- cirq/work/observable_readout_calibration.py +3 -1
- cirq/work/observable_settings.py +1 -1
- cirq/work/pauli_sum_collector.py +9 -8
- cirq/work/sampler.py +2 -0
- cirq/work/zeros_sampler.py +2 -2
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/RECORD +228 -214
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
cirq/qis/states_test.py
CHANGED
|
@@ -475,6 +475,13 @@ def test_dirac_notation_precision():
|
|
|
475
475
|
assert_dirac_notation_python([sqrt, sqrt], "0.707|0⟩ + 0.707|1⟩", decimals=3)
|
|
476
476
|
|
|
477
477
|
|
|
478
|
+
def test_dirac_notation_invalid():
|
|
479
|
+
with pytest.raises(ValueError, match='state_vector has incorrect size'):
|
|
480
|
+
_ = cirq.dirac_notation([0.0, 0.0, 1.0])
|
|
481
|
+
with pytest.raises(ValueError, match='state_vector has incorrect size'):
|
|
482
|
+
_ = cirq.dirac_notation([1.0, 1.0], qid_shape=(3,))
|
|
483
|
+
|
|
484
|
+
|
|
478
485
|
def test_to_valid_state_vector():
|
|
479
486
|
with pytest.raises(ValueError, match='Computational basis state is out of range'):
|
|
480
487
|
cirq.to_valid_state_vector(2, 1)
|
|
@@ -11,6 +11,7 @@
|
|
|
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
|
+
|
|
14
15
|
"""An efficient simulator for Clifford circuits.
|
|
15
16
|
|
|
16
17
|
Allowed operations include:
|
|
@@ -109,7 +110,6 @@ class CliffordSimulator(
|
|
|
109
110
|
measurements: Dict[str, np.ndarray],
|
|
110
111
|
final_simulator_state: 'cirq.SimulationStateBase[cirq.StabilizerChFormSimulationState]',
|
|
111
112
|
):
|
|
112
|
-
|
|
113
113
|
return CliffordTrialResult(
|
|
114
114
|
params=params, measurements=measurements, final_simulator_state=final_simulator_state
|
|
115
115
|
)
|
|
@@ -259,8 +259,8 @@ class CliffordState:
|
|
|
259
259
|
):
|
|
260
260
|
if not isinstance(op.gate, cirq.MeasurementGate):
|
|
261
261
|
raise TypeError(
|
|
262
|
-
'apply_measurement only supports cirq.MeasurementGate operations.
|
|
263
|
-
|
|
262
|
+
f'apply_measurement only supports cirq.MeasurementGate operations. '
|
|
263
|
+
f'Found {op.gate} instead.'
|
|
264
264
|
)
|
|
265
265
|
|
|
266
266
|
if collapse_state_vector:
|
|
@@ -11,6 +11,7 @@
|
|
|
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
|
+
|
|
14
15
|
"""Objects and methods for acting efficiently on a density matrix."""
|
|
15
16
|
|
|
16
17
|
from typing import Any, Callable, List, Optional, Sequence, Tuple, Type, TYPE_CHECKING, Union
|
|
@@ -305,7 +306,7 @@ class DensityMatrixSimulationState(SimulationState[_BufferedDensityMatrix]):
|
|
|
305
306
|
raise TypeError(
|
|
306
307
|
"Can't simulate operations that don't implement "
|
|
307
308
|
"SupportsUnitary, SupportsConsistentApplyUnitary, "
|
|
308
|
-
"SupportsMixture or SupportsKraus or is a measurement: {!r}"
|
|
309
|
+
f"SupportsMixture or SupportsKraus or is a measurement: {action!r}"
|
|
309
310
|
)
|
|
310
311
|
|
|
311
312
|
def __repr__(self) -> str:
|
|
@@ -303,7 +303,7 @@ class DensityMatrixStepResult(simulator_base.StepResultBase['cirq.DensityMatrixS
|
|
|
303
303
|
# Dtype doesn't have a good repr, so we work around by invoking __name__.
|
|
304
304
|
return (
|
|
305
305
|
f'cirq.DensityMatrixStepResult(sim_state={self._sim_state!r},'
|
|
306
|
-
f' dtype=np.{self._dtype
|
|
306
|
+
f' dtype=np.{np.dtype(self._dtype)!r})'
|
|
307
307
|
)
|
|
308
308
|
|
|
309
309
|
|
|
@@ -950,10 +950,13 @@ def test_density_matrix_step_result_repr():
|
|
|
950
950
|
)
|
|
951
951
|
)
|
|
952
952
|
)
|
|
953
|
-
== "cirq.DensityMatrixStepResult(
|
|
954
|
-
"
|
|
953
|
+
== "cirq.DensityMatrixStepResult("
|
|
954
|
+
"sim_state=cirq.DensityMatrixSimulationState("
|
|
955
|
+
"initial_state=np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], "
|
|
956
|
+
"dtype=np.dtype('complex64')), "
|
|
955
957
|
"qubits=(cirq.LineQubit(0),), "
|
|
956
|
-
"classical_data=cirq.ClassicalDataDictionaryStore()),
|
|
958
|
+
"classical_data=cirq.ClassicalDataDictionaryStore()), "
|
|
959
|
+
"dtype=np.dtype('complex64'))"
|
|
957
960
|
)
|
|
958
961
|
|
|
959
962
|
|
|
@@ -1034,9 +1037,10 @@ def test_density_matrix_trial_result_repr():
|
|
|
1034
1037
|
expected_repr = (
|
|
1035
1038
|
"cirq.DensityMatrixTrialResult("
|
|
1036
1039
|
"params=cirq.ParamResolver({'s': 1}), "
|
|
1037
|
-
"measurements={'m': np.array([[1]], dtype=np.int32)}, "
|
|
1040
|
+
"measurements={'m': np.array([[1]], dtype=np.dtype('int32'))}, "
|
|
1038
1041
|
"final_simulator_state=cirq.DensityMatrixSimulationState("
|
|
1039
|
-
"initial_state=np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]],
|
|
1042
|
+
"initial_state=np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], "
|
|
1043
|
+
"dtype=np.dtype('complex64')), "
|
|
1040
1044
|
"qubits=(cirq.LineQubit(0),), "
|
|
1041
1045
|
"classical_data=cirq.ClassicalDataDictionaryStore()))"
|
|
1042
1046
|
)
|
cirq/sim/density_matrix_utils.py
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
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
|
+
|
|
14
15
|
"""Code to handle density matrices."""
|
|
15
16
|
|
|
16
17
|
from typing import List, Optional, TYPE_CHECKING, Tuple, Sequence
|
|
@@ -18,6 +19,7 @@ from typing import List, Optional, TYPE_CHECKING, Tuple, Sequence
|
|
|
18
19
|
import numpy as np
|
|
19
20
|
|
|
20
21
|
from cirq import linalg, value
|
|
22
|
+
from cirq.sim import simulation_utils
|
|
21
23
|
|
|
22
24
|
if TYPE_CHECKING:
|
|
23
25
|
import cirq
|
|
@@ -188,33 +190,8 @@ def _probs(
|
|
|
188
190
|
"""Returns the probabilities for a measurement on the given indices."""
|
|
189
191
|
# Only diagonal elements matter.
|
|
190
192
|
all_probs = np.diagonal(np.reshape(density_matrix, (np.prod(qid_shape, dtype=np.int64),) * 2))
|
|
191
|
-
# Shape into a tensor
|
|
192
|
-
tensor = np.reshape(all_probs, qid_shape)
|
|
193
|
-
|
|
194
|
-
# Calculate the probabilities for measuring the particular results.
|
|
195
|
-
if len(indices) == len(qid_shape):
|
|
196
|
-
# We're measuring every qudit, so no need for fancy indexing
|
|
197
|
-
probs = np.abs(tensor)
|
|
198
|
-
probs = np.transpose(probs, indices)
|
|
199
|
-
probs = probs.reshape(-1)
|
|
200
|
-
else:
|
|
201
|
-
# Fancy indexing required
|
|
202
|
-
meas_shape = tuple(qid_shape[i] for i in indices)
|
|
203
|
-
probs = np.abs(
|
|
204
|
-
[
|
|
205
|
-
tensor[
|
|
206
|
-
linalg.slice_for_qubits_equal_to(
|
|
207
|
-
indices, big_endian_qureg_value=b, qid_shape=qid_shape
|
|
208
|
-
)
|
|
209
|
-
]
|
|
210
|
-
for b in range(np.prod(meas_shape, dtype=np.int64))
|
|
211
|
-
]
|
|
212
|
-
)
|
|
213
|
-
probs = np.sum(probs, axis=tuple(range(1, len(probs.shape))))
|
|
214
193
|
|
|
215
|
-
|
|
216
|
-
probs /= np.sum(probs)
|
|
217
|
-
return probs
|
|
194
|
+
return simulation_utils.state_probabilities_by_indices(all_probs.real, indices, qid_shape)
|
|
218
195
|
|
|
219
196
|
|
|
220
197
|
def _validate_density_matrix_qid_shape(
|
|
@@ -227,10 +204,8 @@ def _validate_density_matrix_qid_shape(
|
|
|
227
204
|
if len(shape) == 2:
|
|
228
205
|
if np.prod(qid_shape, dtype=np.int64) ** 2 != np.prod(shape, dtype=np.int64):
|
|
229
206
|
raise ValueError(
|
|
230
|
-
'Matrix size does not match qid shape {!r}. Got matrix with '
|
|
231
|
-
'shape {!r}. Expected {!r}.'
|
|
232
|
-
qid_shape, shape, np.prod(qid_shape, dtype=np.int64)
|
|
233
|
-
)
|
|
207
|
+
f'Matrix size does not match qid shape {qid_shape!r}. Got matrix with '
|
|
208
|
+
f'shape {shape!r}. Expected {np.prod(qid_shape, dtype=np.int64)!r}.'
|
|
234
209
|
)
|
|
235
210
|
return qid_shape
|
|
236
211
|
if len(shape) % 2 != 0:
|
|
@@ -257,12 +232,12 @@ def _validate_num_qubits(density_matrix: np.ndarray) -> int:
|
|
|
257
232
|
if row_size & (row_size - 1):
|
|
258
233
|
raise ValueError(
|
|
259
234
|
'Matrix could not be shaped into a square matrix with dimensions '
|
|
260
|
-
'that are a power of two. Shape was {}'
|
|
235
|
+
f'that are a power of two. Shape was {shape}'
|
|
261
236
|
)
|
|
262
237
|
if len(shape) > 2 and not np.allclose(shape, 2):
|
|
263
238
|
raise ValueError(
|
|
264
239
|
'Matrix is a tensor of rank greater than 2, but had dimensions '
|
|
265
|
-
'that are not powers of two. Shape was {}'
|
|
240
|
+
f'that are not powers of two. Shape was {shape}'
|
|
266
241
|
)
|
|
267
242
|
return int(row_size).bit_length() - 1
|
|
268
243
|
|
cirq/sim/mux.py
CHANGED
|
@@ -139,7 +139,7 @@ def final_state_vector(
|
|
|
139
139
|
Returns:
|
|
140
140
|
The state vector resulting from applying the given unitary operations to
|
|
141
141
|
the desired initial state. Specifically, a numpy array containing the
|
|
142
|
-
|
|
142
|
+
amplitudes in np.kron order, where the order of arguments to kron
|
|
143
143
|
is determined by the qubit order argument (which defaults to just
|
|
144
144
|
sorting the qubits that are present into an ascending order).
|
|
145
145
|
|
|
@@ -160,7 +160,7 @@ def final_state_vector(
|
|
|
160
160
|
"because it is not unitary. "
|
|
161
161
|
"Maybe you wanted `cirq.final_density_matrix`?\n"
|
|
162
162
|
"\n"
|
|
163
|
-
"Program: {!r}"
|
|
163
|
+
f"Program: {circuit_like!r}"
|
|
164
164
|
)
|
|
165
165
|
|
|
166
166
|
result = sparse_simulator.Simulator(dtype=dtype, seed=seed).simulate(
|
cirq/sim/simulation_state.py
CHANGED
|
@@ -23,18 +23,19 @@ from typing import (
|
|
|
23
23
|
List,
|
|
24
24
|
Optional,
|
|
25
25
|
Sequence,
|
|
26
|
+
Set,
|
|
26
27
|
TypeVar,
|
|
27
28
|
TYPE_CHECKING,
|
|
28
29
|
Tuple,
|
|
29
30
|
)
|
|
31
|
+
from typing_extensions import Self
|
|
30
32
|
|
|
31
33
|
import numpy as np
|
|
32
34
|
|
|
33
|
-
from cirq import protocols, value
|
|
34
|
-
|
|
35
|
+
from cirq import ops, protocols, value
|
|
36
|
+
|
|
35
37
|
from cirq.sim.simulation_state_base import SimulationStateBase
|
|
36
38
|
|
|
37
|
-
TSelf = TypeVar('TSelf', bound='SimulationState')
|
|
38
39
|
TState = TypeVar('TState', bound='cirq.QuantumStateRepresentation')
|
|
39
40
|
|
|
40
41
|
if TYPE_CHECKING:
|
|
@@ -146,7 +147,7 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
|
|
|
146
147
|
return self._state.sample(self.get_axes(qubits), repetitions, seed)
|
|
147
148
|
raise NotImplementedError()
|
|
148
149
|
|
|
149
|
-
def copy(self
|
|
150
|
+
def copy(self, deep_copy_buffers: bool = True) -> Self:
|
|
150
151
|
"""Creates a copy of the object.
|
|
151
152
|
|
|
152
153
|
Args:
|
|
@@ -162,11 +163,43 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
|
|
|
162
163
|
args._state = self._state.copy(deep_copy_buffers=deep_copy_buffers)
|
|
163
164
|
return args
|
|
164
165
|
|
|
165
|
-
def create_merged_state(self
|
|
166
|
+
def create_merged_state(self) -> Self:
|
|
166
167
|
"""Creates a final merged state."""
|
|
167
168
|
return self
|
|
168
169
|
|
|
169
|
-
def
|
|
170
|
+
def add_qubits(self: Self, qubits: Sequence['cirq.Qid']) -> Self:
|
|
171
|
+
"""Add `qubits` in the `|0>` state to a new state space and take the kron product.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
qubits: Sequence of qubits to be added.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
NotImplemented: If the subclass does not implement this method.
|
|
178
|
+
Self: A `cirq.SimulationState` with qubits added or `self` if there are no qubits to
|
|
179
|
+
add.
|
|
180
|
+
"""
|
|
181
|
+
if not qubits:
|
|
182
|
+
return self
|
|
183
|
+
return NotImplemented
|
|
184
|
+
|
|
185
|
+
def remove_qubits(self: Self, qubits: Sequence['cirq.Qid']) -> Self:
|
|
186
|
+
"""Remove `qubits` from the state space.
|
|
187
|
+
|
|
188
|
+
The qubits to be removed should be untangled from rest of the system and in the |0> state.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
qubits: Sequence of qubits to be removed.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
NotImplemented: If the subclass does not implement this method.
|
|
195
|
+
Self: A `cirq.SimulationState` with qubits removed or `self` if there are no qubits to
|
|
196
|
+
remove.
|
|
197
|
+
"""
|
|
198
|
+
if not qubits:
|
|
199
|
+
return self
|
|
200
|
+
return NotImplemented
|
|
201
|
+
|
|
202
|
+
def kronecker_product(self, other: Self, *, inplace=False) -> Self:
|
|
170
203
|
"""Joins two state spaces together."""
|
|
171
204
|
args = self if inplace else copy.copy(self)
|
|
172
205
|
args._state = self._state.kron(other._state)
|
|
@@ -174,8 +207,8 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
|
|
|
174
207
|
return args
|
|
175
208
|
|
|
176
209
|
def factor(
|
|
177
|
-
self
|
|
178
|
-
) -> Tuple[
|
|
210
|
+
self, qubits: Sequence['cirq.Qid'], *, validate=True, atol=1e-07, inplace=False
|
|
211
|
+
) -> Tuple[Self, Self]:
|
|
179
212
|
"""Splits two state spaces after a measurement or reset."""
|
|
180
213
|
extracted = copy.copy(self)
|
|
181
214
|
remainder = self if inplace else copy.copy(self)
|
|
@@ -191,9 +224,7 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
|
|
|
191
224
|
"""Subclasses that allow factorization should override this."""
|
|
192
225
|
return self._state.supports_factor if self._state is not None else False
|
|
193
226
|
|
|
194
|
-
def transpose_to_qubit_order(
|
|
195
|
-
self: TSelf, qubits: Sequence['cirq.Qid'], *, inplace=False
|
|
196
|
-
) -> TSelf:
|
|
227
|
+
def transpose_to_qubit_order(self, qubits: Sequence['cirq.Qid'], *, inplace=False) -> Self:
|
|
197
228
|
"""Physically reindexes the state by the new basis.
|
|
198
229
|
|
|
199
230
|
Args:
|
|
@@ -276,7 +307,7 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
|
|
|
276
307
|
args._set_qubits(qubits)
|
|
277
308
|
return args
|
|
278
309
|
|
|
279
|
-
def __getitem__(self
|
|
310
|
+
def __getitem__(self, item: Optional['cirq.Qid']) -> Self:
|
|
280
311
|
if item not in self.qubit_map:
|
|
281
312
|
raise IndexError(f'{item} not in {self.qubits}')
|
|
282
313
|
return self
|
|
@@ -295,14 +326,23 @@ class SimulationState(SimulationStateBase, Generic[TState], metaclass=abc.ABCMet
|
|
|
295
326
|
def strat_act_on_from_apply_decompose(
|
|
296
327
|
val: Any, args: 'cirq.SimulationState', qubits: Sequence['cirq.Qid']
|
|
297
328
|
) -> bool:
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
329
|
+
if isinstance(val, ops.Gate):
|
|
330
|
+
decomposed = protocols.decompose_once_with_qubits(val, qubits, flatten=False, default=None)
|
|
331
|
+
else:
|
|
332
|
+
decomposed = protocols.decompose_once(val, flatten=False, default=None)
|
|
333
|
+
if decomposed is None:
|
|
302
334
|
return NotImplemented
|
|
303
|
-
|
|
304
|
-
|
|
335
|
+
all_ancilla: Set['cirq.Qid'] = set()
|
|
336
|
+
for operation in ops.flatten_to_ops(decomposed):
|
|
337
|
+
curr_ancilla = tuple(q for q in operation.qubits if q not in args.qubits)
|
|
338
|
+
args = args.add_qubits(curr_ancilla)
|
|
339
|
+
if args is NotImplemented:
|
|
340
|
+
return NotImplemented
|
|
341
|
+
all_ancilla.update(curr_ancilla)
|
|
305
342
|
protocols.act_on(operation, args)
|
|
343
|
+
args = args.remove_qubits(tuple(all_ancilla))
|
|
344
|
+
if args is NotImplemented:
|
|
345
|
+
raise TypeError(f"{type(args)} implements add_qubits but not remove_qubits.")
|
|
306
346
|
return True
|
|
307
347
|
|
|
308
348
|
|
|
@@ -27,6 +27,7 @@ from typing import (
|
|
|
27
27
|
TypeVar,
|
|
28
28
|
Union,
|
|
29
29
|
)
|
|
30
|
+
from typing_extensions import Self
|
|
30
31
|
|
|
31
32
|
import numpy as np
|
|
32
33
|
|
|
@@ -37,7 +38,6 @@ if TYPE_CHECKING:
|
|
|
37
38
|
import cirq
|
|
38
39
|
|
|
39
40
|
|
|
40
|
-
TSelfTarget = TypeVar('TSelfTarget', bound='SimulationStateBase')
|
|
41
41
|
TSimulationState = TypeVar('TSimulationState', bound='cirq.SimulationState')
|
|
42
42
|
|
|
43
43
|
|
|
@@ -98,7 +98,7 @@ class SimulationStateBase(Generic[TSimulationState], metaclass=abc.ABCMeta):
|
|
|
98
98
|
protocols.act_on(op, self)
|
|
99
99
|
|
|
100
100
|
@abc.abstractmethod
|
|
101
|
-
def copy(self
|
|
101
|
+
def copy(self, deep_copy_buffers: bool = True) -> Self:
|
|
102
102
|
"""Creates a copy of the object.
|
|
103
103
|
|
|
104
104
|
Args:
|
|
@@ -124,11 +124,14 @@ class SimulationStateBase(Generic[TSimulationState], metaclass=abc.ABCMeta):
|
|
|
124
124
|
) -> np.ndarray:
|
|
125
125
|
"""Samples the state value."""
|
|
126
126
|
|
|
127
|
+
@abc.abstractmethod
|
|
127
128
|
def __getitem__(self, item: Optional['cirq.Qid']) -> TSimulationState:
|
|
128
129
|
"""Gets the item associated with the qubit."""
|
|
129
130
|
|
|
131
|
+
@abc.abstractmethod
|
|
130
132
|
def __len__(self) -> int:
|
|
131
133
|
"""Gets the number of items in the mapping."""
|
|
132
134
|
|
|
135
|
+
@abc.abstractmethod
|
|
133
136
|
def __iter__(self) -> Iterator[Optional['cirq.Qid']]:
|
|
134
137
|
"""Iterates the keys of the mapping."""
|
|
@@ -19,6 +19,7 @@ import pytest
|
|
|
19
19
|
|
|
20
20
|
import cirq
|
|
21
21
|
from cirq.sim import simulation_state
|
|
22
|
+
from cirq.testing import PhaseUsingCleanAncilla, PhaseUsingDirtyAncilla
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class DummyQuantumState(cirq.QuantumStateRepresentation):
|
|
@@ -33,14 +34,43 @@ class DummyQuantumState(cirq.QuantumStateRepresentation):
|
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
class DummySimulationState(cirq.SimulationState):
|
|
36
|
-
def __init__(self):
|
|
37
|
-
super().__init__(state=DummyQuantumState(), qubits=
|
|
37
|
+
def __init__(self, qubits=cirq.LineQubit.range(2)):
|
|
38
|
+
super().__init__(state=DummyQuantumState(), qubits=qubits)
|
|
38
39
|
|
|
39
40
|
def _act_on_fallback_(
|
|
40
41
|
self, action: Any, qubits: Sequence['cirq.Qid'], allow_decompose: bool = True
|
|
41
42
|
) -> bool:
|
|
42
43
|
return True
|
|
43
44
|
|
|
45
|
+
def add_qubits(self, qubits):
|
|
46
|
+
ret = super().add_qubits(qubits)
|
|
47
|
+
return self if NotImplemented else ret
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class DelegatingAncillaZ(cirq.Gate):
|
|
51
|
+
def __init__(self, exponent=1, measure_ancilla: bool = False):
|
|
52
|
+
self._exponent = exponent
|
|
53
|
+
self._measure_ancilla = measure_ancilla
|
|
54
|
+
|
|
55
|
+
def num_qubits(self) -> int:
|
|
56
|
+
return 1
|
|
57
|
+
|
|
58
|
+
def _decompose_(self, qubits):
|
|
59
|
+
a = cirq.NamedQubit('a')
|
|
60
|
+
yield cirq.CX(qubits[0], a)
|
|
61
|
+
yield PhaseUsingCleanAncilla(self._exponent).on(a)
|
|
62
|
+
yield cirq.CX(qubits[0], a)
|
|
63
|
+
if self._measure_ancilla:
|
|
64
|
+
yield cirq.measure(a)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Composite(cirq.Gate):
|
|
68
|
+
def num_qubits(self) -> int:
|
|
69
|
+
return 1
|
|
70
|
+
|
|
71
|
+
def _decompose_(self, qubits):
|
|
72
|
+
yield cirq.X(*qubits)
|
|
73
|
+
|
|
44
74
|
|
|
45
75
|
def test_measurements():
|
|
46
76
|
args = DummySimulationState()
|
|
@@ -49,19 +79,24 @@ def test_measurements():
|
|
|
49
79
|
|
|
50
80
|
|
|
51
81
|
def test_decompose():
|
|
52
|
-
class Composite(cirq.Gate):
|
|
53
|
-
def num_qubits(self) -> int:
|
|
54
|
-
return 1
|
|
55
|
-
|
|
56
|
-
def _decompose_(self, qubits):
|
|
57
|
-
yield cirq.X(*qubits)
|
|
58
|
-
|
|
59
82
|
args = DummySimulationState()
|
|
60
83
|
assert simulation_state.strat_act_on_from_apply_decompose(
|
|
61
84
|
Composite(), args, [cirq.LineQubit(0)]
|
|
62
85
|
)
|
|
63
86
|
|
|
64
87
|
|
|
88
|
+
def test_decompose_for_gate_allocating_qubits_raises():
|
|
89
|
+
class Composite(cirq.testing.SingleQubitGate):
|
|
90
|
+
def _decompose_(self, qubits):
|
|
91
|
+
anc = cirq.NamedQubit("anc")
|
|
92
|
+
yield cirq.CNOT(*qubits, anc)
|
|
93
|
+
|
|
94
|
+
args = DummySimulationState()
|
|
95
|
+
|
|
96
|
+
with pytest.raises(TypeError, match="add_qubits but not remove_qubits"):
|
|
97
|
+
simulation_state.strat_act_on_from_apply_decompose(Composite(), args, [cirq.LineQubit(0)])
|
|
98
|
+
|
|
99
|
+
|
|
65
100
|
def test_mapping():
|
|
66
101
|
args = DummySimulationState()
|
|
67
102
|
assert list(iter(args)) == cirq.LineQubit.range(2)
|
|
@@ -101,3 +136,80 @@ def test_field_getters():
|
|
|
101
136
|
args = DummySimulationState()
|
|
102
137
|
assert args.prng is np.random
|
|
103
138
|
assert args.qubit_map == {q: i for i, q in enumerate(cirq.LineQubit.range(2))}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@pytest.mark.parametrize('exp', np.linspace(0, 2 * np.pi, 10))
|
|
142
|
+
def test_delegating_gate_unitary(exp):
|
|
143
|
+
q = cirq.LineQubit(0)
|
|
144
|
+
|
|
145
|
+
test_circuit = cirq.Circuit()
|
|
146
|
+
test_circuit.append(cirq.H(q))
|
|
147
|
+
test_circuit.append(DelegatingAncillaZ(exp).on(q))
|
|
148
|
+
|
|
149
|
+
control_circuit = cirq.Circuit(cirq.H(q))
|
|
150
|
+
control_circuit.append(cirq.ZPowGate(exponent=exp).on(q))
|
|
151
|
+
|
|
152
|
+
assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
|
|
153
|
+
assert_test_circuit_for_sv_simulator(test_circuit, control_circuit)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@pytest.mark.parametrize('exp', np.linspace(0, 2 * np.pi, 10))
|
|
157
|
+
def test_delegating_gate_channel(exp):
|
|
158
|
+
q = cirq.LineQubit(0)
|
|
159
|
+
|
|
160
|
+
test_circuit = cirq.Circuit()
|
|
161
|
+
test_circuit.append(cirq.H(q))
|
|
162
|
+
test_circuit.append(DelegatingAncillaZ(exp, True).on(q))
|
|
163
|
+
|
|
164
|
+
control_circuit = cirq.Circuit(cirq.H(q))
|
|
165
|
+
control_circuit.append(cirq.ZPowGate(exponent=exp).on(q))
|
|
166
|
+
|
|
167
|
+
with pytest.raises(TypeError, match="DensityMatrixSimulator doesn't support"):
|
|
168
|
+
# TODO: This test should pass once we extend support to DensityMatrixSimulator.
|
|
169
|
+
assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@pytest.mark.parametrize('num_ancilla', [1, 2, 3])
|
|
173
|
+
def test_phase_using_dirty_ancilla(num_ancilla: int):
|
|
174
|
+
q = cirq.LineQubit(0)
|
|
175
|
+
anc = cirq.NamedQubit.range(num_ancilla, prefix='anc')
|
|
176
|
+
|
|
177
|
+
u = cirq.MatrixGate(cirq.testing.random_unitary(2 ** (num_ancilla + 1)))
|
|
178
|
+
test_circuit = cirq.Circuit(
|
|
179
|
+
u.on(q, *anc), PhaseUsingDirtyAncilla(ancilla_bitsize=num_ancilla).on(q)
|
|
180
|
+
)
|
|
181
|
+
control_circuit = cirq.Circuit(u.on(q, *anc), cirq.Z(q))
|
|
182
|
+
assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
|
|
183
|
+
assert_test_circuit_for_sv_simulator(test_circuit, control_circuit)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@pytest.mark.parametrize('num_ancilla', [1, 2, 3])
|
|
187
|
+
@pytest.mark.parametrize('theta', np.linspace(0, 2 * np.pi, 10))
|
|
188
|
+
def test_phase_using_clean_ancilla(num_ancilla: int, theta: float):
|
|
189
|
+
q = cirq.LineQubit(0)
|
|
190
|
+
u = cirq.MatrixGate(cirq.testing.random_unitary(2))
|
|
191
|
+
test_circuit = cirq.Circuit(
|
|
192
|
+
u.on(q), PhaseUsingCleanAncilla(theta=theta, ancilla_bitsize=num_ancilla).on(q)
|
|
193
|
+
)
|
|
194
|
+
control_circuit = cirq.Circuit(u.on(q), cirq.ZPowGate(exponent=theta).on(q))
|
|
195
|
+
assert_test_circuit_for_dm_simulator(test_circuit, control_circuit)
|
|
196
|
+
assert_test_circuit_for_sv_simulator(test_circuit, control_circuit)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def assert_test_circuit_for_dm_simulator(test_circuit, control_circuit) -> None:
|
|
200
|
+
# Density Matrix Simulator: For unitary gates, this fallbacks to `cirq.apply_channel`
|
|
201
|
+
# which recursively calls to `cirq.apply_unitary(decompose=True)`.
|
|
202
|
+
for split_untangled_states in [True, False]:
|
|
203
|
+
sim = cirq.DensityMatrixSimulator(split_untangled_states=split_untangled_states)
|
|
204
|
+
control_sim = sim.simulate(control_circuit).final_density_matrix
|
|
205
|
+
test_sim = sim.simulate(test_circuit).final_density_matrix
|
|
206
|
+
assert np.allclose(test_sim, control_sim)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def assert_test_circuit_for_sv_simulator(test_circuit, control_circuit) -> None:
|
|
210
|
+
# State Vector Simulator.
|
|
211
|
+
for split_untangled_states in [True, False]:
|
|
212
|
+
sim = cirq.Simulator(split_untangled_states=split_untangled_states)
|
|
213
|
+
control_sim = sim.simulate(control_circuit).final_state_vector
|
|
214
|
+
test_sim = sim.simulate(test_circuit).final_state_vector
|
|
215
|
+
assert np.allclose(test_sim, control_sim)
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
from typing import Sequence, Tuple
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
from cirq import linalg
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def state_probabilities_by_indices(
|
|
22
|
+
state_probability: np.ndarray, indices: Sequence[int], qid_shape: Tuple[int, ...]
|
|
23
|
+
) -> np.ndarray:
|
|
24
|
+
"""Returns the probabilities for a state/measurement on the given indices.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
state_probability: The multi-qubit state probability vector. This is an
|
|
28
|
+
array of 2 to the power of the number of real numbers, and
|
|
29
|
+
so state must be of size ``2**integer``. The `state_probability` can be
|
|
30
|
+
a vector of size ``2**integer`` or a tensor of shape
|
|
31
|
+
``(2, 2, ..., 2)``.
|
|
32
|
+
indices: Which qubits are measured. The `state_probability` is assumed to be
|
|
33
|
+
supplied in big endian order. That is the xth index of v, when
|
|
34
|
+
expressed as a bitstring, has its largest values in the 0th index.
|
|
35
|
+
qid_shape: The qid shape of the `state_probability`.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
State probabilities.
|
|
39
|
+
"""
|
|
40
|
+
probs = state_probability.reshape((-1,))
|
|
41
|
+
not_measured = [i for i in range(len(qid_shape)) if i not in indices]
|
|
42
|
+
if linalg.can_numpy_support_shape(qid_shape):
|
|
43
|
+
# Use numpy transpose if we can since it's more efficient.
|
|
44
|
+
probs = probs.reshape(qid_shape)
|
|
45
|
+
probs = np.transpose(probs, list(indices) + not_measured)
|
|
46
|
+
probs = probs.reshape((-1,))
|
|
47
|
+
else:
|
|
48
|
+
# If we can't use numpy due to numpy/numpy#5744, use a slower method.
|
|
49
|
+
probs = linalg.transpose_flattened_array(probs, qid_shape, list(indices) + not_measured)
|
|
50
|
+
|
|
51
|
+
if len(not_measured):
|
|
52
|
+
# Not all qudits are measured.
|
|
53
|
+
volume = np.prod([qid_shape[i] for i in indices])
|
|
54
|
+
# Reshape into a 2D array in which each of the measured states correspond to a row.
|
|
55
|
+
probs = probs.reshape((volume, -1))
|
|
56
|
+
probs = np.sum(probs, axis=-1)
|
|
57
|
+
|
|
58
|
+
# To deal with rounding issues, ensure that the probabilities sum to 1.
|
|
59
|
+
return probs / np.sum(probs)
|
|
@@ -0,0 +1,32 @@
|
|
|
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 pytest
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
from cirq.sim import simulation_utils
|
|
19
|
+
from cirq import testing
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.mark.parametrize('n,m', [(n, m) for n in range(1, 4) for m in range(1, n + 1)])
|
|
23
|
+
def test_state_probabilities_by_indices(n: int, m: int):
|
|
24
|
+
np.random.seed(0)
|
|
25
|
+
state = testing.random_superposition(1 << n)
|
|
26
|
+
d = (state.conj() * state).real
|
|
27
|
+
desired_axes = list(np.random.choice(n, m, replace=False))
|
|
28
|
+
not_wanted = [i for i in range(n) if i not in desired_axes]
|
|
29
|
+
got = simulation_utils.state_probabilities_by_indices(d, desired_axes, (2,) * n)
|
|
30
|
+
want = np.transpose(d.reshape((2,) * n), desired_axes + not_wanted)
|
|
31
|
+
want = np.sum(want.reshape((1 << len(desired_axes), -1)), axis=-1)
|
|
32
|
+
np.testing.assert_allclose(want, got)
|
cirq/sim/simulator.py
CHANGED
|
@@ -452,6 +452,7 @@ class SimulatesExpectationValues(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
452
452
|
ValueError if 'program' has terminal measurement(s) and
|
|
453
453
|
'permit_terminal_measurements' is False.
|
|
454
454
|
"""
|
|
455
|
+
raise NotImplementedError
|
|
455
456
|
|
|
456
457
|
|
|
457
458
|
class SimulatesFinalState(
|
|
@@ -959,7 +960,7 @@ def check_all_resolved(circuit):
|
|
|
959
960
|
unresolved = [op for moment in circuit for op in moment if protocols.is_parameterized(op)]
|
|
960
961
|
raise ValueError(
|
|
961
962
|
'Circuit contains ops whose symbols were not specified in '
|
|
962
|
-
'parameter sweep. Ops: {}'
|
|
963
|
+
f'parameter sweep. Ops: {unresolved}'
|
|
963
964
|
)
|
|
964
965
|
|
|
965
966
|
|