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.
- cirq/__init__.py +4 -0
- cirq/_compat.py +9 -11
- cirq/_compat_test.py +45 -56
- cirq/_version.py +31 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/circuit.py +13 -8
- cirq/circuits/circuit_operation.py +2 -1
- cirq/circuits/circuit_test.py +2 -2
- cirq/circuits/frozen_circuit.py +3 -2
- cirq/circuits/moment.py +12 -10
- cirq/circuits/qasm_output.py +5 -1
- cirq/circuits/qasm_output_test.py +25 -10
- cirq/contrib/qcircuit/qcircuit_diagram_info.py +9 -7
- cirq/contrib/quimb/mps_simulator_test.py +1 -1
- cirq/contrib/quimb/state_vector.py +9 -2
- cirq/contrib/svg/svg.py +2 -1
- cirq/contrib/svg/svg_test.py +1 -0
- cirq/devices/grid_qubit.py +85 -32
- cirq/devices/grid_qubit_test.py +22 -4
- cirq/devices/line_qubit.py +74 -26
- cirq/devices/line_qubit_test.py +19 -0
- cirq/devices/noise_utils.py +33 -31
- cirq/devices/noise_utils_test.py +1 -84
- cirq/devices/superconducting_qubits_noise_properties.py +7 -6
- cirq/experiments/__init__.py +8 -0
- cirq/experiments/qubit_characterizations.py +288 -44
- cirq/experiments/qubit_characterizations_test.py +61 -7
- cirq/experiments/random_quantum_circuit_generation.py +1 -1
- cirq/experiments/single_qubit_readout_calibration.py +132 -6
- cirq/experiments/single_qubit_readout_calibration_test.py +3 -1
- cirq/experiments/t1_decay_experiment.py +14 -7
- cirq/experiments/t1_decay_experiment_test.py +14 -26
- cirq/experiments/two_qubit_xeb.py +483 -0
- cirq/experiments/two_qubit_xeb_test.py +304 -0
- cirq/json_resolver_cache.py +2 -0
- cirq/linalg/decompositions.py +11 -13
- cirq/linalg/decompositions_test.py +1 -3
- cirq/linalg/diagonalize.py +5 -4
- cirq/linalg/predicates.py +8 -6
- cirq/linalg/transformations.py +2 -1
- cirq/linalg/transformations_test.py +1 -1
- cirq/ops/__init__.py +2 -0
- cirq/ops/clifford_gate.py +59 -16
- cirq/ops/common_gates_test.py +1 -2
- cirq/ops/control_values.py +4 -3
- cirq/ops/controlled_gate_test.py +1 -3
- cirq/ops/gate_operation.py +10 -1
- cirq/ops/named_qubit.py +74 -28
- cirq/ops/named_qubit_test.py +19 -0
- cirq/ops/parity_gates.py +5 -0
- cirq/ops/parity_gates_test.py +2 -10
- cirq/ops/pauli_gates.py +5 -2
- cirq/ops/pauli_string.py +2 -2
- cirq/ops/permutation_gate.py +16 -18
- cirq/ops/phased_iswap_gate_test.py +1 -3
- cirq/ops/phased_x_gate.py +1 -1
- cirq/ops/phased_x_z_gate.py +17 -1
- cirq/ops/phased_x_z_gate_test.py +24 -0
- cirq/ops/qid_util.py +4 -8
- cirq/ops/qubit_manager.py +7 -4
- cirq/ops/qubit_manager_test.py +20 -0
- cirq/ops/raw_types.py +5 -2
- cirq/ops/raw_types_test.py +14 -15
- cirq/ops/uniform_superposition_gate.py +123 -0
- cirq/ops/uniform_superposition_gate_test.py +94 -0
- cirq/protocols/approximate_equality_protocol_test.py +2 -2
- cirq/protocols/circuit_diagram_info_protocol.py +6 -4
- cirq/protocols/commutes_protocol.py +2 -4
- cirq/protocols/decompose_protocol.py +7 -12
- cirq/protocols/decompose_protocol_test.py +7 -3
- cirq/protocols/has_stabilizer_effect_protocol.py +1 -5
- cirq/protocols/has_stabilizer_effect_protocol_test.py +13 -4
- cirq/protocols/json_serialization.py +51 -181
- cirq/protocols/json_serialization_test.py +13 -47
- cirq/protocols/json_test_data/CircuitOperation.json +131 -148
- cirq/protocols/json_test_data/CircuitOperation.json_inward +55 -0
- cirq/protocols/json_test_data/CircuitOperation.repr_inward +6 -0
- cirq/protocols/json_test_data/FrozenCircuit.json +196 -210
- cirq/protocols/json_test_data/FrozenCircuit.json_inward +35 -0
- cirq/protocols/json_test_data/FrozenCircuit.repr_inward +4 -0
- cirq/protocols/json_test_data/UniformSuperpositionGate.json +5 -0
- cirq/protocols/json_test_data/UniformSuperpositionGate.repr +1 -0
- cirq/protocols/json_test_data/cirq.MSGate.json +4 -0
- cirq/protocols/json_test_data/cirq.MSGate.repr +1 -0
- cirq/protocols/json_test_data/spec.py +2 -0
- cirq/protocols/pow_protocol_test.py +1 -3
- cirq/protocols/resolve_parameters.py +4 -2
- cirq/qis/__init__.py +10 -0
- cirq/qis/clifford_tableau.py +8 -2
- cirq/qis/noise_utils.py +123 -0
- cirq/qis/noise_utils_test.py +97 -0
- cirq/sim/classical_simulator.py +227 -87
- cirq/sim/classical_simulator_test.py +135 -0
- cirq/sim/clifford/clifford_simulator_test.py +4 -2
- cirq/sim/mux.py +5 -3
- cirq/sim/simulation_product_state.py +15 -10
- cirq/sim/simulation_state.py +1 -1
- cirq/sim/simulation_state_test.py +2 -2
- cirq/sim/simulator_base.py +3 -3
- cirq/sim/state_vector_simulation_state.py +4 -4
- cirq/sim/state_vector_simulator.py +17 -2
- cirq/study/__init__.py +1 -0
- cirq/study/result.py +14 -0
- cirq/study/result_test.py +6 -0
- cirq/study/sweeps.py +4 -2
- cirq/study/sweeps_test.py +8 -0
- cirq/testing/__init__.py +6 -1
- cirq/testing/_compat_test_data/__init__.py +3 -3
- cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
- cirq/testing/circuit_compare.py +1 -1
- cirq/testing/consistent_qasm.py +6 -0
- cirq/testing/gate_features.py +10 -0
- cirq/testing/lin_alg_utils.py +5 -3
- cirq/transformers/__init__.py +15 -0
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +3 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +24 -0
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +17 -0
- cirq/transformers/dynamical_decoupling.py +122 -0
- cirq/transformers/dynamical_decoupling_test.py +123 -0
- cirq/transformers/gauge_compiling/__init__.py +26 -0
- cirq/transformers/gauge_compiling/cz_gauge.py +46 -0
- cirq/transformers/gauge_compiling/cz_gauge_test.py +23 -0
- cirq/transformers/gauge_compiling/gauge_compiling.py +214 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +41 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +83 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +52 -0
- cirq/transformers/gauge_compiling/iswap_gauge.py +105 -0
- cirq/transformers/gauge_compiling/iswap_gauge_test.py +23 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge.py +33 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +37 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +64 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +27 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +94 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +22 -0
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -0
- cirq/transformers/merge_k_qubit_gates_test.py +23 -23
- cirq/transformers/merge_single_qubit_gates_test.py +14 -14
- cirq/transformers/optimize_for_target_gateset.py +39 -17
- cirq/transformers/optimize_for_target_gateset_test.py +189 -39
- cirq/transformers/qubit_management_transformers.py +1 -1
- cirq/transformers/routing/visualize_routed_circuit_test.py +17 -17
- cirq/transformers/stratify_test.py +13 -13
- cirq/transformers/target_gatesets/compilation_target_gateset.py +26 -2
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +16 -16
- cirq/transformers/target_gatesets/cz_gateset.py +4 -0
- cirq/transformers/transformer_api.py +1 -2
- cirq/transformers/transformer_primitives.py +15 -14
- cirq/transformers/transformer_primitives_test.py +99 -72
- cirq/value/classical_data.py +6 -6
- cirq/value/value_equality_attr.py +4 -0
- cirq/work/sampler.py +3 -4
- cirq/work/sampler_test.py +25 -0
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
cirq/qis/noise_utils.py
ADDED
|
@@ -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
|
cirq/sim/classical_simulator.py
CHANGED
|
@@ -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
|
-
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from cirq import ops,
|
|
19
|
-
from cirq.
|
|
20
|
-
from cirq
|
|
21
|
-
from cirq.
|
|
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(
|
|
26
|
-
if
|
|
27
|
-
|
|
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
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
+
)
|