cirq-core 1.1.0.dev20221219200817__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/conftest.py +8 -0
- 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.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/RECORD +229 -215
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Copyright 2023 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import cirq
|
|
16
|
+
from cirq.ops import common_gates
|
|
17
|
+
from cirq.transformers.analytical_decompositions.quantum_shannon_decomposition import (
|
|
18
|
+
_multiplexed_cossin,
|
|
19
|
+
_nth_gray,
|
|
20
|
+
_msb_demuxer,
|
|
21
|
+
_single_qubit_decomposition,
|
|
22
|
+
quantum_shannon_decomposition,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
import pytest
|
|
26
|
+
import numpy as np
|
|
27
|
+
from scipy.stats import unitary_group
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.mark.parametrize('n_qubits', list(range(1, 8)))
|
|
31
|
+
def test_random_qsd_n_qubit(n_qubits):
|
|
32
|
+
U = unitary_group.rvs(2**n_qubits)
|
|
33
|
+
qubits = [cirq.NamedQubit(f'q{i}') for i in range(n_qubits)]
|
|
34
|
+
circuit = cirq.Circuit(quantum_shannon_decomposition(qubits, U))
|
|
35
|
+
# Test return is equal to inital unitary
|
|
36
|
+
assert cirq.approx_eq(U, circuit.unitary(), atol=1e-9)
|
|
37
|
+
# Test all operations in gate set
|
|
38
|
+
gates = (common_gates.Rz, common_gates.Ry, common_gates.ZPowGate, common_gates.CXPowGate)
|
|
39
|
+
assert all(isinstance(op.gate, gates) for op in circuit.all_operations())
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_qsd_n_qubit_errors():
|
|
43
|
+
qubits = [cirq.NamedQubit(f'q{i}') for i in range(3)]
|
|
44
|
+
with pytest.raises(ValueError, match="shaped numpy array"):
|
|
45
|
+
cirq.Circuit(quantum_shannon_decomposition(qubits, np.eye(9)))
|
|
46
|
+
with pytest.raises(ValueError, match="is_unitary"):
|
|
47
|
+
cirq.Circuit(quantum_shannon_decomposition(qubits, np.ones((8, 8))))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_random_single_qubit_decomposition():
|
|
51
|
+
U = unitary_group.rvs(2)
|
|
52
|
+
qubit = cirq.NamedQubit('q0')
|
|
53
|
+
circuit = cirq.Circuit(_single_qubit_decomposition(qubit, U))
|
|
54
|
+
# Test return is equal to inital unitary
|
|
55
|
+
assert cirq.approx_eq(U, circuit.unitary(), atol=1e-9)
|
|
56
|
+
# Test all operations in gate set
|
|
57
|
+
gates = (common_gates.Rz, common_gates.Ry, common_gates.ZPowGate, common_gates.CXPowGate)
|
|
58
|
+
assert all(isinstance(op.gate, gates) for op in circuit.all_operations())
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_msb_demuxer():
|
|
62
|
+
U1 = unitary_group.rvs(4)
|
|
63
|
+
U2 = unitary_group.rvs(4)
|
|
64
|
+
U_full = np.kron([[1, 0], [0, 0]], U1) + np.kron([[0, 0], [0, 1]], U2)
|
|
65
|
+
qubits = [cirq.NamedQubit(f'q{i}') for i in range(3)]
|
|
66
|
+
circuit = cirq.Circuit(_msb_demuxer(qubits, U1, U2))
|
|
67
|
+
# Test return is equal to inital unitary
|
|
68
|
+
assert cirq.approx_eq(U_full, circuit.unitary(), atol=1e-9)
|
|
69
|
+
# Test all operations in gate set
|
|
70
|
+
gates = (common_gates.Rz, common_gates.Ry, common_gates.ZPowGate, common_gates.CXPowGate)
|
|
71
|
+
assert all(isinstance(op.gate, gates) for op in circuit.all_operations())
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_multiplexed_cossin():
|
|
75
|
+
angle_1 = np.random.random_sample() * 2 * np.pi
|
|
76
|
+
angle_2 = np.random.random_sample() * 2 * np.pi
|
|
77
|
+
c1, s1 = np.cos(angle_1), np.sin(angle_1)
|
|
78
|
+
c2, s2 = np.cos(angle_2), np.sin(angle_2)
|
|
79
|
+
multiplexed_ry = [[c1, 0, -s1, 0], [0, c2, 0, -s2], [s1, 0, c1, 0], [0, s2, 0, c2]]
|
|
80
|
+
multiplexed_ry = np.array(multiplexed_ry)
|
|
81
|
+
qubits = [cirq.NamedQubit(f'q{i}') for i in range(2)]
|
|
82
|
+
circuit = cirq.Circuit(_multiplexed_cossin(qubits, [angle_1, angle_2]))
|
|
83
|
+
# Test return is equal to inital unitary
|
|
84
|
+
assert cirq.approx_eq(multiplexed_ry, circuit.unitary(), atol=1e-9)
|
|
85
|
+
# Test all operations in gate set
|
|
86
|
+
gates = (common_gates.Rz, common_gates.Ry, common_gates.ZPowGate, common_gates.CXPowGate)
|
|
87
|
+
assert all(isinstance(op.gate, gates) for op in circuit.all_operations())
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@pytest.mark.parametrize(
|
|
91
|
+
'n, gray',
|
|
92
|
+
[
|
|
93
|
+
(0, 0),
|
|
94
|
+
(1, 1),
|
|
95
|
+
(2, 3),
|
|
96
|
+
(3, 2),
|
|
97
|
+
(4, 6),
|
|
98
|
+
(5, 7),
|
|
99
|
+
(6, 5),
|
|
100
|
+
(7, 4),
|
|
101
|
+
(8, 12),
|
|
102
|
+
(9, 13),
|
|
103
|
+
(10, 15),
|
|
104
|
+
(11, 14),
|
|
105
|
+
(12, 10),
|
|
106
|
+
(13, 11),
|
|
107
|
+
(14, 9),
|
|
108
|
+
(15, 8),
|
|
109
|
+
],
|
|
110
|
+
)
|
|
111
|
+
def test_nth_gray(n, gray):
|
|
112
|
+
assert _nth_gray(n) == gray
|
|
@@ -211,9 +211,7 @@ def test_middle_multiplexor(angles, num_cnots):
|
|
|
211
211
|
]
|
|
212
212
|
)
|
|
213
213
|
== num_cnots
|
|
214
|
-
), "expected {} CNOTs got \n {} \n {}"
|
|
215
|
-
num_cnots, circuit_u1u2_mid, circuit_u1u2_mid.unitary()
|
|
216
|
-
)
|
|
214
|
+
), f"expected {num_cnots} CNOTs got \n {circuit_u1u2_mid} \n {circuit_u1u2_mid.unitary()}"
|
|
217
215
|
|
|
218
216
|
|
|
219
217
|
@pytest.mark.parametrize("shift_left", [True, False])
|
|
@@ -28,7 +28,7 @@ def decompose_two_qubit_interaction_into_four_fsim_gates(
|
|
|
28
28
|
interaction: Union['cirq.SupportsUnitary', np.ndarray],
|
|
29
29
|
*,
|
|
30
30
|
fsim_gate: Union['cirq.FSimGate', 'cirq.ISwapPowGate'],
|
|
31
|
-
qubits: Sequence['cirq.Qid'] = None,
|
|
31
|
+
qubits: Optional[Sequence['cirq.Qid']] = None,
|
|
32
32
|
) -> 'cirq.Circuit':
|
|
33
33
|
"""Decomposes operations into an FSimGate near theta=pi/2, phi=0.
|
|
34
34
|
|
|
@@ -33,7 +33,7 @@ def expand_composite(
|
|
|
33
33
|
"""A transformer that expands composite operations via `cirq.decompose`.
|
|
34
34
|
|
|
35
35
|
For each operation in the circuit, this pass examines if the operation can
|
|
36
|
-
be decomposed. If it can be, the operation is cleared out and
|
|
36
|
+
be decomposed. If it can be, the operation is cleared out and replaced
|
|
37
37
|
with its decomposition using a fixed insertion strategy.
|
|
38
38
|
|
|
39
39
|
Transformation is applied using `cirq.map_operations_and_unroll`, which preserves the
|
|
@@ -164,8 +164,8 @@ def kak_vector_infidelity(
|
|
|
164
164
|
|
|
165
165
|
if ignore_equivalent_vectors:
|
|
166
166
|
k_diff = k_vec_a - k_vec_b
|
|
167
|
-
out = 1 - np.
|
|
168
|
-
out -= np.
|
|
167
|
+
out = 1 - np.prod(np.cos(k_diff), axis=-1) ** 2
|
|
168
|
+
out -= np.prod(np.sin(k_diff), axis=-1) ** 2
|
|
169
169
|
return out
|
|
170
170
|
|
|
171
171
|
# We must take the minimum infidelity over all possible locally equivalent
|
|
@@ -181,8 +181,8 @@ def kak_vector_infidelity(
|
|
|
181
181
|
|
|
182
182
|
k_diff = k_vec_a - k_vec_b
|
|
183
183
|
|
|
184
|
-
out = 1 - np.
|
|
185
|
-
out -= np.
|
|
184
|
+
out = 1 - np.prod(np.cos(k_diff), axis=-1) ** 2
|
|
185
|
+
out -= np.prod(np.sin(k_diff), axis=-1) ** 2 # (...,192)
|
|
186
186
|
|
|
187
187
|
return out.min(axis=-1)
|
|
188
188
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import itertools
|
|
16
16
|
from collections import defaultdict
|
|
17
|
-
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
|
|
17
|
+
from typing import Any, cast, Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
|
|
18
18
|
|
|
19
19
|
import numpy as np
|
|
20
20
|
|
|
@@ -420,13 +420,13 @@ class _ConfusionChannel(ops.Gate):
|
|
|
420
420
|
return self._kraus
|
|
421
421
|
|
|
422
422
|
def _apply_channel_(self, args: 'cirq.ApplyChannelArgs'):
|
|
423
|
-
configs = []
|
|
423
|
+
configs: List[transformations._BuildFromSlicesArgs] = []
|
|
424
424
|
for i in range(np.prod(self._shape) ** 2):
|
|
425
|
-
scale = self._confusion_map.flat[i]
|
|
425
|
+
scale = cast(complex, self._confusion_map.flat[i])
|
|
426
426
|
if scale == 0:
|
|
427
427
|
continue
|
|
428
428
|
index: Any = np.unravel_index(i, self._shape * 2)
|
|
429
|
-
slices = []
|
|
429
|
+
slices: List[transformations._SliceConfig] = []
|
|
430
430
|
axis_count = len(args.left_axes)
|
|
431
431
|
for j in range(axis_count):
|
|
432
432
|
s1 = transformations._SliceConfig(
|
|
@@ -127,10 +127,23 @@ def merge_single_qubit_moments_to_phxz(
|
|
|
127
127
|
return None
|
|
128
128
|
ret_ops = []
|
|
129
129
|
for q in m1.qubits | m2.qubits:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
op1, op2 = m1.operation_at(q), m2.operation_at(q)
|
|
131
|
+
if op1 and op2:
|
|
132
|
+
mat = protocols.unitary(op2) @ protocols.unitary(op1)
|
|
133
|
+
gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(mat, atol)
|
|
134
|
+
if gate:
|
|
135
|
+
ret_ops.append(gate(q))
|
|
136
|
+
else:
|
|
137
|
+
op = op1 or op2
|
|
138
|
+
assert op is not None
|
|
139
|
+
if isinstance(op.gate, ops.PhasedXZGate):
|
|
140
|
+
ret_ops.append(op)
|
|
141
|
+
else:
|
|
142
|
+
gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(
|
|
143
|
+
protocols.unitary(op), atol
|
|
144
|
+
)
|
|
145
|
+
if gate:
|
|
146
|
+
ret_ops.append(gate(q))
|
|
134
147
|
return circuits.Moment(ret_ops)
|
|
135
148
|
|
|
136
149
|
return transformer_primitives.merge_moments(
|
|
@@ -129,7 +129,7 @@ class RouteCQC:
|
|
|
129
129
|
context: transformer context storing common configurable options for transformers.
|
|
130
130
|
|
|
131
131
|
Returns:
|
|
132
|
-
The routed circuit, which is equivalent to original circuit
|
|
132
|
+
The routed circuit, which is equivalent to original circuit up to a final qubit
|
|
133
133
|
permutation and where each 2-qubit operation is between adjacent qubits in the
|
|
134
134
|
`device_graph`.
|
|
135
135
|
|
|
@@ -183,7 +183,7 @@ class RouteCQC:
|
|
|
183
183
|
context: transformer context storing common configurable options for transformers.
|
|
184
184
|
|
|
185
185
|
Returns:
|
|
186
|
-
The routed circuit, which is equivalent to original circuit
|
|
186
|
+
The routed circuit, which is equivalent to original circuit up to a final qubit
|
|
187
187
|
permutation and where each 2-qubit operation is between adjacent qubits in the
|
|
188
188
|
`device_graph`.
|
|
189
189
|
The initial mapping from logical to physical qubits used as part of the routing
|
cirq/transformers/stratify.py
CHANGED
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"""Transformer pass to repack circuits avoiding simultaneous operations with different classes."""
|
|
16
16
|
|
|
17
17
|
import itertools
|
|
18
|
-
from typing import TYPE_CHECKING, Type, Callable, Optional, Union, Iterable, Sequence, List
|
|
18
|
+
from typing import TYPE_CHECKING, Type, Callable, Dict, Optional, Union, Iterable, Sequence, List
|
|
19
19
|
|
|
20
|
-
from cirq import ops, circuits, _import
|
|
21
|
-
from cirq.transformers import transformer_api
|
|
20
|
+
from cirq import ops, circuits, protocols, _import
|
|
21
|
+
from cirq.transformers import transformer_api
|
|
22
22
|
|
|
23
23
|
drop_empty_moments = _import.LazyLoader('drop_empty_moments', globals(), 'cirq.transformers')
|
|
24
24
|
|
|
@@ -61,38 +61,36 @@ def stratified_circuit(
|
|
|
61
61
|
Returns:
|
|
62
62
|
A copy of the original circuit, but with re-arranged operations.
|
|
63
63
|
"""
|
|
64
|
-
|
|
65
64
|
# Normalize categories into classifier functions.
|
|
66
|
-
classifiers =
|
|
67
|
-
# Make the classifiers exhaustive by adding an "everything else" bucket.
|
|
68
|
-
and_the_rest = lambda op: all(not classifier(op) for classifier in classifiers)
|
|
69
|
-
classifiers_and_the_rest = [*classifiers, and_the_rest]
|
|
65
|
+
classifiers = _get_classifiers(circuit, categories)
|
|
70
66
|
|
|
71
67
|
# Try the algorithm with each permutation of the classifiers.
|
|
72
|
-
|
|
68
|
+
smallest_depth = protocols.num_qubits(circuit) * len(circuit) + 1
|
|
69
|
+
shortest_stratified_circuit = circuits.Circuit()
|
|
73
70
|
reversed_circuit = circuit[::-1]
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
classifiers=list(c),
|
|
80
|
-
context=context or transformer_api.TransformerContext(),
|
|
81
|
-
)
|
|
71
|
+
for ordered_classifiers in itertools.permutations(classifiers):
|
|
72
|
+
solution = _stratify_circuit(
|
|
73
|
+
circuit,
|
|
74
|
+
classifiers=ordered_classifiers,
|
|
75
|
+
context=context or transformer_api.TransformerContext(),
|
|
82
76
|
)
|
|
77
|
+
if len(solution) < smallest_depth:
|
|
78
|
+
shortest_stratified_circuit = solution
|
|
79
|
+
smallest_depth = len(solution)
|
|
80
|
+
|
|
83
81
|
# Do the same thing, except this time in reverse. This helps for some
|
|
84
82
|
# circuits because it inserts operations at the end instead of at the
|
|
85
83
|
# beginning.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
solution = _stratify_circuit(
|
|
85
|
+
reversed_circuit,
|
|
86
|
+
classifiers=ordered_classifiers,
|
|
87
|
+
context=context or transformer_api.TransformerContext(),
|
|
88
|
+
)[::-1]
|
|
89
|
+
if len(solution) < smallest_depth:
|
|
90
|
+
shortest_stratified_circuit = solution
|
|
91
|
+
smallest_depth = len(solution)
|
|
93
92
|
|
|
94
|
-
|
|
95
|
-
return min(solutions, key=lambda c: len(c))
|
|
93
|
+
return shortest_stratified_circuit
|
|
96
94
|
|
|
97
95
|
|
|
98
96
|
def _stratify_circuit(
|
|
@@ -116,43 +114,88 @@ def _stratify_circuit(
|
|
|
116
114
|
Returns:
|
|
117
115
|
The stratified circuit.
|
|
118
116
|
"""
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
assert len(stratified_circuit) == len(circuit) * num_categories
|
|
135
|
-
|
|
136
|
-
# Try to move operations to the left to reduce circuit depth, preserving stratification.
|
|
137
|
-
for curr_idx, moment in enumerate(stratified_circuit):
|
|
138
|
-
curr_category = curr_idx % num_categories
|
|
139
|
-
if curr_category == 0:
|
|
140
|
-
# Moment containing tagged operations to be ignored.
|
|
141
|
-
continue
|
|
142
|
-
batch_removals: List[Tuple[int, 'cirq.Operation']] = []
|
|
143
|
-
batch_inserts: List[Tuple[int, 'cirq.Operation']] = []
|
|
117
|
+
num_classes = len(classifiers) + 1 # include one "extra" category for ignored operations
|
|
118
|
+
new_moments: List[List['cirq.Operation']] = []
|
|
119
|
+
|
|
120
|
+
# Keep track of the latest time index for each qubit, measurement key, and control key.
|
|
121
|
+
qubit_time_index: Dict['cirq.Qid', int] = {}
|
|
122
|
+
measurement_time_index: Dict['cirq.MeasurementKey', int] = {}
|
|
123
|
+
control_time_index: Dict['cirq.MeasurementKey', int] = {}
|
|
124
|
+
|
|
125
|
+
# The minimum time index for operations with a tag in context.tags_to_ignore.
|
|
126
|
+
last_ignored_ops_time_index = 0
|
|
127
|
+
|
|
128
|
+
for moment in circuit:
|
|
129
|
+
# Identify the new time indices that operations should be moved into.
|
|
130
|
+
ignored_ops = []
|
|
131
|
+
op_time_indices = {}
|
|
144
132
|
for op in moment:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
133
|
+
|
|
134
|
+
# Identify the earliest moment that can accommodate this op.
|
|
135
|
+
min_time_index_for_op = circuits.circuit.get_earliest_accommodating_moment_index(
|
|
136
|
+
op, qubit_time_index, measurement_time_index, control_time_index
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Identify the "class" of this operation (by index).
|
|
140
|
+
ignored_op = any(tag in op.tags for tag in context.tags_to_ignore)
|
|
141
|
+
if not ignored_op:
|
|
142
|
+
op_class = _get_op_class(op, classifiers)
|
|
143
|
+
else:
|
|
144
|
+
op_class = len(classifiers)
|
|
145
|
+
ignored_ops.append(op)
|
|
146
|
+
min_time_index_for_op = max(min_time_index_for_op, last_ignored_ops_time_index + 1)
|
|
147
|
+
|
|
148
|
+
# Identify the time index to place this operation into.
|
|
149
|
+
time_index = (min_time_index_for_op // num_classes) * num_classes + op_class
|
|
150
|
+
if time_index < min_time_index_for_op:
|
|
151
|
+
time_index += num_classes
|
|
152
|
+
op_time_indices[op] = time_index
|
|
153
|
+
|
|
154
|
+
# Assign ignored operations to the same moment.
|
|
155
|
+
if ignored_ops:
|
|
156
|
+
last_ignored_ops_time_index = max(op_time_indices[op] for op in ignored_ops)
|
|
157
|
+
for op in ignored_ops:
|
|
158
|
+
op_time_indices[op] = last_ignored_ops_time_index
|
|
159
|
+
|
|
160
|
+
# Move the operations into their assigned moments.
|
|
161
|
+
for op, time_index in op_time_indices.items():
|
|
162
|
+
if time_index >= len(new_moments):
|
|
163
|
+
new_moments += [[] for _ in range(num_classes)]
|
|
164
|
+
new_moments[time_index].append(op)
|
|
165
|
+
|
|
166
|
+
# Update qubit, measurment key, and control key moments.
|
|
167
|
+
for qubit in op.qubits:
|
|
168
|
+
qubit_time_index[qubit] = time_index
|
|
169
|
+
for key in protocols.measurement_key_objs(op):
|
|
170
|
+
measurement_time_index[key] = time_index
|
|
171
|
+
for key in protocols.control_keys(op):
|
|
172
|
+
control_time_index[key] = time_index
|
|
173
|
+
|
|
174
|
+
return circuits.Circuit(circuits.Moment(moment) for moment in new_moments if moment)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _get_classifiers(
|
|
178
|
+
circuit: circuits.AbstractCircuit, categories: Iterable[Category]
|
|
179
|
+
) -> List[Classifier]:
|
|
180
|
+
"""Convert a collection of categories into a list of classifiers.
|
|
181
|
+
|
|
182
|
+
The returned list of classifiers is:
|
|
183
|
+
- Exhaustive, meaning every operation in the circuit is classified by at least one classifier.
|
|
184
|
+
- Minimal, meaning unused classifiers are forgotten.
|
|
185
|
+
"""
|
|
186
|
+
# Convert all categories into classifiers, and make the list exhaustive by adding a dummy
|
|
187
|
+
# classifier for otherwise unclassified ops.
|
|
188
|
+
classifiers = [_category_to_classifier(cat) for cat in categories] + [_dummy_classifier]
|
|
189
|
+
|
|
190
|
+
# Figure out which classes are actually used in the circuit.
|
|
191
|
+
class_is_used = [False for _ in classifiers]
|
|
192
|
+
for op in circuit.all_operations():
|
|
193
|
+
class_is_used[_get_op_class(op, classifiers)] = True
|
|
194
|
+
if all(class_is_used):
|
|
195
|
+
break
|
|
196
|
+
|
|
197
|
+
# Return only the classifiers that are used.
|
|
198
|
+
return [classifier for classifier, is_used in zip(classifiers, class_is_used) if is_used]
|
|
156
199
|
|
|
157
200
|
|
|
158
201
|
# No type for `category` because mypy does not keep the return type when
|
|
@@ -177,3 +220,23 @@ def _category_to_classifier(category) -> Classifier:
|
|
|
177
220
|
f'Type[cirq.Gate], Type[cirq.Operation], '
|
|
178
221
|
f'or Callable[[cirq.Operation], bool].'
|
|
179
222
|
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _dummy_classifier(op: 'cirq.Operation') -> bool:
|
|
226
|
+
"""Dummy classifier, used to "complete" a collection of classifiers and make it exhaustive."""
|
|
227
|
+
return False # coverage: ignore
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _get_op_class(op: 'cirq.Operation', classifiers: Sequence[Classifier]) -> int:
|
|
231
|
+
"""Get the "class" of an operator, by index."""
|
|
232
|
+
for class_index, classifier in enumerate(classifiers):
|
|
233
|
+
if classifier is _dummy_classifier:
|
|
234
|
+
dummy_classifier_index = class_index
|
|
235
|
+
elif classifier(op):
|
|
236
|
+
return class_index
|
|
237
|
+
# If we got this far, the operation did not match any "actual" classifier,
|
|
238
|
+
# so return the index of the dummy classifer.
|
|
239
|
+
try:
|
|
240
|
+
return dummy_classifier_index
|
|
241
|
+
except NameError:
|
|
242
|
+
raise ValueError(f"Operation {op} not identified by any classifier")
|
|
@@ -224,17 +224,14 @@ def test_stratify_respects_no_compile_operations():
|
|
|
224
224
|
)
|
|
225
225
|
expected = cirq.Circuit(
|
|
226
226
|
[
|
|
227
|
+
cirq.Moment(cirq.Z(cirq.LineQubit(4))),
|
|
228
|
+
cirq.Moment(cirq.ISWAP(cirq.LineQubit(3), cirq.LineQubit(4))),
|
|
227
229
|
cirq.Moment(
|
|
228
230
|
cirq.TaggedOperation(cirq.X(cirq.LineQubit(0)), 'nocompile'),
|
|
229
231
|
cirq.TaggedOperation(cirq.ISWAP(cirq.LineQubit(1), cirq.LineQubit(2)), 'nocompile'),
|
|
230
232
|
),
|
|
231
|
-
cirq.Moment(cirq.X(cirq.LineQubit(0))),
|
|
232
|
-
cirq.Moment(cirq.
|
|
233
|
-
cirq.Moment(
|
|
234
|
-
cirq.ISWAP(cirq.LineQubit(3), cirq.LineQubit(4)),
|
|
235
|
-
cirq.ISWAP(cirq.LineQubit(0), cirq.LineQubit(1)),
|
|
236
|
-
),
|
|
237
|
-
cirq.Moment(cirq.X(cirq.LineQubit(3))),
|
|
233
|
+
cirq.Moment(cirq.X(cirq.LineQubit(0)), cirq.X(cirq.LineQubit(3))),
|
|
234
|
+
cirq.Moment(cirq.ISWAP(cirq.LineQubit(0), cirq.LineQubit(1))),
|
|
238
235
|
]
|
|
239
236
|
)
|
|
240
237
|
cirq.testing.assert_has_diagram(
|
|
@@ -254,15 +251,15 @@ def test_stratify_respects_no_compile_operations():
|
|
|
254
251
|
cirq.testing.assert_has_diagram(
|
|
255
252
|
expected,
|
|
256
253
|
'''
|
|
257
|
-
0:
|
|
258
|
-
|
|
259
|
-
1:
|
|
260
|
-
|
|
261
|
-
2:
|
|
262
|
-
|
|
263
|
-
3:
|
|
264
|
-
|
|
265
|
-
4:
|
|
254
|
+
0: ───────────────X['nocompile']───────X───iSwap───
|
|
255
|
+
│
|
|
256
|
+
1: ───────────────iSwap['nocompile']───────iSwap───
|
|
257
|
+
│
|
|
258
|
+
2: ───────────────iSwap────────────────────────────
|
|
259
|
+
|
|
260
|
+
3: ───────iSwap────────────────────────X───────────
|
|
261
|
+
│
|
|
262
|
+
4: ───Z───iSwap────────────────────────────────────
|
|
266
263
|
''',
|
|
267
264
|
)
|
|
268
265
|
cirq.testing.assert_same_circuits(
|
|
@@ -409,3 +406,10 @@ def test_surface_code_cycle_stratifies_without_growing():
|
|
|
409
406
|
# https://github.com/quantumlib/Cirq/pull/2772/ for some discussion on
|
|
410
407
|
# this, as well as a more optimal but much more complex and slow solution.
|
|
411
408
|
assert len(stratified) == 9
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def test_unclassified_ops():
|
|
412
|
+
op = cirq.X(cirq.q(0))
|
|
413
|
+
classifiers = []
|
|
414
|
+
with pytest.raises(ValueError, match='not identified by any classifier'):
|
|
415
|
+
cirq.transformers.stratify._get_op_class(op, classifiers)
|
|
@@ -109,7 +109,7 @@ class TransformerLogger:
|
|
|
109
109
|
The `LogLevel`s can be used to control the input processing and output resolution of the logs.
|
|
110
110
|
"""
|
|
111
111
|
|
|
112
|
-
def __init__(self):
|
|
112
|
+
def __init__(self) -> None:
|
|
113
113
|
"""Initializes TransformerLogger."""
|
|
114
114
|
self._curr_id: int = 0
|
|
115
115
|
self._logs: List[_LoggerNode] = []
|
|
@@ -158,7 +158,8 @@ def map_operations(
|
|
|
158
158
|
|
|
159
159
|
return map_moments(
|
|
160
160
|
circuit,
|
|
161
|
-
lambda m, i:
|
|
161
|
+
lambda m, i: circuits.Circuit(apply_map(op, i) for op in m.operations).moments
|
|
162
|
+
or [circuits.Moment()],
|
|
162
163
|
deep=deep,
|
|
163
164
|
tags_to_ignore=tags_to_ignore,
|
|
164
165
|
)
|
|
@@ -296,7 +297,7 @@ def merge_operations(
|
|
|
296
297
|
|
|
297
298
|
The method iterates on the input circuit moment-by-moment from left to right and attempts
|
|
298
299
|
to repeatedly merge each operation in the latest moment with all the corresponding merge-able
|
|
299
|
-
operations to
|
|
300
|
+
operations to its left.
|
|
300
301
|
|
|
301
302
|
If op1 and op2 are merged, both op1 and op2 are deleted from the circuit and
|
|
302
303
|
the resulting `merged_op` is inserted at the index corresponding to the larger
|
|
@@ -414,6 +414,17 @@ def test_map_operations_can_add_qubits_if_flag_false():
|
|
|
414
414
|
cirq.testing.assert_same_circuits(c_mapped, cirq.Circuit(cirq.CNOT(q[0], q[1])))
|
|
415
415
|
|
|
416
416
|
|
|
417
|
+
def test_map_operations_maps_different_ops_from_same_moment_to_shared_qubits():
|
|
418
|
+
q = cirq.LineQubit.range(3)
|
|
419
|
+
c = cirq.Circuit(cirq.H.on_each(q[:2]))
|
|
420
|
+
c_mapped = cirq.map_operations(
|
|
421
|
+
c, lambda op, _: op.controlled_by(q[2]), raise_if_add_qubits=False
|
|
422
|
+
)
|
|
423
|
+
cirq.testing.assert_same_circuits(
|
|
424
|
+
c_mapped, cirq.Circuit(cirq.H(q[0]).controlled_by(q[2]), cirq.H(q[1]).controlled_by(q[2]))
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
|
|
417
428
|
def test_map_operations_can_drop_operations():
|
|
418
429
|
q = cirq.LineQubit.range(2)
|
|
419
430
|
c = cirq.Circuit(cirq.X(q[0]), cirq.Y(q[1]), cirq.X(q[1]), cirq.Y(q[0]))
|
cirq/value/abc_alt.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
|
"""A more flexible abstract base class metaclass ABCMetaImplementAnyOneOf."""
|
|
15
16
|
|
|
16
17
|
import abc
|
|
@@ -91,9 +92,9 @@ class ABCMetaImplementAnyOneOf(abc.ABCMeta):
|
|
|
91
92
|
value = getattr(cls, name)
|
|
92
93
|
except AttributeError:
|
|
93
94
|
raise TypeError(
|
|
94
|
-
|
|
95
|
+
f"A method named '{name}' was listed as a possible "
|
|
95
96
|
'implementation alternative but it does not exist in the '
|
|
96
|
-
'definition of {!r}.'
|
|
97
|
+
f'definition of {cls!r}.'
|
|
97
98
|
)
|
|
98
99
|
if getattr(value, '__isabstractmethod__', False):
|
|
99
100
|
return False
|
cirq/value/abc_alt_test.py
CHANGED
cirq/value/classical_data.py
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
import abc
|
|
16
16
|
import enum
|
|
17
|
-
from typing import Dict, List, Mapping, Sequence, Tuple, TYPE_CHECKING
|
|
17
|
+
from typing import Dict, List, Mapping, Optional, Sequence, Tuple, TYPE_CHECKING
|
|
18
|
+
from typing_extensions import Self
|
|
18
19
|
|
|
19
20
|
from cirq.value import digits, value_equality_attr
|
|
20
21
|
|
|
@@ -38,10 +39,7 @@ class MeasurementType(enum.IntEnum):
|
|
|
38
39
|
CHANNEL = 2
|
|
39
40
|
|
|
40
41
|
def __repr__(self):
|
|
41
|
-
return f'cirq.{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
TSelf = TypeVar('TSelf', bound='ClassicalDataStoreReader')
|
|
42
|
+
return f'cirq.MeasurementType.{self.name}'
|
|
45
43
|
|
|
46
44
|
|
|
47
45
|
class ClassicalDataStoreReader(abc.ABC):
|
|
@@ -101,7 +99,7 @@ class ClassicalDataStoreReader(abc.ABC):
|
|
|
101
99
|
"""
|
|
102
100
|
|
|
103
101
|
@abc.abstractmethod
|
|
104
|
-
def copy(self
|
|
102
|
+
def copy(self) -> Self:
|
|
105
103
|
"""Creates a copy of the object."""
|
|
106
104
|
|
|
107
105
|
|
|
@@ -142,10 +140,12 @@ class ClassicalDataDictionaryStore(ClassicalDataStore):
|
|
|
142
140
|
def __init__(
|
|
143
141
|
self,
|
|
144
142
|
*,
|
|
145
|
-
_records: Dict['cirq.MeasurementKey', List[Tuple[int, ...]]] = None,
|
|
146
|
-
_measured_qubits:
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
_records: Optional[Dict['cirq.MeasurementKey', List[Tuple[int, ...]]]] = None,
|
|
144
|
+
_measured_qubits: Optional[
|
|
145
|
+
Dict['cirq.MeasurementKey', List[Tuple['cirq.Qid', ...]]]
|
|
146
|
+
] = None,
|
|
147
|
+
_channel_records: Optional[Dict['cirq.MeasurementKey', List[int]]] = None,
|
|
148
|
+
_measurement_types: Optional[Dict['cirq.MeasurementKey', 'cirq.MeasurementType']] = None,
|
|
149
149
|
):
|
|
150
150
|
"""Initializes a `ClassicalDataDictionaryStore` object."""
|
|
151
151
|
if not _measurement_types:
|