cirq-core 1.2.0.dev20230717225858__py3-none-any.whl → 1.3.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 +5 -0
- cirq/_compat.py +26 -11
- cirq/_compat_test.py +37 -3
- cirq/_version.py +31 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/circuit.py +106 -32
- cirq/circuits/circuit_operation.py +2 -2
- cirq/circuits/circuit_operation_test.py +1 -1
- cirq/circuits/circuit_test.py +109 -3
- cirq/circuits/frozen_circuit.py +80 -5
- cirq/circuits/frozen_circuit_test.py +47 -2
- cirq/circuits/qasm_output_test.py +9 -9
- cirq/conftest.py +1 -2
- cirq/contrib/acquaintance/devices.py +1 -1
- cirq/contrib/hacks/disable_validation_test.py +1 -1
- cirq/contrib/noise_models/noise_models.py +1 -2
- cirq/contrib/paulistring/clifford_optimize.py +1 -1
- cirq/contrib/paulistring/clifford_target_gateset_test.py +4 -4
- cirq/contrib/qcircuit/qcircuit_pdf.py +1 -1
- cirq/contrib/quimb/density_matrix.py +2 -3
- cirq/contrib/quimb/grid_circuits.py +3 -3
- cirq/contrib/quimb/state_vector.py +3 -5
- cirq/contrib/routing/utils.py +1 -2
- cirq/contrib/svg/svg.py +4 -6
- cirq/devices/grid_qubit.py +49 -38
- cirq/devices/grid_qubit_test.py +1 -3
- cirq/devices/insertion_noise_model.py +21 -1
- cirq/devices/insertion_noise_model_test.py +6 -0
- cirq/devices/line_qubit.py +67 -40
- cirq/devices/named_topologies.py +8 -14
- cirq/devices/noise_properties.py +1 -1
- cirq/devices/noise_utils.py +7 -5
- cirq/devices/noise_utils_test.py +7 -0
- cirq/experiments/fidelity_estimation_test.py +1 -1
- cirq/experiments/qubit_characterizations.py +6 -5
- cirq/experiments/random_quantum_circuit_generation.py +1 -1
- cirq/experiments/random_quantum_circuit_generation_test.py +28 -1
- cirq/experiments/readout_confusion_matrix.py +6 -6
- cirq/experiments/xeb_fitting.py +3 -5
- cirq/experiments/xeb_fitting_test.py +2 -2
- cirq/experiments/xeb_sampling.py +1 -1
- cirq/interop/quirk/url_to_circuit.py +40 -38
- cirq/json_resolver_cache.py +2 -0
- cirq/linalg/decompositions.py +6 -5
- cirq/ops/__init__.py +2 -0
- cirq/ops/classically_controlled_operation.py +1 -1
- cirq/ops/clifford_gate.py +9 -9
- cirq/ops/clifford_gate_test.py +3 -4
- cirq/ops/common_channels.py +2 -5
- cirq/ops/common_channels_test.py +3 -5
- cirq/ops/common_gates_test.py +7 -7
- cirq/ops/controlled_operation_test.py +2 -2
- cirq/ops/dense_pauli_string.py +3 -0
- cirq/ops/eigen_gate_test.py +1 -3
- cirq/ops/fourier_transform.py +1 -2
- cirq/ops/fsim_gate.py +1 -1
- cirq/ops/gate_features_test.py +2 -2
- cirq/ops/gate_operation_test.py +1 -2
- cirq/ops/greedy_qubit_manager.py +86 -0
- cirq/ops/greedy_qubit_manager_test.py +98 -0
- cirq/ops/linear_combinations.py +1 -1
- cirq/ops/named_qubit.py +55 -18
- cirq/ops/parity_gates.py +65 -18
- cirq/ops/parity_gates_test.py +41 -2
- cirq/ops/pauli_gates.py +2 -2
- cirq/ops/pauli_string.py +3 -4
- cirq/ops/pauli_string_raw_types_test.py +3 -3
- cirq/ops/pauli_string_test.py +3 -4
- cirq/ops/random_gate_channel_test.py +3 -3
- cirq/ops/raw_types.py +1 -1
- cirq/ops/raw_types_test.py +5 -5
- cirq/ops/three_qubit_gates.py +12 -8
- cirq/protocols/act_on_protocol_test.py +9 -9
- cirq/protocols/apply_channel_protocol.py +9 -6
- cirq/protocols/apply_unitary_protocol_test.py +1 -1
- cirq/protocols/equal_up_to_global_phase_protocol_test.py +2 -2
- cirq/protocols/has_stabilizer_effect_protocol.py +52 -6
- cirq/protocols/has_stabilizer_effect_protocol_test.py +21 -8
- cirq/protocols/has_unitary_protocol_test.py +1 -3
- cirq/protocols/json_serialization.py +6 -6
- cirq/protocols/json_serialization_test.py +7 -14
- cirq/protocols/json_test_data/InsertionNoiseModel.json +91 -0
- cirq/protocols/json_test_data/InsertionNoiseModel.repr +4 -0
- cirq/protocols/json_test_data/OpIdentifier.json +45 -10
- cirq/protocols/json_test_data/OpIdentifier.repr +7 -1
- cirq/protocols/json_test_data/spec.py +4 -0
- cirq/protocols/measurement_key_protocol_test.py +1 -1
- cirq/protocols/unitary_protocol_test.py +13 -16
- cirq/qis/clifford_tableau.py +7 -8
- cirq/qis/measures.py +1 -1
- cirq/qis/states.py +2 -3
- cirq/sim/__init__.py +2 -0
- cirq/sim/classical_simulator.py +107 -0
- cirq/sim/classical_simulator_test.py +207 -0
- cirq/sim/clifford/clifford_simulator_test.py +7 -7
- cirq/sim/clifford/stabilizer_simulation_state.py +2 -2
- cirq/sim/clifford/stabilizer_state_ch_form.py +7 -7
- cirq/sim/density_matrix_simulation_state.py +19 -4
- cirq/sim/density_matrix_simulator_test.py +5 -13
- cirq/sim/simulation_state_test.py +13 -14
- cirq/sim/simulator_test.py +6 -9
- cirq/sim/state_vector_simulation_state.py +1 -1
- cirq/study/resolver.py +41 -41
- cirq/study/resolver_test.py +13 -12
- cirq/testing/__init__.py +4 -1
- cirq/testing/circuit_compare.py +1 -1
- cirq/testing/circuit_compare_test.py +11 -11
- cirq/testing/consistent_controlled_gate_op.py +15 -1
- cirq/testing/consistent_controlled_gate_op_test.py +12 -3
- cirq/testing/consistent_decomposition.py +0 -1
- cirq/testing/consistent_protocols.py +6 -1
- cirq/testing/consistent_protocols_test.py +5 -10
- cirq/testing/consistent_qasm.py +2 -4
- cirq/testing/consistent_qasm_test.py +2 -3
- cirq/testing/consistent_specified_has_unitary_test.py +1 -3
- cirq/testing/equals_tester.py +1 -1
- cirq/testing/equals_tester_test.py +5 -5
- cirq/testing/equivalent_repr_eval_test.py +1 -3
- cirq/testing/gate_features_test.py +6 -6
- cirq/testing/order_tester_test.py +1 -3
- cirq/testing/random_circuit_test.py +1 -3
- cirq/transformers/__init__.py +3 -0
- cirq/transformers/analytical_decompositions/__init__.py +1 -0
- cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +1 -2
- cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +2 -5
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +38 -0
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +18 -0
- cirq/transformers/expand_composite_test.py +4 -4
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +1 -1
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -2
- cirq/transformers/merge_k_qubit_gates_test.py +2 -2
- cirq/transformers/qubit_management_transformers.py +177 -0
- cirq/transformers/qubit_management_transformers_test.py +250 -0
- cirq/transformers/routing/route_circuit_cqc.py +23 -4
- cirq/transformers/routing/route_circuit_cqc_test.py +42 -0
- cirq/transformers/stratify.py +10 -11
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +10 -10
- cirq/transformers/target_gatesets/cz_gateset_test.py +8 -10
- cirq/transformers/transformer_primitives.py +138 -28
- cirq/value/abc_alt_test.py +4 -4
- cirq/value/duration.py +68 -37
- cirq/value/duration_test.py +2 -0
- cirq/value/measurement_key_test.py +1 -1
- cirq/value/product_state.py +4 -8
- cirq/value/value_equality_attr.py +12 -5
- cirq/vis/heatmap.py +7 -4
- cirq/vis/heatmap_test.py +14 -4
- cirq/vis/histogram.py +4 -4
- cirq/vis/state_histogram.py +10 -6
- cirq/vis/state_histogram_test.py +2 -0
- cirq/work/observable_measurement_data_test.py +1 -1
- cirq/work/observable_measurement_test.py +2 -2
- cirq/work/zeros_sampler.py +1 -1
- {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/METADATA +11 -19
- {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/RECORD +158 -150
- {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.2.0.dev20230717225858.dist-info → cirq_core-1.3.0.dist-info}/top_level.txt +0 -0
cirq/devices/grid_qubit.py
CHANGED
|
@@ -19,7 +19,7 @@ from typing_extensions import Self
|
|
|
19
19
|
|
|
20
20
|
import numpy as np
|
|
21
21
|
|
|
22
|
-
from cirq import
|
|
22
|
+
from cirq import ops, protocols
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
25
|
import cirq
|
|
@@ -29,9 +29,43 @@ if TYPE_CHECKING:
|
|
|
29
29
|
class _BaseGridQid(ops.Qid):
|
|
30
30
|
"""The Base class for `GridQid` and `GridQubit`."""
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
_row: int
|
|
33
|
+
_col: int
|
|
34
|
+
_dimension: int
|
|
35
|
+
_hash: Optional[int] = None
|
|
36
|
+
|
|
37
|
+
def __getstate__(self):
|
|
38
|
+
# Don't save hash when pickling; see #3777.
|
|
39
|
+
state = self.__dict__
|
|
40
|
+
if "_hash" in state:
|
|
41
|
+
state = state.copy()
|
|
42
|
+
del state["_hash"]
|
|
43
|
+
return state
|
|
44
|
+
|
|
45
|
+
def __hash__(self) -> int:
|
|
46
|
+
if self._hash is None:
|
|
47
|
+
self._hash = hash((self._row, self._col, self._dimension))
|
|
48
|
+
return self._hash
|
|
49
|
+
|
|
50
|
+
def __eq__(self, other):
|
|
51
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
52
|
+
if isinstance(other, _BaseGridQid):
|
|
53
|
+
return (
|
|
54
|
+
self._row == other._row
|
|
55
|
+
and self._col == other._col
|
|
56
|
+
and self._dimension == other._dimension
|
|
57
|
+
)
|
|
58
|
+
return NotImplemented
|
|
59
|
+
|
|
60
|
+
def __ne__(self, other):
|
|
61
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
62
|
+
if isinstance(other, _BaseGridQid):
|
|
63
|
+
return (
|
|
64
|
+
self._row != other._row
|
|
65
|
+
or self._col != other._col
|
|
66
|
+
or self._dimension != other._dimension
|
|
67
|
+
)
|
|
68
|
+
return NotImplemented
|
|
35
69
|
|
|
36
70
|
def _comparison_key(self):
|
|
37
71
|
return self._row, self._col
|
|
@@ -44,6 +78,10 @@ class _BaseGridQid(ops.Qid):
|
|
|
44
78
|
def col(self) -> int:
|
|
45
79
|
return self._col
|
|
46
80
|
|
|
81
|
+
@property
|
|
82
|
+
def dimension(self) -> int:
|
|
83
|
+
return self._dimension
|
|
84
|
+
|
|
47
85
|
def with_dimension(self, dimension: int) -> 'GridQid':
|
|
48
86
|
return GridQid(self._row, self._col, dimension=dimension)
|
|
49
87
|
|
|
@@ -149,13 +187,10 @@ class GridQid(_BaseGridQid):
|
|
|
149
187
|
dimension: The dimension of the qid's Hilbert space, i.e.
|
|
150
188
|
the number of quantum levels.
|
|
151
189
|
"""
|
|
152
|
-
super().__init__(row, col)
|
|
153
|
-
self._dimension = dimension
|
|
154
190
|
self.validate_dimension(dimension)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return self._dimension
|
|
191
|
+
self._row = row
|
|
192
|
+
self._col = col
|
|
193
|
+
self._dimension = dimension
|
|
159
194
|
|
|
160
195
|
def _with_row_col(self, row: int, col: int) -> 'GridQid':
|
|
161
196
|
return GridQid(row, col, dimension=self.dimension)
|
|
@@ -288,35 +323,11 @@ class GridQubit(_BaseGridQid):
|
|
|
288
323
|
cirq.GridQubit(5, 4)
|
|
289
324
|
"""
|
|
290
325
|
|
|
291
|
-
|
|
292
|
-
# Don't save hash when pickling; see #3777.
|
|
293
|
-
state = self.__dict__
|
|
294
|
-
hash_key = _compat._method_cache_name(self.__hash__)
|
|
295
|
-
if hash_key in state:
|
|
296
|
-
state = state.copy()
|
|
297
|
-
del state[hash_key]
|
|
298
|
-
return state
|
|
299
|
-
|
|
300
|
-
@_compat.cached_method
|
|
301
|
-
def __hash__(self) -> int:
|
|
302
|
-
# Explicitly cached for performance (vs delegating to Qid).
|
|
303
|
-
return super().__hash__()
|
|
326
|
+
_dimension = 2
|
|
304
327
|
|
|
305
|
-
def
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return self._row == other._row and self._col == other._col
|
|
309
|
-
return NotImplemented
|
|
310
|
-
|
|
311
|
-
def __ne__(self, other):
|
|
312
|
-
# Explicitly implemented for performance (vs delegating to Qid).
|
|
313
|
-
if isinstance(other, GridQubit):
|
|
314
|
-
return self._row != other._row or self._col != other._col
|
|
315
|
-
return NotImplemented
|
|
316
|
-
|
|
317
|
-
@property
|
|
318
|
-
def dimension(self) -> int:
|
|
319
|
-
return 2
|
|
328
|
+
def __init__(self, row: int, col: int) -> None:
|
|
329
|
+
self._row = row
|
|
330
|
+
self._col = col
|
|
320
331
|
|
|
321
332
|
def _with_row_col(self, row: int, col: int):
|
|
322
333
|
return GridQubit(row, col)
|
cirq/devices/grid_qubit_test.py
CHANGED
|
@@ -19,7 +19,6 @@ import numpy as np
|
|
|
19
19
|
import pytest
|
|
20
20
|
|
|
21
21
|
import cirq
|
|
22
|
-
from cirq import _compat
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
def test_init():
|
|
@@ -45,8 +44,7 @@ def test_pickled_hash():
|
|
|
45
44
|
q = cirq.GridQubit(3, 4)
|
|
46
45
|
q_bad = cirq.GridQubit(3, 4)
|
|
47
46
|
_ = hash(q_bad) # compute hash to ensure it is cached.
|
|
48
|
-
|
|
49
|
-
setattr(q_bad, hash_key, getattr(q_bad, hash_key) + 1)
|
|
47
|
+
q_bad._hash = q_bad._hash + 1
|
|
50
48
|
assert q_bad == q
|
|
51
49
|
assert hash(q_bad) != hash(q)
|
|
52
50
|
data = pickle.dumps(q_bad)
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import dataclasses
|
|
16
|
-
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence
|
|
17
17
|
|
|
18
18
|
from cirq import devices
|
|
19
19
|
from cirq.devices import noise_utils
|
|
@@ -74,3 +74,23 @@ class InsertionNoiseModel(devices.NoiseModel):
|
|
|
74
74
|
if self.prepend:
|
|
75
75
|
return [*noise_steps.moments, moment]
|
|
76
76
|
return [moment, *noise_steps.moments]
|
|
77
|
+
|
|
78
|
+
def __repr__(self) -> str:
|
|
79
|
+
return (
|
|
80
|
+
f'cirq.devices.InsertionNoiseModel(ops_added={self.ops_added},'
|
|
81
|
+
+ f' prepend={self.prepend},'
|
|
82
|
+
+ f' require_physical_tag={self.require_physical_tag})'
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def _json_dict_(self) -> Dict[str, Any]:
|
|
86
|
+
return {
|
|
87
|
+
'ops_added': list(self.ops_added.items()),
|
|
88
|
+
'prepend': self.prepend,
|
|
89
|
+
'require_physical_tag': self.require_physical_tag,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def _from_json_dict_(cls, ops_added, prepend, require_physical_tag, **kwargs):
|
|
94
|
+
return cls(
|
|
95
|
+
ops_added=dict(ops_added), prepend=prepend, require_physical_tag=require_physical_tag
|
|
96
|
+
)
|
|
@@ -47,6 +47,8 @@ def test_insertion_noise():
|
|
|
47
47
|
moment_3 = cirq.Moment(cirq.Z(q0), cirq.X(q1))
|
|
48
48
|
assert model.noisy_moment(moment_3, system_qubits=[q0, q1]) == [moment_3]
|
|
49
49
|
|
|
50
|
+
cirq.testing.assert_equivalent_repr(model)
|
|
51
|
+
|
|
50
52
|
|
|
51
53
|
def test_colliding_noise_qubits():
|
|
52
54
|
# Check that noise affecting other qubits doesn't cause issues.
|
|
@@ -61,6 +63,8 @@ def test_colliding_noise_qubits():
|
|
|
61
63
|
cirq.Moment(cirq.CNOT(q1, q2)),
|
|
62
64
|
]
|
|
63
65
|
|
|
66
|
+
cirq.testing.assert_equivalent_repr(model)
|
|
67
|
+
|
|
64
68
|
|
|
65
69
|
def test_prepend():
|
|
66
70
|
q0, q1 = cirq.LineQubit.range(2)
|
|
@@ -106,3 +110,5 @@ def test_supertype_matching():
|
|
|
106
110
|
|
|
107
111
|
moment_1 = cirq.Moment(cirq.Y(q0))
|
|
108
112
|
assert model.noisy_moment(moment_1, system_qubits=[q0]) == [moment_1, cirq.Moment(cirq.T(q0))]
|
|
113
|
+
|
|
114
|
+
cirq.testing.assert_equivalent_repr(model)
|
cirq/devices/line_qubit.py
CHANGED
|
@@ -27,19 +27,48 @@ if TYPE_CHECKING:
|
|
|
27
27
|
class _BaseLineQid(ops.Qid):
|
|
28
28
|
"""The base class for `LineQid` and `LineQubit`."""
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
_x: int
|
|
31
|
+
_dimension: int
|
|
32
|
+
_hash: Optional[int] = None
|
|
33
|
+
|
|
34
|
+
def __getstate__(self):
|
|
35
|
+
# Don't save hash when pickling; see #3777.
|
|
36
|
+
state = self.__dict__
|
|
37
|
+
if "_hash" in state:
|
|
38
|
+
state = state.copy()
|
|
39
|
+
del state["_hash"]
|
|
40
|
+
return state
|
|
41
|
+
|
|
42
|
+
def __hash__(self) -> int:
|
|
43
|
+
if self._hash is None:
|
|
44
|
+
self._hash = hash((self._x, self._dimension))
|
|
45
|
+
return self._hash
|
|
46
|
+
|
|
47
|
+
def __eq__(self, other):
|
|
48
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
49
|
+
if isinstance(other, _BaseLineQid):
|
|
50
|
+
return self._x == other._x and self._dimension == other._dimension
|
|
51
|
+
return NotImplemented
|
|
52
|
+
|
|
53
|
+
def __ne__(self, other):
|
|
54
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
55
|
+
if isinstance(other, _BaseLineQid):
|
|
56
|
+
return self._x != other._x or self._dimension != other._dimension
|
|
57
|
+
return NotImplemented
|
|
33
58
|
|
|
34
59
|
def _comparison_key(self):
|
|
35
|
-
return self.
|
|
60
|
+
return self._x
|
|
36
61
|
|
|
37
62
|
@property
|
|
38
63
|
def x(self) -> int:
|
|
39
64
|
return self._x
|
|
40
65
|
|
|
66
|
+
@property
|
|
67
|
+
def dimension(self) -> int:
|
|
68
|
+
return self._dimension
|
|
69
|
+
|
|
41
70
|
def with_dimension(self, dimension: int) -> 'LineQid':
|
|
42
|
-
return LineQid(self.
|
|
71
|
+
return LineQid(self._x, dimension)
|
|
43
72
|
|
|
44
73
|
def is_adjacent(self, other: 'cirq.Qid') -> bool:
|
|
45
74
|
"""Determines if two qubits are adjacent line qubits.
|
|
@@ -49,7 +78,7 @@ class _BaseLineQid(ops.Qid):
|
|
|
49
78
|
|
|
50
79
|
Returns: True iff other and self are adjacent.
|
|
51
80
|
"""
|
|
52
|
-
return isinstance(other, _BaseLineQid) and abs(self.
|
|
81
|
+
return isinstance(other, _BaseLineQid) and abs(self._x - other._x) == 1
|
|
53
82
|
|
|
54
83
|
def neighbors(self, qids: Optional[Iterable[ops.Qid]] = None) -> Set['_BaseLineQid']:
|
|
55
84
|
"""Returns qubits that are potential neighbors to this LineQubit
|
|
@@ -57,11 +86,7 @@ class _BaseLineQid(ops.Qid):
|
|
|
57
86
|
Args:
|
|
58
87
|
qids: optional Iterable of qubits to constrain neighbors to.
|
|
59
88
|
"""
|
|
60
|
-
|
|
61
|
-
for q in [self - 1, self + 1]:
|
|
62
|
-
if qids is None or q in qids:
|
|
63
|
-
neighbors.add(q)
|
|
64
|
-
return neighbors
|
|
89
|
+
return {q for q in [self - 1, self + 1] if qids is None or q in qids}
|
|
65
90
|
|
|
66
91
|
@abc.abstractmethod
|
|
67
92
|
def _with_x(self, x: int) -> Self:
|
|
@@ -69,29 +94,29 @@ class _BaseLineQid(ops.Qid):
|
|
|
69
94
|
|
|
70
95
|
def __add__(self, other: Union[int, Self]) -> Self:
|
|
71
96
|
if isinstance(other, _BaseLineQid):
|
|
72
|
-
if self.
|
|
97
|
+
if self._dimension != other._dimension:
|
|
73
98
|
raise TypeError(
|
|
74
99
|
"Can only add LineQids with identical dimension. "
|
|
75
|
-
f"Got {self.
|
|
100
|
+
f"Got {self._dimension} and {other._dimension}"
|
|
76
101
|
)
|
|
77
|
-
return self._with_x(x=self.
|
|
102
|
+
return self._with_x(x=self._x + other._x)
|
|
78
103
|
if not isinstance(other, int):
|
|
79
104
|
raise TypeError(f"Can only add ints and {type(self).__name__}. Instead was {other}")
|
|
80
|
-
return self._with_x(self.
|
|
105
|
+
return self._with_x(self._x + other)
|
|
81
106
|
|
|
82
107
|
def __sub__(self, other: Union[int, Self]) -> Self:
|
|
83
108
|
if isinstance(other, _BaseLineQid):
|
|
84
|
-
if self.
|
|
109
|
+
if self._dimension != other._dimension:
|
|
85
110
|
raise TypeError(
|
|
86
111
|
"Can only subtract LineQids with identical dimension. "
|
|
87
|
-
f"Got {self.
|
|
112
|
+
f"Got {self._dimension} and {other._dimension}"
|
|
88
113
|
)
|
|
89
|
-
return self._with_x(x=self.
|
|
114
|
+
return self._with_x(x=self._x - other._x)
|
|
90
115
|
if not isinstance(other, int):
|
|
91
116
|
raise TypeError(
|
|
92
117
|
f"Can only subtract ints and {type(self).__name__}. Instead was {other}"
|
|
93
118
|
)
|
|
94
|
-
return self._with_x(self.
|
|
119
|
+
return self._with_x(self._x - other)
|
|
95
120
|
|
|
96
121
|
def __radd__(self, other: int) -> Self:
|
|
97
122
|
return self + other
|
|
@@ -100,16 +125,16 @@ class _BaseLineQid(ops.Qid):
|
|
|
100
125
|
return -self + other
|
|
101
126
|
|
|
102
127
|
def __neg__(self) -> Self:
|
|
103
|
-
return self._with_x(-self.
|
|
128
|
+
return self._with_x(-self._x)
|
|
104
129
|
|
|
105
130
|
def __complex__(self) -> complex:
|
|
106
|
-
return complex(self.
|
|
131
|
+
return complex(self._x)
|
|
107
132
|
|
|
108
133
|
def __float__(self) -> float:
|
|
109
|
-
return float(self.
|
|
134
|
+
return float(self._x)
|
|
110
135
|
|
|
111
136
|
def __int__(self) -> int:
|
|
112
|
-
return int(self.
|
|
137
|
+
return int(self._x)
|
|
113
138
|
|
|
114
139
|
|
|
115
140
|
class LineQid(_BaseLineQid):
|
|
@@ -137,16 +162,12 @@ class LineQid(_BaseLineQid):
|
|
|
137
162
|
dimension: The dimension of the qid's Hilbert space, i.e.
|
|
138
163
|
the number of quantum levels.
|
|
139
164
|
"""
|
|
140
|
-
super().__init__(x)
|
|
141
|
-
self._dimension = dimension
|
|
142
165
|
self.validate_dimension(dimension)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
def dimension(self):
|
|
146
|
-
return self._dimension
|
|
166
|
+
self._x = x
|
|
167
|
+
self._dimension = dimension
|
|
147
168
|
|
|
148
169
|
def _with_x(self, x: int) -> 'LineQid':
|
|
149
|
-
return LineQid(x, dimension=self.
|
|
170
|
+
return LineQid(x, dimension=self._dimension)
|
|
150
171
|
|
|
151
172
|
@staticmethod
|
|
152
173
|
def range(*range_args, dimension: int) -> List['LineQid']:
|
|
@@ -192,15 +213,15 @@ class LineQid(_BaseLineQid):
|
|
|
192
213
|
return LineQid.for_qid_shape(qid_shape(val), start=start, step=step)
|
|
193
214
|
|
|
194
215
|
def __repr__(self) -> str:
|
|
195
|
-
return f"cirq.LineQid({self.
|
|
216
|
+
return f"cirq.LineQid({self._x}, dimension={self._dimension})"
|
|
196
217
|
|
|
197
218
|
def __str__(self) -> str:
|
|
198
|
-
return f"q({self.
|
|
219
|
+
return f"q({self._x}) (d={self._dimension})"
|
|
199
220
|
|
|
200
221
|
def _circuit_diagram_info_(
|
|
201
222
|
self, args: 'cirq.CircuitDiagramInfoArgs'
|
|
202
223
|
) -> 'cirq.CircuitDiagramInfo':
|
|
203
|
-
return protocols.CircuitDiagramInfo(wire_symbols=(f"{self.
|
|
224
|
+
return protocols.CircuitDiagramInfo(wire_symbols=(f"{self._x} (d={self._dimension})",))
|
|
204
225
|
|
|
205
226
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
206
227
|
return protocols.obj_to_dict_helper(self, ['x', 'dimension'])
|
|
@@ -223,9 +244,15 @@ class LineQubit(_BaseLineQid):
|
|
|
223
244
|
|
|
224
245
|
"""
|
|
225
246
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
247
|
+
_dimension = 2
|
|
248
|
+
|
|
249
|
+
def __init__(self, x: int) -> None:
|
|
250
|
+
"""Initializes a line qubit at the given x coordinate.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
x: The x coordinate.
|
|
254
|
+
"""
|
|
255
|
+
self._x = x
|
|
229
256
|
|
|
230
257
|
def _with_x(self, x: int) -> 'LineQubit':
|
|
231
258
|
return LineQubit(x)
|
|
@@ -234,7 +261,7 @@ class LineQubit(_BaseLineQid):
|
|
|
234
261
|
cls = LineQid if type(self) is LineQubit else type(self)
|
|
235
262
|
# Must be the same as Qid._cmp_tuple but with cls in place of
|
|
236
263
|
# type(self).
|
|
237
|
-
return (cls.__name__, repr(cls), self._comparison_key(), self.
|
|
264
|
+
return (cls.__name__, repr(cls), self._comparison_key(), self._dimension)
|
|
238
265
|
|
|
239
266
|
@staticmethod
|
|
240
267
|
def range(*range_args) -> List['LineQubit']:
|
|
@@ -249,15 +276,15 @@ class LineQubit(_BaseLineQid):
|
|
|
249
276
|
return [LineQubit(i) for i in range(*range_args)]
|
|
250
277
|
|
|
251
278
|
def __repr__(self) -> str:
|
|
252
|
-
return f"cirq.LineQubit({self.
|
|
279
|
+
return f"cirq.LineQubit({self._x})"
|
|
253
280
|
|
|
254
281
|
def __str__(self) -> str:
|
|
255
|
-
return f"q({self.
|
|
282
|
+
return f"q({self._x})"
|
|
256
283
|
|
|
257
284
|
def _circuit_diagram_info_(
|
|
258
285
|
self, args: 'cirq.CircuitDiagramInfoArgs'
|
|
259
286
|
) -> 'cirq.CircuitDiagramInfo':
|
|
260
|
-
return protocols.CircuitDiagramInfo(wire_symbols=(f"{self.
|
|
287
|
+
return protocols.CircuitDiagramInfo(wire_symbols=(f"{self._x}",))
|
|
261
288
|
|
|
262
289
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
263
290
|
return protocols.obj_to_dict_helper(self, ['x'])
|
cirq/devices/named_topologies.py
CHANGED
|
@@ -74,7 +74,7 @@ def _node_and_coordinates(
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
def draw_gridlike(
|
|
77
|
-
graph: nx.Graph, ax: plt.Axes = None, tilted: bool = True, **kwargs
|
|
77
|
+
graph: nx.Graph, ax: Optional[plt.Axes] = None, tilted: bool = True, **kwargs
|
|
78
78
|
) -> Dict[Any, Tuple[int, int]]:
|
|
79
79
|
"""Draw a grid-like graph using Matplotlib.
|
|
80
80
|
|
|
@@ -93,7 +93,7 @@ def draw_gridlike(
|
|
|
93
93
|
to NetworkX plotting functionality.
|
|
94
94
|
"""
|
|
95
95
|
if ax is None:
|
|
96
|
-
ax = plt.gca() #
|
|
96
|
+
ax = plt.gca() # pragma: no cover
|
|
97
97
|
|
|
98
98
|
if tilted:
|
|
99
99
|
pos = {node: (y, -x) for node, (x, y) in _node_and_coordinates(graph.nodes)}
|
|
@@ -295,8 +295,7 @@ def get_placements(
|
|
|
295
295
|
for big_to_small_map in matcher.subgraph_monomorphisms_iter():
|
|
296
296
|
dedupe[frozenset(big_to_small_map.keys())] = big_to_small_map
|
|
297
297
|
if len(dedupe) > max_placements:
|
|
298
|
-
#
|
|
299
|
-
raise ValueError(
|
|
298
|
+
raise ValueError( # pragma: no cover
|
|
300
299
|
f"We found more than {max_placements} placements. Please use a "
|
|
301
300
|
f"more constraining `big_graph` or a more constrained `small_graph`."
|
|
302
301
|
)
|
|
@@ -367,27 +366,23 @@ def draw_placements(
|
|
|
367
366
|
this callback is called. The callback should accept `ax` and `i` keyword arguments
|
|
368
367
|
for the current axis and mapping index, respectively.
|
|
369
368
|
"""
|
|
370
|
-
if len(small_to_big_mappings) > max_plots:
|
|
371
|
-
# coverage: ignore
|
|
369
|
+
if len(small_to_big_mappings) > max_plots: # pragma: no cover
|
|
372
370
|
warnings.warn(f"You've provided a lot of mappings. Only plotting the first {max_plots}")
|
|
373
371
|
small_to_big_mappings = small_to_big_mappings[:max_plots]
|
|
374
372
|
|
|
375
373
|
call_show = False
|
|
376
374
|
if axes is None:
|
|
377
|
-
#
|
|
378
|
-
call_show = True
|
|
375
|
+
call_show = True # pragma: no cover
|
|
379
376
|
|
|
380
377
|
for i, small_to_big_map in enumerate(small_to_big_mappings):
|
|
381
378
|
if axes is not None:
|
|
382
379
|
ax = axes[i]
|
|
383
|
-
else:
|
|
384
|
-
# coverage: ignore
|
|
380
|
+
else: # pragma: no cover
|
|
385
381
|
ax = plt.gca()
|
|
386
382
|
|
|
387
383
|
small_mapped = nx.relabel_nodes(small_graph, small_to_big_map)
|
|
388
384
|
if bad_placement_callback is not None:
|
|
389
|
-
#
|
|
390
|
-
if not _is_valid_placement_helper(
|
|
385
|
+
if not _is_valid_placement_helper( # pragma: no cover
|
|
391
386
|
big_graph=big_graph,
|
|
392
387
|
small_mapped=small_mapped,
|
|
393
388
|
small_to_big_mapping=small_to_big_map,
|
|
@@ -406,7 +401,6 @@ def draw_placements(
|
|
|
406
401
|
)
|
|
407
402
|
ax.axis('equal')
|
|
408
403
|
if call_show:
|
|
409
|
-
# coverage: ignore
|
|
410
404
|
# poor man's multi-axis figure: call plt.show() after each plot
|
|
411
405
|
# and jupyter will put the plots one after another.
|
|
412
|
-
plt.show()
|
|
406
|
+
plt.show() # pragma: no cover
|
cirq/devices/noise_properties.py
CHANGED
|
@@ -97,7 +97,7 @@ class NoiseModelFromNoiseProperties(devices.NoiseModel):
|
|
|
97
97
|
# only ops with PHYSICAL_GATE_TAG will receive noise.
|
|
98
98
|
if virtual_ops:
|
|
99
99
|
# Only subclasses will trigger this case.
|
|
100
|
-
new_moments.append(circuits.Moment(virtual_ops)) #
|
|
100
|
+
new_moments.append(circuits.Moment(virtual_ops)) # pragma: no cover
|
|
101
101
|
if physical_ops:
|
|
102
102
|
new_moments.append(circuits.Moment(physical_ops))
|
|
103
103
|
|
cirq/devices/noise_utils.py
CHANGED
|
@@ -16,6 +16,7 @@ from typing import TYPE_CHECKING, Any, Dict, Tuple, Type, Union
|
|
|
16
16
|
import numpy as np
|
|
17
17
|
|
|
18
18
|
from cirq import ops, protocols, value
|
|
19
|
+
from cirq._compat import proper_repr
|
|
19
20
|
|
|
20
21
|
if TYPE_CHECKING:
|
|
21
22
|
import cirq
|
|
@@ -78,20 +79,21 @@ class OpIdentifier:
|
|
|
78
79
|
return f'{self.gate_type}{self.qubits}'
|
|
79
80
|
|
|
80
81
|
def __repr__(self) -> str:
|
|
81
|
-
fullname = f'{self.gate_type.__module__}.{self.gate_type.__qualname__}'
|
|
82
82
|
qubits = ', '.join(map(repr, self.qubits))
|
|
83
|
-
return f'cirq.devices.noise_utils.OpIdentifier({
|
|
83
|
+
return f'cirq.devices.noise_utils.OpIdentifier({proper_repr(self.gate_type)}, {qubits})'
|
|
84
84
|
|
|
85
85
|
def _value_equality_values_(self) -> Any:
|
|
86
86
|
return (self.gate_type, self.qubits)
|
|
87
87
|
|
|
88
88
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
if hasattr(self.gate_type, '__name__'):
|
|
90
|
+
return {'gate_type': protocols.json_cirq_type(self._gate_type), 'qubits': self._qubits}
|
|
91
|
+
return {'gate_type': self._gate_type, 'qubits': self._qubits}
|
|
91
92
|
|
|
92
93
|
@classmethod
|
|
93
94
|
def _from_json_dict_(cls, gate_type, qubits, **kwargs) -> 'OpIdentifier':
|
|
94
|
-
|
|
95
|
+
if isinstance(gate_type, str):
|
|
96
|
+
gate_type = protocols.cirq_type_from_json(gate_type)
|
|
95
97
|
return cls(gate_type, *qubits)
|
|
96
98
|
|
|
97
99
|
|
cirq/devices/noise_utils_test.py
CHANGED
|
@@ -62,6 +62,13 @@ def test_op_id_swap():
|
|
|
62
62
|
assert cirq.CZ(q1, q0) in swap_id
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
def test_op_id_instance():
|
|
66
|
+
q0 = cirq.LineQubit.range(1)[0]
|
|
67
|
+
gate = cirq.SingleQubitCliffordGate.from_xz_map((cirq.X, False), (cirq.Z, False))
|
|
68
|
+
op_id = OpIdentifier(gate, q0)
|
|
69
|
+
cirq.testing.assert_equivalent_repr(op_id)
|
|
70
|
+
|
|
71
|
+
|
|
65
72
|
@pytest.mark.parametrize(
|
|
66
73
|
'decay_constant,num_qubits,expected_output',
|
|
67
74
|
[(0.01, 1, 1 - (0.99 * 1 / 2)), (0.05, 2, 1 - (0.95 * 3 / 4))],
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
import dataclasses
|
|
16
16
|
import itertools
|
|
17
17
|
|
|
18
|
-
from typing import Any, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING
|
|
18
|
+
from typing import Any, cast, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING
|
|
19
19
|
import numpy as np
|
|
20
20
|
|
|
21
21
|
from matplotlib import pyplot as plt
|
|
22
22
|
|
|
23
23
|
# this is for older systems with matplotlib <3.2 otherwise 3d projections fail
|
|
24
|
-
from mpl_toolkits import mplot3d
|
|
24
|
+
from mpl_toolkits import mplot3d
|
|
25
25
|
from cirq import circuits, ops, protocols
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
@@ -89,8 +89,9 @@ class RandomizedBenchMarkResult:
|
|
|
89
89
|
"""
|
|
90
90
|
show_plot = not ax
|
|
91
91
|
if not ax:
|
|
92
|
-
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
|
|
93
|
-
|
|
92
|
+
fig, ax = plt.subplots(1, 1, figsize=(8, 8)) # pragma: no cover
|
|
93
|
+
ax = cast(plt.Axes, ax) # pragma: no cover
|
|
94
|
+
ax.set_ylim((0.0, 1.0)) # pragma: no cover
|
|
94
95
|
ax.plot(self._num_cfds_seq, self._gnd_state_probs, 'ro-', **plot_kwargs)
|
|
95
96
|
ax.set_xlabel(r"Number of Cliffords")
|
|
96
97
|
ax.set_ylabel('Ground State Probability')
|
|
@@ -541,7 +542,7 @@ def _find_inv_matrix(mat: np.ndarray, mat_sequence: np.ndarray) -> int:
|
|
|
541
542
|
def _matrix_bar_plot(
|
|
542
543
|
mat: np.ndarray,
|
|
543
544
|
z_label: str,
|
|
544
|
-
ax:
|
|
545
|
+
ax: mplot3d.axes3d.Axes3D,
|
|
545
546
|
kets: Optional[Sequence[str]] = None,
|
|
546
547
|
title: Optional[str] = None,
|
|
547
548
|
ylim: Tuple[int, int] = (-1, 1),
|
|
@@ -259,6 +259,30 @@ class FakeSycamoreGate(cirq.FSimGate):
|
|
|
259
259
|
'seed, expected_circuit_length, single_qubit_layers_slice, '
|
|
260
260
|
'two_qubit_layers_slice',
|
|
261
261
|
(
|
|
262
|
+
(
|
|
263
|
+
(cirq.q(0, 0), cirq.q(0, 1), cirq.q(0, 2)),
|
|
264
|
+
4,
|
|
265
|
+
lambda a, b, _: cirq.CZ(a, b),
|
|
266
|
+
[[(cirq.q(0, 0), cirq.q(0, 1))], [(cirq.q(0, 1), cirq.q(0, 2))]],
|
|
267
|
+
(cirq.X**0.5,),
|
|
268
|
+
True,
|
|
269
|
+
1234,
|
|
270
|
+
9,
|
|
271
|
+
slice(None, None, 2),
|
|
272
|
+
slice(1, None, 2),
|
|
273
|
+
),
|
|
274
|
+
(
|
|
275
|
+
(cirq.q(0, 0), cirq.q(0, 1), cirq.q(0, 2)),
|
|
276
|
+
4,
|
|
277
|
+
lambda a, b, _: cirq.CZ(a, b),
|
|
278
|
+
[[(cirq.q(0, 1), cirq.q(0, 0))], [(cirq.q(0, 1), cirq.q(0, 2))]],
|
|
279
|
+
(cirq.X**0.5,),
|
|
280
|
+
True,
|
|
281
|
+
1234,
|
|
282
|
+
9,
|
|
283
|
+
slice(None, None, 2),
|
|
284
|
+
slice(1, None, 2),
|
|
285
|
+
),
|
|
262
286
|
(
|
|
263
287
|
cirq.GridQubit.rect(4, 3),
|
|
264
288
|
20,
|
|
@@ -406,7 +430,10 @@ def _validate_two_qubit_layers(
|
|
|
406
430
|
# Operation is two-qubit
|
|
407
431
|
assert cirq.num_qubits(op) == 2
|
|
408
432
|
# Operation fits pattern
|
|
409
|
-
assert
|
|
433
|
+
assert (
|
|
434
|
+
op.qubits in pattern[i % len(pattern)]
|
|
435
|
+
or op.qubits[::-1] in pattern[i % len(pattern)]
|
|
436
|
+
)
|
|
410
437
|
active_pairs.add(op.qubits)
|
|
411
438
|
# All interactions that should be in this layer are present
|
|
412
439
|
assert all(
|
|
@@ -278,7 +278,7 @@ class TensoredConfusionMatrices:
|
|
|
278
278
|
raise ValueError(f"method: {method} should be 'pseudo_inverse' or 'least_squares'.")
|
|
279
279
|
|
|
280
280
|
if method == 'pseudo_inverse':
|
|
281
|
-
return result @ self.correction_matrix(qubits) #
|
|
281
|
+
return result @ self.correction_matrix(qubits) # pragma: no cover
|
|
282
282
|
|
|
283
283
|
# Least squares minimization.
|
|
284
284
|
cm = self.confusion_matrix(qubits)
|
|
@@ -291,11 +291,11 @@ class TensoredConfusionMatrices:
|
|
|
291
291
|
res = scipy.optimize.minimize(
|
|
292
292
|
func, result, method='SLSQP', constraints=constraints, bounds=bounds
|
|
293
293
|
)
|
|
294
|
-
if res.success is False: #
|
|
295
|
-
raise ValueError( #
|
|
296
|
-
f"SLSQP optimization for constrained minimization " #
|
|
297
|
-
f"did not converge. Result:\n{res}" #
|
|
298
|
-
) #
|
|
294
|
+
if res.success is False: # pragma: no cover
|
|
295
|
+
raise ValueError( # pragma: no cover
|
|
296
|
+
f"SLSQP optimization for constrained minimization " # pragma: no cover
|
|
297
|
+
f"did not converge. Result:\n{res}" # pragma: no cover
|
|
298
|
+
) # pragma: no cover
|
|
299
299
|
return res.x
|
|
300
300
|
|
|
301
301
|
def __repr__(self) -> str:
|