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
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Copyright 2024 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
|
+
"""Wraps Parallel Two Qubit XEB into a few convenience methods."""
|
|
15
|
+
from typing import Optional, Sequence, Dict
|
|
16
|
+
import itertools
|
|
17
|
+
import io
|
|
18
|
+
|
|
19
|
+
import matplotlib.pyplot as plt
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
import networkx as nx
|
|
23
|
+
import pandas as pd
|
|
24
|
+
import pytest
|
|
25
|
+
|
|
26
|
+
import cirq
|
|
27
|
+
from cirq.experiments.qubit_characterizations import ParallelRandomizedBenchmarkingResult
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _manhattan_distance(qubit1: 'cirq.GridQubit', qubit2: 'cirq.GridQubit') -> int:
|
|
31
|
+
return abs(qubit1.row - qubit2.row) + abs(qubit1.col - qubit2.col)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class MockDevice(cirq.Device):
|
|
35
|
+
@property
|
|
36
|
+
def metadata(self):
|
|
37
|
+
qubits = cirq.GridQubit.rect(3, 2, 4, 3)
|
|
38
|
+
graph = nx.Graph(
|
|
39
|
+
pair for pair in itertools.combinations(qubits, 2) if _manhattan_distance(*pair) == 1
|
|
40
|
+
)
|
|
41
|
+
return cirq.DeviceMetadata(qubits, graph)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class MockProcessor:
|
|
45
|
+
def get_device(self):
|
|
46
|
+
return MockDevice()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class DensityMatrixSimulatorWithProcessor(cirq.DensityMatrixSimulator):
|
|
50
|
+
@property
|
|
51
|
+
def processor(self):
|
|
52
|
+
return MockProcessor()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_parallel_two_qubit_xeb_simulator_without_processor_fails():
|
|
56
|
+
sampler = (
|
|
57
|
+
cirq.DensityMatrixSimulator(
|
|
58
|
+
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
with pytest.raises(ValueError):
|
|
63
|
+
_ = cirq.experiments.parallel_two_qubit_xeb(
|
|
64
|
+
sampler=sampler,
|
|
65
|
+
n_repetitions=1,
|
|
66
|
+
n_combinations=1,
|
|
67
|
+
n_circuits=1,
|
|
68
|
+
cycle_depths=[3, 4, 5],
|
|
69
|
+
random_state=0,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@pytest.mark.parametrize(
|
|
74
|
+
'sampler,qubits',
|
|
75
|
+
[
|
|
76
|
+
(
|
|
77
|
+
cirq.DensityMatrixSimulator(
|
|
78
|
+
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
|
|
79
|
+
),
|
|
80
|
+
cirq.GridQubit.rect(3, 2, 4, 3),
|
|
81
|
+
),
|
|
82
|
+
(
|
|
83
|
+
DensityMatrixSimulatorWithProcessor(
|
|
84
|
+
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
|
|
85
|
+
),
|
|
86
|
+
None,
|
|
87
|
+
),
|
|
88
|
+
],
|
|
89
|
+
)
|
|
90
|
+
def test_parallel_two_qubit_xeb(sampler: cirq.Sampler, qubits: Optional[Sequence[cirq.GridQubit]]):
|
|
91
|
+
res = cirq.experiments.parallel_two_qubit_xeb(
|
|
92
|
+
sampler=sampler,
|
|
93
|
+
qubits=qubits,
|
|
94
|
+
n_repetitions=100,
|
|
95
|
+
n_combinations=1,
|
|
96
|
+
n_circuits=1,
|
|
97
|
+
cycle_depths=[3, 4, 5],
|
|
98
|
+
random_state=0,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
got = [res.xeb_error(*reversed(pair)) for pair in res.all_qubit_pairs]
|
|
102
|
+
np.testing.assert_allclose(got, 0.1, atol=1e-1)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@pytest.mark.usefixtures('closefigures')
|
|
106
|
+
@pytest.mark.parametrize(
|
|
107
|
+
'sampler,qubits',
|
|
108
|
+
[
|
|
109
|
+
(cirq.DensityMatrixSimulator(seed=0), cirq.GridQubit.rect(3, 2, 4, 3)),
|
|
110
|
+
(DensityMatrixSimulatorWithProcessor(seed=0), None),
|
|
111
|
+
],
|
|
112
|
+
)
|
|
113
|
+
@pytest.mark.parametrize('ax', [None, plt.subplots(1, 1, figsize=(8, 8))[1]])
|
|
114
|
+
def test_plotting(sampler, qubits, ax):
|
|
115
|
+
res = cirq.experiments.parallel_two_qubit_xeb(
|
|
116
|
+
sampler=sampler,
|
|
117
|
+
qubits=qubits,
|
|
118
|
+
n_repetitions=1,
|
|
119
|
+
n_combinations=1,
|
|
120
|
+
n_circuits=1,
|
|
121
|
+
cycle_depths=[3, 4, 5],
|
|
122
|
+
random_state=0,
|
|
123
|
+
ax=ax,
|
|
124
|
+
)
|
|
125
|
+
res.plot_heatmap(ax=ax)
|
|
126
|
+
res.plot_fitted_exponential(cirq.GridQubit(4, 4), cirq.GridQubit(4, 3), ax=ax)
|
|
127
|
+
res.plot_histogram(ax=ax)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
_TEST_RESULT = cirq.experiments.TwoQubitXEBResult(
|
|
131
|
+
pd.read_csv(
|
|
132
|
+
io.StringIO(
|
|
133
|
+
"""layer_i,pair_i,pair,a,layer_fid,cycle_depths,fidelities,a_std,layer_fid_std
|
|
134
|
+
0,0,"(cirq.GridQubit(4, 4), cirq.GridQubit(5, 4))",,0.9,[],[],,
|
|
135
|
+
0,1,"(cirq.GridQubit(5, 3), cirq.GridQubit(6, 3))",,0.8,[],[],,
|
|
136
|
+
1,0,"(cirq.GridQubit(4, 3), cirq.GridQubit(5, 3))",,0.3,[],[],,
|
|
137
|
+
1,1,"(cirq.GridQubit(5, 4), cirq.GridQubit(6, 4))",,0.2,[],[],,
|
|
138
|
+
2,0,"(cirq.GridQubit(4, 3), cirq.GridQubit(4, 4))",,0.1,[],[],,
|
|
139
|
+
2,1,"(cirq.GridQubit(6, 3), cirq.GridQubit(6, 4))",,0.5,[],[],,
|
|
140
|
+
3,0,"(cirq.GridQubit(5, 3), cirq.GridQubit(5, 4))",,0.4,[],[],"""
|
|
141
|
+
),
|
|
142
|
+
index_col=[0, 1, 2],
|
|
143
|
+
converters={2: lambda s: eval(s)},
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@pytest.mark.parametrize(
|
|
149
|
+
'q0,q1,pauli',
|
|
150
|
+
[
|
|
151
|
+
(cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 1 / 8),
|
|
152
|
+
(cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 1 / 4),
|
|
153
|
+
(cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.8 + 3 / 40),
|
|
154
|
+
(cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 5 / 8),
|
|
155
|
+
],
|
|
156
|
+
)
|
|
157
|
+
def test_pauli_error(q0: cirq.GridQubit, q1: cirq.GridQubit, pauli: float):
|
|
158
|
+
assert _TEST_RESULT.pauli_error()[(q0, q1)] == pytest.approx(pauli)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class MockParallelRandomizedBenchmarkingResult(ParallelRandomizedBenchmarkingResult):
|
|
162
|
+
def pauli_error(self) -> Dict[cirq.Qid, float]:
|
|
163
|
+
return {
|
|
164
|
+
cirq.GridQubit(4, 4): 0.01,
|
|
165
|
+
cirq.GridQubit(5, 4): 0.02,
|
|
166
|
+
cirq.GridQubit(5, 3): 0.03,
|
|
167
|
+
cirq.GridQubit(5, 6): 0.04,
|
|
168
|
+
cirq.GridQubit(4, 3): 0.05,
|
|
169
|
+
cirq.GridQubit(6, 3): 0.06,
|
|
170
|
+
cirq.GridQubit(6, 4): 0.07,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@pytest.mark.parametrize(
|
|
175
|
+
'q0,q1,pauli',
|
|
176
|
+
[
|
|
177
|
+
(cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 1 / 8 - 0.03),
|
|
178
|
+
(cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 1 / 4 - 0.09),
|
|
179
|
+
(cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.8 + 3 / 40 - 0.08),
|
|
180
|
+
(cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 5 / 8 - 0.13),
|
|
181
|
+
],
|
|
182
|
+
)
|
|
183
|
+
def test_inferred_pauli_error(q0: cirq.GridQubit, q1: cirq.GridQubit, pauli: float):
|
|
184
|
+
combined_results = cirq.experiments.InferredXEBResult(
|
|
185
|
+
rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
assert combined_results.inferred_pauli_error()[(q0, q1)] == pytest.approx(pauli)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@pytest.mark.parametrize(
|
|
192
|
+
'q0,q1,xeb',
|
|
193
|
+
[
|
|
194
|
+
(cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 0.076),
|
|
195
|
+
(cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 0.128),
|
|
196
|
+
(cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.636),
|
|
197
|
+
(cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 0.396),
|
|
198
|
+
],
|
|
199
|
+
)
|
|
200
|
+
def test_inferred_xeb_error(q0: cirq.GridQubit, q1: cirq.GridQubit, xeb: float):
|
|
201
|
+
combined_results = cirq.experiments.InferredXEBResult(
|
|
202
|
+
rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
assert combined_results.inferred_xeb_error()[(q0, q1)] == pytest.approx(xeb)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def test_inferred_single_qubit_pauli():
|
|
209
|
+
combined_results = cirq.experiments.InferredXEBResult(
|
|
210
|
+
rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
assert combined_results.single_qubit_pauli_error() == {
|
|
214
|
+
cirq.GridQubit(4, 4): 0.01,
|
|
215
|
+
cirq.GridQubit(5, 4): 0.02,
|
|
216
|
+
cirq.GridQubit(5, 3): 0.03,
|
|
217
|
+
cirq.GridQubit(5, 6): 0.04,
|
|
218
|
+
cirq.GridQubit(4, 3): 0.05,
|
|
219
|
+
cirq.GridQubit(6, 3): 0.06,
|
|
220
|
+
cirq.GridQubit(6, 4): 0.07,
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
@pytest.mark.parametrize(
|
|
225
|
+
'q0,q1,pauli',
|
|
226
|
+
[
|
|
227
|
+
(cirq.GridQubit(4, 4), cirq.GridQubit(5, 4), 1 / 8),
|
|
228
|
+
(cirq.GridQubit(5, 3), cirq.GridQubit(6, 3), 1 / 4),
|
|
229
|
+
(cirq.GridQubit(4, 3), cirq.GridQubit(5, 3), 0.8 + 3 / 40),
|
|
230
|
+
(cirq.GridQubit(6, 3), cirq.GridQubit(6, 4), 5 / 8),
|
|
231
|
+
],
|
|
232
|
+
)
|
|
233
|
+
def test_inferred_two_qubit_pauli(q0: cirq.GridQubit, q1: cirq.GridQubit, pauli: float):
|
|
234
|
+
combined_results = cirq.experiments.InferredXEBResult(
|
|
235
|
+
rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
|
|
236
|
+
)
|
|
237
|
+
assert combined_results.two_qubit_pauli_error()[(q0, q1)] == pytest.approx(pauli)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@pytest.mark.parametrize('ax', [None, plt.subplots(1, 1, figsize=(8, 8))[1]])
|
|
241
|
+
@pytest.mark.parametrize('target_error', ['pauli', 'xeb', 'decay_constant'])
|
|
242
|
+
@pytest.mark.parametrize('kind', ['single_qubit', 'two_qubit', 'both', ''])
|
|
243
|
+
def test_inferred_plots(ax, target_error, kind):
|
|
244
|
+
combined_results = cirq.experiments.InferredXEBResult(
|
|
245
|
+
rb_result=MockParallelRandomizedBenchmarkingResult({}), xeb_result=_TEST_RESULT
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
combined_results.plot_heatmap(target_error=target_error, ax=ax)
|
|
249
|
+
|
|
250
|
+
raise_error = False
|
|
251
|
+
if kind not in ('single_qubit', 'two_qubit', 'both'):
|
|
252
|
+
raise_error = True
|
|
253
|
+
if kind != 'two_qubit' and target_error != 'pauli':
|
|
254
|
+
raise_error = True
|
|
255
|
+
|
|
256
|
+
if raise_error:
|
|
257
|
+
with pytest.raises(ValueError):
|
|
258
|
+
combined_results.plot_histogram(target_error=target_error, kind=kind, ax=ax)
|
|
259
|
+
else:
|
|
260
|
+
combined_results.plot_histogram(target_error=target_error, kind=kind, ax=ax)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@pytest.mark.parametrize(
|
|
264
|
+
'sampler,qubits',
|
|
265
|
+
[
|
|
266
|
+
(
|
|
267
|
+
cirq.DensityMatrixSimulator(
|
|
268
|
+
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
|
|
269
|
+
),
|
|
270
|
+
cirq.GridQubit.rect(3, 2, 4, 3),
|
|
271
|
+
),
|
|
272
|
+
(
|
|
273
|
+
DensityMatrixSimulatorWithProcessor(
|
|
274
|
+
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
|
|
275
|
+
),
|
|
276
|
+
None,
|
|
277
|
+
),
|
|
278
|
+
],
|
|
279
|
+
)
|
|
280
|
+
def test_run_rb_and_xeb(sampler: cirq.Sampler, qubits: Optional[Sequence[cirq.GridQubit]]):
|
|
281
|
+
res = cirq.experiments.run_rb_and_xeb(
|
|
282
|
+
sampler=sampler,
|
|
283
|
+
qubits=qubits,
|
|
284
|
+
repetitions=100,
|
|
285
|
+
num_clifford_range=tuple(np.arange(3, 10, 1)),
|
|
286
|
+
xeb_combinations=1,
|
|
287
|
+
num_circuits=1,
|
|
288
|
+
depths_xeb=(3, 4, 5),
|
|
289
|
+
random_state=0,
|
|
290
|
+
)
|
|
291
|
+
np.testing.assert_allclose(
|
|
292
|
+
[res.xeb_result.xeb_error(*pair) for pair in res.all_qubit_pairs], 0.1, atol=1e-1
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def test_run_rb_and_xeb_without_processor_fails():
|
|
297
|
+
sampler = (
|
|
298
|
+
cirq.DensityMatrixSimulator(
|
|
299
|
+
seed=0, noise=cirq.ConstantQubitNoiseModel(cirq.amplitude_damp(0.1))
|
|
300
|
+
),
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
with pytest.raises(ValueError):
|
|
304
|
+
_ = cirq.experiments.run_rb_and_xeb(sampler=sampler)
|
cirq/json_resolver_cache.py
CHANGED
|
@@ -157,6 +157,7 @@ def _class_resolver_dictionary() -> Dict[str, ObjectFactory]:
|
|
|
157
157
|
'LineTopology': cirq.LineTopology,
|
|
158
158
|
'Linspace': cirq.Linspace,
|
|
159
159
|
'ListSweep': cirq.ListSweep,
|
|
160
|
+
'cirq.MSGate': cirq.MSGate,
|
|
160
161
|
'MatrixGate': cirq.MatrixGate,
|
|
161
162
|
'MixedUnitaryChannel': cirq.MixedUnitaryChannel,
|
|
162
163
|
'MeasurementKey': cirq.MeasurementKey,
|
|
@@ -246,6 +247,7 @@ def _class_resolver_dictionary() -> Dict[str, ObjectFactory]:
|
|
|
246
247
|
'ZipLongest': cirq.ZipLongest,
|
|
247
248
|
'ZPowGate': cirq.ZPowGate,
|
|
248
249
|
'ZZPowGate': cirq.ZZPowGate,
|
|
250
|
+
'UniformSuperpositionGate': cirq.UniformSuperpositionGate,
|
|
249
251
|
# Old types, only supported for backwards-compatibility
|
|
250
252
|
'BooleanHamiltonian': _boolean_hamiltonian_gate_op, # Removed in v0.15
|
|
251
253
|
'CrossEntropyResult': _cross_entropy_result, # Removed in v0.16
|
cirq/linalg/decompositions.py
CHANGED
|
@@ -222,8 +222,9 @@ def kron_factor_4x4_to_2x2s(matrix: np.ndarray) -> Tuple[complex, np.ndarray, np
|
|
|
222
222
|
f2[(a & 1) ^ i, (b & 1) ^ j] = matrix[a ^ i, b ^ j]
|
|
223
223
|
|
|
224
224
|
# Rescale factors to have unit determinants.
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
226
|
+
f1 /= np.sqrt(np.linalg.det(f1)) or 1
|
|
227
|
+
f2 /= np.sqrt(np.linalg.det(f2)) or 1
|
|
227
228
|
|
|
228
229
|
# Determine global phase.
|
|
229
230
|
g = matrix[a, b] / (f1[a >> 1, b >> 1] * f2[a & 1, b & 1])
|
|
@@ -451,18 +452,14 @@ class KakDecomposition:
|
|
|
451
452
|
single_qubit_operations_after: a0, a1 from the above equation.
|
|
452
453
|
"""
|
|
453
454
|
self.global_phase: complex = global_phase
|
|
454
|
-
self.single_qubit_operations_before: Tuple[
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
np.eye(2, dtype=np.complex64),
|
|
458
|
-
np.eye(2, dtype=np.complex64),
|
|
455
|
+
self.single_qubit_operations_before: Tuple[np.ndarray, np.ndarray] = (
|
|
456
|
+
single_qubit_operations_before
|
|
457
|
+
or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
|
|
459
458
|
)
|
|
460
459
|
self.interaction_coefficients = interaction_coefficients
|
|
461
|
-
self.single_qubit_operations_after: Tuple[
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
np.eye(2, dtype=np.complex64),
|
|
465
|
-
np.eye(2, dtype=np.complex64),
|
|
460
|
+
self.single_qubit_operations_after: Tuple[np.ndarray, np.ndarray] = (
|
|
461
|
+
single_qubit_operations_after
|
|
462
|
+
or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
|
|
466
463
|
)
|
|
467
464
|
|
|
468
465
|
def _value_equality_values_(self) -> Any:
|
|
@@ -969,7 +966,8 @@ def kak_vector(
|
|
|
969
966
|
# The algorithm in the appendix mentioned above is slightly incorrect in
|
|
970
967
|
# that it only works for elements of SU(4). A phase correction must be
|
|
971
968
|
# added to deal with U(4).
|
|
972
|
-
|
|
969
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
970
|
+
phases = np.log(-1j * np.linalg.det(unitary)).imag + np.pi / 2
|
|
973
971
|
evals *= np.exp(-1j * phases / 2)[..., np.newaxis]
|
|
974
972
|
|
|
975
973
|
# The following steps follow the appendix exactly.
|
|
@@ -422,9 +422,7 @@ def test_axis_angle_decomposition_str():
|
|
|
422
422
|
assert (
|
|
423
423
|
str(
|
|
424
424
|
cirq.axis_angle(
|
|
425
|
-
cirq.unitary(cirq.X**0.25)
|
|
426
|
-
@ cirq.unitary(cirq.Y**0.25)
|
|
427
|
-
@ cirq.unitary(cirq.Z**0.25)
|
|
425
|
+
cirq.unitary(cirq.X**0.25) @ cirq.unitary(cirq.Y**0.25) @ cirq.unitary(cirq.Z**0.25)
|
|
428
426
|
)
|
|
429
427
|
)
|
|
430
428
|
== '0.477*π around 0.679*X+0.281*Y+0.679*Z'
|
cirq/linalg/diagonalize.py
CHANGED
|
@@ -255,10 +255,11 @@ def bidiagonalize_unitary_with_special_orthogonals(
|
|
|
255
255
|
)
|
|
256
256
|
|
|
257
257
|
# Convert to special orthogonal w/o breaking diagonalization.
|
|
258
|
-
|
|
259
|
-
left
|
|
260
|
-
|
|
261
|
-
right
|
|
258
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
259
|
+
if np.linalg.det(left) < 0:
|
|
260
|
+
left[0, :] *= -1
|
|
261
|
+
if np.linalg.det(right) < 0:
|
|
262
|
+
right[:, 0] *= -1
|
|
262
263
|
|
|
263
264
|
diag = combinators.dot(left, mat, right)
|
|
264
265
|
|
cirq/linalg/predicates.py
CHANGED
|
@@ -91,9 +91,10 @@ def is_special_orthogonal(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float
|
|
|
91
91
|
Returns:
|
|
92
92
|
Whether the matrix is special orthogonal within the given tolerance.
|
|
93
93
|
"""
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
95
|
+
return is_orthogonal(matrix, rtol=rtol, atol=atol) and (
|
|
96
|
+
matrix.shape[0] == 0 or np.allclose(np.linalg.det(matrix), 1, rtol=rtol, atol=atol)
|
|
97
|
+
)
|
|
97
98
|
|
|
98
99
|
|
|
99
100
|
def is_unitary(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8) -> bool:
|
|
@@ -128,9 +129,10 @@ def is_special_unitary(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float =
|
|
|
128
129
|
Whether the matrix is unitary with unit determinant within the given
|
|
129
130
|
tolerance.
|
|
130
131
|
"""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
133
|
+
return is_unitary(matrix, rtol=rtol, atol=atol) and (
|
|
134
|
+
matrix.shape[0] == 0 or np.allclose(np.linalg.det(matrix), 1, rtol=rtol, atol=atol)
|
|
135
|
+
)
|
|
134
136
|
|
|
135
137
|
|
|
136
138
|
def is_normal(matrix: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8) -> bool:
|
cirq/linalg/transformations.py
CHANGED
|
@@ -592,7 +592,8 @@ def to_special(u: np.ndarray) -> np.ndarray:
|
|
|
592
592
|
Returns:
|
|
593
593
|
the special unitary matrix
|
|
594
594
|
"""
|
|
595
|
-
|
|
595
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
596
|
+
return u * (np.linalg.det(u) ** (-1 / len(u)))
|
|
596
597
|
|
|
597
598
|
|
|
598
599
|
def state_vector_kronecker_product(t1: np.ndarray, t2: np.ndarray) -> np.ndarray:
|
|
@@ -584,7 +584,7 @@ def test_partial_trace_of_state_vector_as_mixture_mixed_result():
|
|
|
584
584
|
(0.5, np.array([1, 0, 0, 0]).reshape((2, 2))),
|
|
585
585
|
(0.5, np.array([0, 0, 0, 1]).reshape((2, 2))),
|
|
586
586
|
)
|
|
587
|
-
for
|
|
587
|
+
for q1, q2 in [(0, 1), (0, 2), (1, 2)]:
|
|
588
588
|
mixture = cirq.partial_trace_of_state_vector_as_mixture(state, [q1, q2], atol=1e-8)
|
|
589
589
|
assert mixtures_equal(mixture, truth)
|
|
590
590
|
|
cirq/ops/__init__.py
CHANGED
|
@@ -217,3 +217,5 @@ from cirq.ops.wait_gate import wait, WaitGate
|
|
|
217
217
|
from cirq.ops.state_preparation_channel import StatePreparationChannel
|
|
218
218
|
|
|
219
219
|
from cirq.ops.control_values import AbstractControlValues, ProductOfSums, SumOfProducts
|
|
220
|
+
|
|
221
|
+
from cirq.ops.uniform_superposition_gate import UniformSuperpositionGate
|
cirq/ops/clifford_gate.py
CHANGED
|
@@ -14,11 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
from typing import Any, Dict, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
import functools
|
|
18
|
+
from dataclasses import dataclass
|
|
18
19
|
import numpy as np
|
|
19
20
|
|
|
20
21
|
from cirq import protocols, value, linalg, qis
|
|
21
22
|
from cirq._import import LazyLoader
|
|
23
|
+
from cirq._compat import cached_method
|
|
22
24
|
from cirq.ops import common_gates, named_qubit, raw_types, pauli_gates, phased_x_z_gate
|
|
23
25
|
from cirq.ops.pauli_gates import Pauli
|
|
24
26
|
from cirq.type_workarounds import NotImplementedType
|
|
@@ -356,6 +358,8 @@ class CommonCliffordGates(metaclass=CommonCliffordGateMetaClass):
|
|
|
356
358
|
class CliffordGate(raw_types.Gate, CommonCliffordGates):
|
|
357
359
|
"""Clifford rotation for N-qubit."""
|
|
358
360
|
|
|
361
|
+
_clifford_tableau: qis.CliffordTableau
|
|
362
|
+
|
|
359
363
|
def __init__(self, *, _clifford_tableau: qis.CliffordTableau) -> None:
|
|
360
364
|
# We use the Clifford tableau to represent a Clifford gate.
|
|
361
365
|
# It is crucial to note that the meaning of tableau here is different
|
|
@@ -376,7 +380,7 @@ class CliffordGate(raw_types.Gate, CommonCliffordGates):
|
|
|
376
380
|
# more precisely the conjugate transformation of ZI by this gate, becomes -ZI.
|
|
377
381
|
# (Note the real clifford tableau has to satify the Symplectic property.
|
|
378
382
|
# here is just for illustration)
|
|
379
|
-
self
|
|
383
|
+
object.__setattr__(self, '_clifford_tableau', _clifford_tableau.copy())
|
|
380
384
|
|
|
381
385
|
@property
|
|
382
386
|
def clifford_tableau(self):
|
|
@@ -396,21 +400,37 @@ class CliffordGate(raw_types.Gate, CommonCliffordGates):
|
|
|
396
400
|
# By definition, Clifford Gate should always return True.
|
|
397
401
|
return True
|
|
398
402
|
|
|
399
|
-
def __pow__(self, exponent) -> 'CliffordGate':
|
|
403
|
+
def __pow__(self, exponent: float) -> 'CliffordGate':
|
|
404
|
+
if exponent != int(exponent):
|
|
405
|
+
return NotImplemented
|
|
406
|
+
exponent = int(exponent)
|
|
407
|
+
|
|
400
408
|
if exponent == -1:
|
|
401
409
|
return CliffordGate.from_clifford_tableau(self.clifford_tableau.inverse())
|
|
402
|
-
if exponent
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
410
|
+
if exponent == 0:
|
|
411
|
+
return CliffordGate.from_clifford_tableau(
|
|
412
|
+
qis.CliffordTableau(num_qubits=self._num_qubits_())
|
|
413
|
+
)
|
|
414
|
+
if exponent == 1:
|
|
415
|
+
return self
|
|
416
|
+
|
|
417
|
+
base_tableau = self.clifford_tableau.copy()
|
|
418
|
+
if exponent < 0:
|
|
419
|
+
base_tableau = base_tableau.inverse()
|
|
420
|
+
exponent = abs(exponent)
|
|
421
|
+
|
|
422
|
+
# https://cp-algorithms.com/algebra/binary-exp.html
|
|
423
|
+
aux = qis.CliffordTableau(
|
|
424
|
+
num_qubits=self.clifford_tableau.n
|
|
425
|
+
) # this tableau collects the odd terms
|
|
426
|
+
while exponent > 1:
|
|
427
|
+
if exponent & 1:
|
|
428
|
+
aux = aux.then(base_tableau)
|
|
429
|
+
base_tableau = base_tableau.then(base_tableau)
|
|
430
|
+
exponent >>= 1
|
|
431
|
+
|
|
432
|
+
base_tableau = base_tableau.then(aux)
|
|
433
|
+
return CliffordGate.from_clifford_tableau(base_tableau)
|
|
414
434
|
|
|
415
435
|
def __repr__(self) -> str:
|
|
416
436
|
return f"Clifford Gate with Tableau:\n {self.clifford_tableau._str_full_()}"
|
|
@@ -457,6 +477,7 @@ class CliffordGate(raw_types.Gate, CommonCliffordGates):
|
|
|
457
477
|
return NotImplemented
|
|
458
478
|
|
|
459
479
|
|
|
480
|
+
@dataclass(frozen=True, init=False, eq=False, repr=False)
|
|
460
481
|
@value.value_equality(manual_cls=True)
|
|
461
482
|
class SingleQubitCliffordGate(CliffordGate):
|
|
462
483
|
"""Any single qubit Clifford rotation."""
|
|
@@ -468,6 +489,7 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
468
489
|
return 1
|
|
469
490
|
|
|
470
491
|
@staticmethod
|
|
492
|
+
@functools.cache
|
|
471
493
|
def from_clifford_tableau(tableau: qis.CliffordTableau) -> 'SingleQubitCliffordGate':
|
|
472
494
|
if not isinstance(tableau, qis.CliffordTableau):
|
|
473
495
|
raise ValueError('Input argument has to be a CliffordTableau instance.')
|
|
@@ -679,6 +701,10 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
679
701
|
* {middle point of xyz in 4 Quadrant} * 120 is [[0, 1], [1, 1]]
|
|
680
702
|
* {middle point of xyz in 4 Quadrant} * 240 is [[1, 1], [1, 0]]
|
|
681
703
|
"""
|
|
704
|
+
return self._to_phased_xz_gate
|
|
705
|
+
|
|
706
|
+
@functools.cached_property
|
|
707
|
+
def _to_phased_xz_gate(self) -> phased_x_z_gate.PhasedXZGate:
|
|
682
708
|
x_to_flip, z_to_flip = self.clifford_tableau.rs
|
|
683
709
|
flip_index = int(z_to_flip) * 2 + x_to_flip
|
|
684
710
|
a, x, z = 0.0, 0.0, 0.0
|
|
@@ -716,7 +742,7 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
716
742
|
z = -0.5 if x_to_flip else 0.5
|
|
717
743
|
return phased_x_z_gate.PhasedXZGate(x_exponent=x, z_exponent=z, axis_phase_exponent=a)
|
|
718
744
|
|
|
719
|
-
def __pow__(self, exponent) -> 'SingleQubitCliffordGate':
|
|
745
|
+
def __pow__(self, exponent: Union[float, int]) -> 'SingleQubitCliffordGate':
|
|
720
746
|
# First to check if we can get the sqrt and negative sqrt Clifford.
|
|
721
747
|
if self._get_sqrt_map().get(exponent, None):
|
|
722
748
|
pow_gate = self._get_sqrt_map()[exponent].get(self, None)
|
|
@@ -761,6 +787,7 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
761
787
|
to, flip = self.pauli_tuple(pauli)
|
|
762
788
|
return to == pauli and not flip
|
|
763
789
|
|
|
790
|
+
@cached_method
|
|
764
791
|
def merged_with(self, second: 'SingleQubitCliffordGate') -> 'SingleQubitCliffordGate':
|
|
765
792
|
"""Returns a SingleQubitCliffordGate such that the circuits
|
|
766
793
|
--output-- and --self--second--
|
|
@@ -773,6 +800,10 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
773
800
|
return True
|
|
774
801
|
|
|
775
802
|
def _unitary_(self) -> np.ndarray:
|
|
803
|
+
return self._unitary
|
|
804
|
+
|
|
805
|
+
@functools.cached_property
|
|
806
|
+
def _unitary(self) -> np.ndarray:
|
|
776
807
|
mat = np.eye(2)
|
|
777
808
|
qubit = named_qubit.NamedQubit('arbitrary')
|
|
778
809
|
for op in protocols.decompose_once_with_qubits(self, (qubit,)):
|
|
@@ -787,6 +818,10 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
787
818
|
clifford gate if applied in order. This decomposition agrees with
|
|
788
819
|
cirq.unitary(self), including global phase.
|
|
789
820
|
"""
|
|
821
|
+
return self._decompose_gate
|
|
822
|
+
|
|
823
|
+
@functools.cached_property
|
|
824
|
+
def _decompose_gate(self) -> Sequence['cirq.Gate']:
|
|
790
825
|
if self == SingleQubitCliffordGate.H:
|
|
791
826
|
return [common_gates.H]
|
|
792
827
|
rotations = self.decompose_rotation()
|
|
@@ -802,6 +837,10 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
802
837
|
Note that the combined unitary effect of these rotations may
|
|
803
838
|
differ from cirq.unitary(self) by a global phase.
|
|
804
839
|
"""
|
|
840
|
+
return self._decompose_rotation
|
|
841
|
+
|
|
842
|
+
@functools.cached_property
|
|
843
|
+
def _decompose_rotation(self) -> Sequence[Tuple[Pauli, int]]:
|
|
805
844
|
x_rot = self.pauli_tuple(pauli_gates.X)
|
|
806
845
|
y_rot = self.pauli_tuple(pauli_gates.Y)
|
|
807
846
|
z_rot = self.pauli_tuple(pauli_gates.Z)
|
|
@@ -895,6 +934,10 @@ class SingleQubitCliffordGate(CliffordGate):
|
|
|
895
934
|
)
|
|
896
935
|
|
|
897
936
|
def _value_equality_values_(self):
|
|
937
|
+
return self._value_equality_values
|
|
938
|
+
|
|
939
|
+
@functools.cached_property
|
|
940
|
+
def _value_equality_values(self):
|
|
898
941
|
return self._clifford_tableau.matrix().tobytes() + self._clifford_tableau.rs.tobytes()
|
|
899
942
|
|
|
900
943
|
def _value_equality_values_cls_(self):
|
cirq/ops/common_gates_test.py
CHANGED
|
@@ -87,8 +87,7 @@ def test_cz_unitary():
|
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
assert np.allclose(
|
|
90
|
-
cirq.unitary(cirq.CZ**0),
|
|
91
|
-
np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]),
|
|
90
|
+
cirq.unitary(cirq.CZ**0), np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
|
|
92
91
|
)
|
|
93
92
|
|
|
94
93
|
assert np.allclose(
|
cirq/ops/control_values.py
CHANGED
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import abc
|
|
15
|
+
from functools import cached_property
|
|
15
16
|
from typing import Collection, Tuple, TYPE_CHECKING, Any, Dict, Iterator, Optional, Sequence, Union
|
|
16
17
|
import itertools
|
|
17
18
|
|
|
18
|
-
from cirq import protocols, value
|
|
19
|
+
from cirq import protocols, value
|
|
19
20
|
|
|
20
21
|
if TYPE_CHECKING:
|
|
21
22
|
import cirq
|
|
@@ -144,7 +145,7 @@ class ProductOfSums(AbstractControlValues):
|
|
|
144
145
|
(cv,) if isinstance(cv, int) else tuple(sorted(set(cv))) for cv in data
|
|
145
146
|
)
|
|
146
147
|
|
|
147
|
-
@
|
|
148
|
+
@cached_property
|
|
148
149
|
def is_trivial(self) -> bool:
|
|
149
150
|
return self._qubit_sums == ((1,),) * self._num_qubits_()
|
|
150
151
|
|
|
@@ -252,7 +253,7 @@ class SumOfProducts(AbstractControlValues):
|
|
|
252
253
|
if not all(len(p) == num_qubits for p in self._conjunctions):
|
|
253
254
|
raise ValueError(f'Each term of {self._conjunctions} should be of length {num_qubits}.')
|
|
254
255
|
|
|
255
|
-
@
|
|
256
|
+
@cached_property
|
|
256
257
|
def is_trivial(self) -> bool:
|
|
257
258
|
return self._conjunctions == ((1,) * self._num_qubits_(),)
|
|
258
259
|
|
cirq/ops/controlled_gate_test.py
CHANGED
|
@@ -452,9 +452,7 @@ def test_extrapolatable_effect():
|
|
|
452
452
|
|
|
453
453
|
assert cirq.ControlledGate(cirq.Z) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5)
|
|
454
454
|
|
|
455
|
-
assert cirq.ControlledGate(cirq.Z).on(a, b) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5).on(
|
|
456
|
-
a, b
|
|
457
|
-
)
|
|
455
|
+
assert cirq.ControlledGate(cirq.Z).on(a, b) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5).on(a, b)
|
|
458
456
|
|
|
459
457
|
assert cirq.ControlledGate(cirq.Z) ** 0.5 == cirq.ControlledGate(cirq.Z**0.5)
|
|
460
458
|
|