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.
Potentially problematic release.
This version of cirq-core might be problematic. Click here for more details.
- cirq/__init__.py +4 -0
- cirq/_compat.py +9 -11
- cirq/_compat_test.py +45 -56
- cirq/_version.py +31 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/circuit.py +13 -8
- cirq/circuits/circuit_operation.py +2 -1
- cirq/circuits/circuit_test.py +2 -2
- cirq/circuits/frozen_circuit.py +3 -2
- cirq/circuits/moment.py +12 -10
- cirq/circuits/qasm_output.py +5 -1
- cirq/circuits/qasm_output_test.py +25 -10
- cirq/contrib/qcircuit/qcircuit_diagram_info.py +9 -7
- cirq/contrib/quimb/mps_simulator_test.py +1 -1
- cirq/contrib/quimb/state_vector.py +9 -2
- cirq/contrib/svg/svg.py +2 -1
- cirq/contrib/svg/svg_test.py +1 -0
- cirq/devices/grid_qubit.py +85 -32
- cirq/devices/grid_qubit_test.py +22 -4
- cirq/devices/line_qubit.py +74 -26
- cirq/devices/line_qubit_test.py +19 -0
- cirq/devices/noise_utils.py +33 -31
- cirq/devices/noise_utils_test.py +1 -84
- cirq/devices/superconducting_qubits_noise_properties.py +7 -6
- cirq/experiments/__init__.py +8 -0
- cirq/experiments/qubit_characterizations.py +288 -44
- cirq/experiments/qubit_characterizations_test.py +61 -7
- cirq/experiments/random_quantum_circuit_generation.py +1 -1
- cirq/experiments/single_qubit_readout_calibration.py +132 -6
- cirq/experiments/single_qubit_readout_calibration_test.py +3 -1
- cirq/experiments/t1_decay_experiment.py +14 -7
- cirq/experiments/t1_decay_experiment_test.py +14 -26
- cirq/experiments/two_qubit_xeb.py +483 -0
- cirq/experiments/two_qubit_xeb_test.py +304 -0
- cirq/json_resolver_cache.py +2 -0
- cirq/linalg/decompositions.py +11 -13
- cirq/linalg/decompositions_test.py +1 -3
- cirq/linalg/diagonalize.py +5 -4
- cirq/linalg/predicates.py +8 -6
- cirq/linalg/transformations.py +2 -1
- cirq/linalg/transformations_test.py +1 -1
- cirq/ops/__init__.py +2 -0
- cirq/ops/clifford_gate.py +59 -16
- cirq/ops/common_gates_test.py +1 -2
- cirq/ops/control_values.py +4 -3
- cirq/ops/controlled_gate_test.py +1 -3
- cirq/ops/gate_operation.py +10 -1
- cirq/ops/named_qubit.py +74 -28
- cirq/ops/named_qubit_test.py +19 -0
- cirq/ops/parity_gates.py +5 -0
- cirq/ops/parity_gates_test.py +2 -10
- cirq/ops/pauli_gates.py +5 -2
- cirq/ops/pauli_string.py +2 -2
- cirq/ops/permutation_gate.py +16 -18
- cirq/ops/phased_iswap_gate_test.py +1 -3
- cirq/ops/phased_x_gate.py +1 -1
- cirq/ops/phased_x_z_gate.py +17 -1
- cirq/ops/phased_x_z_gate_test.py +24 -0
- cirq/ops/qid_util.py +4 -8
- cirq/ops/qubit_manager.py +7 -4
- cirq/ops/qubit_manager_test.py +20 -0
- cirq/ops/raw_types.py +5 -2
- cirq/ops/raw_types_test.py +14 -15
- cirq/ops/uniform_superposition_gate.py +123 -0
- cirq/ops/uniform_superposition_gate_test.py +94 -0
- cirq/protocols/approximate_equality_protocol_test.py +2 -2
- cirq/protocols/circuit_diagram_info_protocol.py +6 -4
- cirq/protocols/commutes_protocol.py +2 -4
- cirq/protocols/decompose_protocol.py +7 -12
- cirq/protocols/decompose_protocol_test.py +7 -3
- cirq/protocols/has_stabilizer_effect_protocol.py +1 -5
- cirq/protocols/has_stabilizer_effect_protocol_test.py +13 -4
- cirq/protocols/json_serialization.py +51 -181
- cirq/protocols/json_serialization_test.py +13 -47
- cirq/protocols/json_test_data/CircuitOperation.json +131 -148
- cirq/protocols/json_test_data/CircuitOperation.json_inward +55 -0
- cirq/protocols/json_test_data/CircuitOperation.repr_inward +6 -0
- cirq/protocols/json_test_data/FrozenCircuit.json +196 -210
- cirq/protocols/json_test_data/FrozenCircuit.json_inward +35 -0
- cirq/protocols/json_test_data/FrozenCircuit.repr_inward +4 -0
- cirq/protocols/json_test_data/UniformSuperpositionGate.json +5 -0
- cirq/protocols/json_test_data/UniformSuperpositionGate.repr +1 -0
- cirq/protocols/json_test_data/cirq.MSGate.json +4 -0
- cirq/protocols/json_test_data/cirq.MSGate.repr +1 -0
- cirq/protocols/json_test_data/spec.py +2 -0
- cirq/protocols/pow_protocol_test.py +1 -3
- cirq/protocols/resolve_parameters.py +4 -2
- cirq/qis/__init__.py +10 -0
- cirq/qis/clifford_tableau.py +8 -2
- cirq/qis/noise_utils.py +123 -0
- cirq/qis/noise_utils_test.py +97 -0
- cirq/sim/classical_simulator.py +227 -87
- cirq/sim/classical_simulator_test.py +135 -0
- cirq/sim/clifford/clifford_simulator_test.py +4 -2
- cirq/sim/mux.py +5 -3
- cirq/sim/simulation_product_state.py +15 -10
- cirq/sim/simulation_state.py +1 -1
- cirq/sim/simulation_state_test.py +2 -2
- cirq/sim/simulator_base.py +3 -3
- cirq/sim/state_vector_simulation_state.py +4 -4
- cirq/sim/state_vector_simulator.py +17 -2
- cirq/study/__init__.py +1 -0
- cirq/study/result.py +14 -0
- cirq/study/result_test.py +6 -0
- cirq/study/sweeps.py +4 -2
- cirq/study/sweeps_test.py +8 -0
- cirq/testing/__init__.py +6 -1
- cirq/testing/_compat_test_data/__init__.py +3 -3
- cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
- cirq/testing/circuit_compare.py +1 -1
- cirq/testing/consistent_qasm.py +6 -0
- cirq/testing/gate_features.py +10 -0
- cirq/testing/lin_alg_utils.py +5 -3
- cirq/transformers/__init__.py +15 -0
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +3 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +24 -0
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +17 -0
- cirq/transformers/dynamical_decoupling.py +122 -0
- cirq/transformers/dynamical_decoupling_test.py +123 -0
- cirq/transformers/gauge_compiling/__init__.py +26 -0
- cirq/transformers/gauge_compiling/cz_gauge.py +46 -0
- cirq/transformers/gauge_compiling/cz_gauge_test.py +23 -0
- cirq/transformers/gauge_compiling/gauge_compiling.py +214 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +41 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +83 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +52 -0
- cirq/transformers/gauge_compiling/iswap_gauge.py +105 -0
- cirq/transformers/gauge_compiling/iswap_gauge_test.py +23 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge.py +33 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +37 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +64 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +27 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +94 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +22 -0
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +1 -0
- cirq/transformers/merge_k_qubit_gates_test.py +23 -23
- cirq/transformers/merge_single_qubit_gates_test.py +14 -14
- cirq/transformers/optimize_for_target_gateset.py +39 -17
- cirq/transformers/optimize_for_target_gateset_test.py +189 -39
- cirq/transformers/qubit_management_transformers.py +1 -1
- cirq/transformers/routing/visualize_routed_circuit_test.py +17 -17
- cirq/transformers/stratify_test.py +13 -13
- cirq/transformers/target_gatesets/compilation_target_gateset.py +26 -2
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +16 -16
- cirq/transformers/target_gatesets/cz_gateset.py +4 -0
- cirq/transformers/transformer_api.py +1 -2
- cirq/transformers/transformer_primitives.py +15 -14
- cirq/transformers/transformer_primitives_test.py +99 -72
- cirq/value/classical_data.py +6 -6
- cirq/value/value_equality_attr.py +4 -0
- cirq/work/sampler.py +3 -4
- cirq/work/sampler_test.py +25 -0
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.3.0.dev20231201164435.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
cirq/devices/grid_qubit.py
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import abc
|
|
16
16
|
import functools
|
|
17
|
+
import weakref
|
|
17
18
|
from typing import Any, Dict, Iterable, List, Optional, Tuple, Set, TYPE_CHECKING, Union
|
|
18
19
|
from typing_extensions import Self
|
|
19
20
|
|
|
@@ -32,43 +33,66 @@ class _BaseGridQid(ops.Qid):
|
|
|
32
33
|
_row: int
|
|
33
34
|
_col: int
|
|
34
35
|
_dimension: int
|
|
36
|
+
_comp_key: Optional[Tuple[int, int]] = None
|
|
35
37
|
_hash: Optional[int] = None
|
|
36
38
|
|
|
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
39
|
def __hash__(self) -> int:
|
|
46
40
|
if self._hash is None:
|
|
47
41
|
self._hash = hash((self._row, self._col, self._dimension))
|
|
48
42
|
return self._hash
|
|
49
43
|
|
|
50
|
-
def __eq__(self, other):
|
|
44
|
+
def __eq__(self, other) -> bool:
|
|
51
45
|
# Explicitly implemented for performance (vs delegating to Qid).
|
|
52
46
|
if isinstance(other, _BaseGridQid):
|
|
53
|
-
return (
|
|
47
|
+
return self is other or (
|
|
54
48
|
self._row == other._row
|
|
55
49
|
and self._col == other._col
|
|
56
50
|
and self._dimension == other._dimension
|
|
57
51
|
)
|
|
58
52
|
return NotImplemented
|
|
59
53
|
|
|
60
|
-
def __ne__(self, other):
|
|
54
|
+
def __ne__(self, other) -> bool:
|
|
61
55
|
# Explicitly implemented for performance (vs delegating to Qid).
|
|
62
56
|
if isinstance(other, _BaseGridQid):
|
|
63
|
-
return (
|
|
57
|
+
return self is not other and (
|
|
64
58
|
self._row != other._row
|
|
65
59
|
or self._col != other._col
|
|
66
60
|
or self._dimension != other._dimension
|
|
67
61
|
)
|
|
68
62
|
return NotImplemented
|
|
69
63
|
|
|
64
|
+
def __lt__(self, other) -> bool:
|
|
65
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
66
|
+
if isinstance(other, _BaseGridQid):
|
|
67
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
68
|
+
return k0 < k1 or (k0 == k1 and self._dimension < other._dimension)
|
|
69
|
+
return super().__lt__(other)
|
|
70
|
+
|
|
71
|
+
def __le__(self, other) -> bool:
|
|
72
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
73
|
+
if isinstance(other, _BaseGridQid):
|
|
74
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
75
|
+
return k0 < k1 or (k0 == k1 and self._dimension <= other._dimension)
|
|
76
|
+
return super().__le__(other)
|
|
77
|
+
|
|
78
|
+
def __ge__(self, other) -> bool:
|
|
79
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
80
|
+
if isinstance(other, _BaseGridQid):
|
|
81
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
82
|
+
return k0 > k1 or (k0 == k1 and self._dimension >= other._dimension)
|
|
83
|
+
return super().__ge__(other)
|
|
84
|
+
|
|
85
|
+
def __gt__(self, other) -> bool:
|
|
86
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
87
|
+
if isinstance(other, _BaseGridQid):
|
|
88
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
89
|
+
return k0 > k1 or (k0 == k1 and self._dimension > other._dimension)
|
|
90
|
+
return super().__gt__(other)
|
|
91
|
+
|
|
70
92
|
def _comparison_key(self):
|
|
71
|
-
|
|
93
|
+
if self._comp_key is None:
|
|
94
|
+
self._comp_key = self._row, self._col
|
|
95
|
+
return self._comp_key
|
|
72
96
|
|
|
73
97
|
@property
|
|
74
98
|
def row(self) -> int:
|
|
@@ -178,8 +202,12 @@ class GridQid(_BaseGridQid):
|
|
|
178
202
|
cirq.GridQid(5, 4, dimension=2)
|
|
179
203
|
"""
|
|
180
204
|
|
|
181
|
-
|
|
182
|
-
|
|
205
|
+
# Cache of existing GridQid instances, returned by __new__ if available.
|
|
206
|
+
# Holds weak references so instances can still be garbage collected.
|
|
207
|
+
_cache = weakref.WeakValueDictionary[Tuple[int, int, int], 'cirq.GridQid']()
|
|
208
|
+
|
|
209
|
+
def __new__(cls, row: int, col: int, *, dimension: int) -> 'cirq.GridQid':
|
|
210
|
+
"""Creates a grid qid at the given row, col coordinate
|
|
183
211
|
|
|
184
212
|
Args:
|
|
185
213
|
row: the row coordinate
|
|
@@ -187,13 +215,23 @@ class GridQid(_BaseGridQid):
|
|
|
187
215
|
dimension: The dimension of the qid's Hilbert space, i.e.
|
|
188
216
|
the number of quantum levels.
|
|
189
217
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
218
|
+
key = (row, col, dimension)
|
|
219
|
+
inst = cls._cache.get(key)
|
|
220
|
+
if inst is None:
|
|
221
|
+
cls.validate_dimension(dimension)
|
|
222
|
+
inst = super().__new__(cls)
|
|
223
|
+
inst._row = row
|
|
224
|
+
inst._col = col
|
|
225
|
+
inst._dimension = dimension
|
|
226
|
+
cls._cache[key] = inst
|
|
227
|
+
return inst
|
|
228
|
+
|
|
229
|
+
def __getnewargs_ex__(self):
|
|
230
|
+
"""Returns a tuple of (args, kwargs) to pass to __new__ when unpickling."""
|
|
231
|
+
return (self._row, self._col), {"dimension": self._dimension}
|
|
194
232
|
|
|
195
233
|
def _with_row_col(self, row: int, col: int) -> 'GridQid':
|
|
196
|
-
return GridQid(row, col, dimension=self.
|
|
234
|
+
return GridQid(row, col, dimension=self._dimension)
|
|
197
235
|
|
|
198
236
|
@staticmethod
|
|
199
237
|
def square(diameter: int, top: int = 0, left: int = 0, *, dimension: int) -> List['GridQid']:
|
|
@@ -290,16 +328,16 @@ class GridQid(_BaseGridQid):
|
|
|
290
328
|
return [GridQid(*c, dimension=dimension) for c in coords]
|
|
291
329
|
|
|
292
330
|
def __repr__(self) -> str:
|
|
293
|
-
return f"cirq.GridQid({self._row}, {self._col}, dimension={self.
|
|
331
|
+
return f"cirq.GridQid({self._row}, {self._col}, dimension={self._dimension})"
|
|
294
332
|
|
|
295
333
|
def __str__(self) -> str:
|
|
296
|
-
return f"q({self._row}, {self._col}) (d={self.
|
|
334
|
+
return f"q({self._row}, {self._col}) (d={self._dimension})"
|
|
297
335
|
|
|
298
336
|
def _circuit_diagram_info_(
|
|
299
337
|
self, args: 'cirq.CircuitDiagramInfoArgs'
|
|
300
338
|
) -> 'cirq.CircuitDiagramInfo':
|
|
301
339
|
return protocols.CircuitDiagramInfo(
|
|
302
|
-
wire_symbols=(f"({self._row}, {self._col}) (d={self.
|
|
340
|
+
wire_symbols=(f"({self._row}, {self._col}) (d={self._dimension})",)
|
|
303
341
|
)
|
|
304
342
|
|
|
305
343
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
@@ -325,17 +363,32 @@ class GridQubit(_BaseGridQid):
|
|
|
325
363
|
|
|
326
364
|
_dimension = 2
|
|
327
365
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
366
|
+
# Cache of existing GridQubit instances, returned by __new__ if available.
|
|
367
|
+
# Holds weak references so instances can still be garbage collected.
|
|
368
|
+
_cache = weakref.WeakValueDictionary[Tuple[int, int], 'cirq.GridQubit']()
|
|
331
369
|
|
|
332
|
-
def
|
|
333
|
-
|
|
370
|
+
def __new__(cls, row: int, col: int) -> 'cirq.GridQubit':
|
|
371
|
+
"""Creates a grid qubit at the given row, col coordinate
|
|
334
372
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
373
|
+
Args:
|
|
374
|
+
row: the row coordinate
|
|
375
|
+
col: the column coordinate
|
|
376
|
+
"""
|
|
377
|
+
key = (row, col)
|
|
378
|
+
inst = cls._cache.get(key)
|
|
379
|
+
if inst is None:
|
|
380
|
+
inst = super().__new__(cls)
|
|
381
|
+
inst._row = row
|
|
382
|
+
inst._col = col
|
|
383
|
+
cls._cache[key] = inst
|
|
384
|
+
return inst
|
|
385
|
+
|
|
386
|
+
def __getnewargs__(self):
|
|
387
|
+
"""Returns a tuple of args to pass to __new__ when unpickling."""
|
|
388
|
+
return (self._row, self._col)
|
|
389
|
+
|
|
390
|
+
def _with_row_col(self, row: int, col: int) -> 'GridQubit':
|
|
391
|
+
return GridQubit(row, col)
|
|
339
392
|
|
|
340
393
|
@staticmethod
|
|
341
394
|
def square(diameter: int, top: int = 0, left: int = 0) -> List['GridQubit']:
|
cirq/devices/grid_qubit_test.py
CHANGED
|
@@ -40,11 +40,29 @@ def test_eq():
|
|
|
40
40
|
eq.make_equality_group(lambda: cirq.GridQid(0, 0, dimension=3))
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
def
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
def test_grid_qubit_pickled_hash():
|
|
44
|
+
# Use a large number that is unlikely to be used by any other tests.
|
|
45
|
+
row, col = 123456789, 2345678910
|
|
46
|
+
q_bad = cirq.GridQubit(row, col)
|
|
47
|
+
cirq.GridQubit._cache.pop((row, col))
|
|
48
|
+
q = cirq.GridQubit(row, col)
|
|
49
|
+
_test_qid_pickled_hash(q, q_bad)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_grid_qid_pickled_hash():
|
|
53
|
+
# Use a large number that is unlikely to be used by any other tests.
|
|
54
|
+
row, col = 123456789, 2345678910
|
|
55
|
+
q_bad = cirq.GridQid(row, col, dimension=3)
|
|
56
|
+
cirq.GridQid._cache.pop((row, col, 3))
|
|
57
|
+
q = cirq.GridQid(row, col, dimension=3)
|
|
58
|
+
_test_qid_pickled_hash(q, q_bad)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _test_qid_pickled_hash(q: 'cirq.Qid', q_bad: 'cirq.Qid') -> None:
|
|
62
|
+
"""Test that hashes are not pickled with Qid instances."""
|
|
63
|
+
assert q_bad is not q
|
|
46
64
|
_ = hash(q_bad) # compute hash to ensure it is cached.
|
|
47
|
-
q_bad._hash = q_bad._hash + 1
|
|
65
|
+
q_bad._hash = q_bad._hash + 1 # type: ignore[attr-defined]
|
|
48
66
|
assert q_bad == q
|
|
49
67
|
assert hash(q_bad) != hash(q)
|
|
50
68
|
data = pickle.dumps(q_bad)
|
cirq/devices/line_qubit.py
CHANGED
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
import abc
|
|
16
16
|
import functools
|
|
17
|
-
|
|
17
|
+
import weakref
|
|
18
|
+
from typing import Any, Dict, Iterable, List, Optional, Sequence, Set, Tuple, TYPE_CHECKING, Union
|
|
18
19
|
from typing_extensions import Self
|
|
19
20
|
|
|
20
21
|
from cirq import ops, protocols
|
|
@@ -31,31 +32,57 @@ class _BaseLineQid(ops.Qid):
|
|
|
31
32
|
_dimension: int
|
|
32
33
|
_hash: Optional[int] = None
|
|
33
34
|
|
|
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
35
|
def __hash__(self) -> int:
|
|
43
36
|
if self._hash is None:
|
|
44
37
|
self._hash = hash((self._x, self._dimension))
|
|
45
38
|
return self._hash
|
|
46
39
|
|
|
47
|
-
def __eq__(self, other):
|
|
40
|
+
def __eq__(self, other) -> bool:
|
|
48
41
|
# Explicitly implemented for performance (vs delegating to Qid).
|
|
49
42
|
if isinstance(other, _BaseLineQid):
|
|
50
|
-
return self._x == other._x and self._dimension == other._dimension
|
|
43
|
+
return self is other or (self._x == other._x and self._dimension == other._dimension)
|
|
51
44
|
return NotImplemented
|
|
52
45
|
|
|
53
|
-
def __ne__(self, other):
|
|
46
|
+
def __ne__(self, other) -> bool:
|
|
54
47
|
# Explicitly implemented for performance (vs delegating to Qid).
|
|
55
48
|
if isinstance(other, _BaseLineQid):
|
|
56
|
-
return self
|
|
49
|
+
return self is not other and (
|
|
50
|
+
self._x != other._x or self._dimension != other._dimension
|
|
51
|
+
)
|
|
57
52
|
return NotImplemented
|
|
58
53
|
|
|
54
|
+
def __lt__(self, other) -> bool:
|
|
55
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
56
|
+
if isinstance(other, _BaseLineQid):
|
|
57
|
+
return self._x < other._x or (
|
|
58
|
+
self._x == other._x and self._dimension < other._dimension
|
|
59
|
+
)
|
|
60
|
+
return super().__lt__(other)
|
|
61
|
+
|
|
62
|
+
def __le__(self, other) -> bool:
|
|
63
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
64
|
+
if isinstance(other, _BaseLineQid):
|
|
65
|
+
return self._x < other._x or (
|
|
66
|
+
self._x == other._x and self._dimension <= other._dimension
|
|
67
|
+
)
|
|
68
|
+
return super().__le__(other)
|
|
69
|
+
|
|
70
|
+
def __ge__(self, other) -> bool:
|
|
71
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
72
|
+
if isinstance(other, _BaseLineQid):
|
|
73
|
+
return self._x > other._x or (
|
|
74
|
+
self._x == other._x and self._dimension >= other._dimension
|
|
75
|
+
)
|
|
76
|
+
return super().__ge__(other)
|
|
77
|
+
|
|
78
|
+
def __gt__(self, other) -> bool:
|
|
79
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
80
|
+
if isinstance(other, _BaseLineQid):
|
|
81
|
+
return self._x > other._x or (
|
|
82
|
+
self._x == other._x and self._dimension > other._dimension
|
|
83
|
+
)
|
|
84
|
+
return super().__gt__(other)
|
|
85
|
+
|
|
59
86
|
def _comparison_key(self):
|
|
60
87
|
return self._x
|
|
61
88
|
|
|
@@ -154,7 +181,11 @@ class LineQid(_BaseLineQid):
|
|
|
154
181
|
|
|
155
182
|
"""
|
|
156
183
|
|
|
157
|
-
|
|
184
|
+
# Cache of existing LineQid instances, returned by __new__ if available.
|
|
185
|
+
# Holds weak references so instances can still be garbage collected.
|
|
186
|
+
_cache = weakref.WeakValueDictionary[Tuple[int, int], 'cirq.LineQid']()
|
|
187
|
+
|
|
188
|
+
def __new__(cls, x: int, dimension: int) -> 'cirq.LineQid':
|
|
158
189
|
"""Initializes a line qid at the given x coordinate.
|
|
159
190
|
|
|
160
191
|
Args:
|
|
@@ -162,9 +193,19 @@ class LineQid(_BaseLineQid):
|
|
|
162
193
|
dimension: The dimension of the qid's Hilbert space, i.e.
|
|
163
194
|
the number of quantum levels.
|
|
164
195
|
"""
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
196
|
+
key = (x, dimension)
|
|
197
|
+
inst = cls._cache.get(key)
|
|
198
|
+
if inst is None:
|
|
199
|
+
cls.validate_dimension(dimension)
|
|
200
|
+
inst = super().__new__(cls)
|
|
201
|
+
inst._x = x
|
|
202
|
+
inst._dimension = dimension
|
|
203
|
+
cls._cache[key] = inst
|
|
204
|
+
return inst
|
|
205
|
+
|
|
206
|
+
def __getnewargs__(self):
|
|
207
|
+
"""Returns a tuple of args to pass to __new__ when unpickling."""
|
|
208
|
+
return (self._x, self._dimension)
|
|
168
209
|
|
|
169
210
|
def _with_x(self, x: int) -> 'LineQid':
|
|
170
211
|
return LineQid(x, dimension=self._dimension)
|
|
@@ -246,23 +287,30 @@ class LineQubit(_BaseLineQid):
|
|
|
246
287
|
|
|
247
288
|
_dimension = 2
|
|
248
289
|
|
|
249
|
-
|
|
250
|
-
|
|
290
|
+
# Cache of existing LineQubit instances, returned by __new__ if available.
|
|
291
|
+
# Holds weak references so instances can still be garbage collected.
|
|
292
|
+
_cache = weakref.WeakValueDictionary[int, 'cirq.LineQubit']()
|
|
293
|
+
|
|
294
|
+
def __new__(cls, x: int) -> 'cirq.LineQubit':
|
|
295
|
+
"""Initializes a line qid at the given x coordinate.
|
|
251
296
|
|
|
252
297
|
Args:
|
|
253
298
|
x: The x coordinate.
|
|
254
299
|
"""
|
|
255
|
-
|
|
300
|
+
inst = cls._cache.get(x)
|
|
301
|
+
if inst is None:
|
|
302
|
+
inst = super().__new__(cls)
|
|
303
|
+
inst._x = x
|
|
304
|
+
cls._cache[x] = inst
|
|
305
|
+
return inst
|
|
306
|
+
|
|
307
|
+
def __getnewargs__(self):
|
|
308
|
+
"""Returns a tuple of args to pass to __new__ when unpickling."""
|
|
309
|
+
return (self._x,)
|
|
256
310
|
|
|
257
311
|
def _with_x(self, x: int) -> 'LineQubit':
|
|
258
312
|
return LineQubit(x)
|
|
259
313
|
|
|
260
|
-
def _cmp_tuple(self):
|
|
261
|
-
cls = LineQid if type(self) is LineQubit else type(self)
|
|
262
|
-
# Must be the same as Qid._cmp_tuple but with cls in place of
|
|
263
|
-
# type(self).
|
|
264
|
-
return (cls.__name__, repr(cls), self._comparison_key(), self._dimension)
|
|
265
|
-
|
|
266
314
|
@staticmethod
|
|
267
315
|
def range(*range_args) -> List['LineQubit']:
|
|
268
316
|
"""Returns a range of line qubits.
|
cirq/devices/line_qubit_test.py
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import pytest
|
|
16
16
|
|
|
17
17
|
import cirq
|
|
18
|
+
from cirq.devices.grid_qubit_test import _test_qid_pickled_hash
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def test_init():
|
|
@@ -67,6 +68,24 @@ def test_cmp_failure():
|
|
|
67
68
|
_ = cirq.LineQid(1, 3) < 0
|
|
68
69
|
|
|
69
70
|
|
|
71
|
+
def test_line_qubit_pickled_hash():
|
|
72
|
+
# Use a large number that is unlikely to be used by any other tests.
|
|
73
|
+
x = 1234567891011
|
|
74
|
+
q_bad = cirq.LineQubit(x)
|
|
75
|
+
cirq.LineQubit._cache.pop(x)
|
|
76
|
+
q = cirq.LineQubit(x)
|
|
77
|
+
_test_qid_pickled_hash(q, q_bad)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_line_qid_pickled_hash():
|
|
81
|
+
# Use a large number that is unlikely to be used by any other tests.
|
|
82
|
+
x = 1234567891011
|
|
83
|
+
q_bad = cirq.LineQid(x, dimension=3)
|
|
84
|
+
cirq.LineQid._cache.pop((x, 3))
|
|
85
|
+
q = cirq.LineQid(x, dimension=3)
|
|
86
|
+
_test_qid_pickled_hash(q, q_bad)
|
|
87
|
+
|
|
88
|
+
|
|
70
89
|
def test_is_adjacent():
|
|
71
90
|
assert cirq.LineQubit(1).is_adjacent(cirq.LineQubit(2))
|
|
72
91
|
assert cirq.LineQubit(1).is_adjacent(cirq.LineQubit(0))
|
cirq/devices/noise_utils.py
CHANGED
|
@@ -13,10 +13,9 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from typing import TYPE_CHECKING, Any, Dict, Tuple, Type, Union
|
|
16
|
-
import numpy as np
|
|
17
16
|
|
|
18
|
-
from cirq import ops, protocols, value
|
|
19
|
-
from cirq._compat import proper_repr
|
|
17
|
+
from cirq import ops, protocols, value, qis
|
|
18
|
+
from cirq._compat import proper_repr, deprecated
|
|
20
19
|
|
|
21
20
|
if TYPE_CHECKING:
|
|
22
21
|
import cirq
|
|
@@ -97,8 +96,10 @@ class OpIdentifier:
|
|
|
97
96
|
return cls(gate_type, *qubits)
|
|
98
97
|
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
def decay_constant_to_xeb_fidelity(
|
|
99
|
+
@deprecated(deadline='v2.0', fix='use cirq.qis.decay_constant_to_xeb_fidelity')
|
|
100
|
+
def decay_constant_to_xeb_fidelity(
|
|
101
|
+
decay_constant: float, num_qubits: int = 2
|
|
102
|
+
) -> float: # pragma: no cover
|
|
102
103
|
"""Calculates the XEB fidelity from the depolarization decay constant.
|
|
103
104
|
|
|
104
105
|
Args:
|
|
@@ -108,11 +109,13 @@ def decay_constant_to_xeb_fidelity(decay_constant: float, num_qubits: int = 2) -
|
|
|
108
109
|
Returns:
|
|
109
110
|
Calculated XEB fidelity.
|
|
110
111
|
"""
|
|
111
|
-
|
|
112
|
-
return 1 - ((1 - decay_constant) * (1 - 1 / N))
|
|
112
|
+
return qis.decay_constant_to_xeb_fidelity(decay_constant, num_qubits)
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
@deprecated(deadline='v2.0', fix='use cirq.qis.decay_constant_to_pauli_error')
|
|
116
|
+
def decay_constant_to_pauli_error(
|
|
117
|
+
decay_constant: float, num_qubits: int = 1
|
|
118
|
+
) -> float: # pragma: no cover
|
|
116
119
|
"""Calculates pauli error from the depolarization decay constant.
|
|
117
120
|
|
|
118
121
|
Args:
|
|
@@ -122,11 +125,13 @@ def decay_constant_to_pauli_error(decay_constant: float, num_qubits: int = 1) ->
|
|
|
122
125
|
Returns:
|
|
123
126
|
Calculated Pauli error.
|
|
124
127
|
"""
|
|
125
|
-
|
|
126
|
-
return (1 - decay_constant) * (1 - 1 / N / N)
|
|
128
|
+
return qis.decay_constant_to_pauli_error(decay_constant, num_qubits)
|
|
127
129
|
|
|
128
130
|
|
|
129
|
-
|
|
131
|
+
@deprecated(deadline='v2.0', fix='use cirq.qis.pauli_error_to_decay_constant')
|
|
132
|
+
def pauli_error_to_decay_constant(
|
|
133
|
+
pauli_error: float, num_qubits: int = 1
|
|
134
|
+
) -> float: # pragma: no cover
|
|
130
135
|
"""Calculates depolarization decay constant from pauli error.
|
|
131
136
|
|
|
132
137
|
Args:
|
|
@@ -136,11 +141,13 @@ def pauli_error_to_decay_constant(pauli_error: float, num_qubits: int = 1) -> fl
|
|
|
136
141
|
Returns:
|
|
137
142
|
Calculated depolarization decay constant.
|
|
138
143
|
"""
|
|
139
|
-
|
|
140
|
-
return 1 - (pauli_error / (1 - 1 / N / N))
|
|
144
|
+
return qis.pauli_error_to_decay_constant(pauli_error, num_qubits)
|
|
141
145
|
|
|
142
146
|
|
|
143
|
-
|
|
147
|
+
@deprecated(deadline='v2.0', fix='use cirq.qis.xeb_fidelity_to_decay_constant')
|
|
148
|
+
def xeb_fidelity_to_decay_constant(
|
|
149
|
+
xeb_fidelity: float, num_qubits: int = 2
|
|
150
|
+
) -> float: # pragma: no cover
|
|
144
151
|
"""Calculates the depolarization decay constant from XEB fidelity.
|
|
145
152
|
|
|
146
153
|
Args:
|
|
@@ -150,11 +157,11 @@ def xeb_fidelity_to_decay_constant(xeb_fidelity: float, num_qubits: int = 2) ->
|
|
|
150
157
|
Returns:
|
|
151
158
|
Calculated depolarization decay constant.
|
|
152
159
|
"""
|
|
153
|
-
|
|
154
|
-
return 1 - (1 - xeb_fidelity) / (1 - 1 / N)
|
|
160
|
+
return qis.xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits)
|
|
155
161
|
|
|
156
162
|
|
|
157
|
-
|
|
163
|
+
@deprecated(deadline='v2.0', fix='use cirq.qis.pauli_error_from_t1')
|
|
164
|
+
def pauli_error_from_t1(t_ns: float, t1_ns: float) -> float: # pragma: no cover
|
|
158
165
|
"""Calculates the pauli error from T1 decay constant.
|
|
159
166
|
|
|
160
167
|
This computes error for a specific duration, `t`.
|
|
@@ -166,11 +173,11 @@ def pauli_error_from_t1(t_ns: float, t1_ns: float) -> float:
|
|
|
166
173
|
Returns:
|
|
167
174
|
Calculated Pauli error resulting from T1 decay.
|
|
168
175
|
"""
|
|
169
|
-
|
|
170
|
-
return (1 - np.exp(-t_ns / t2)) / 2 + (1 - np.exp(-t_ns / t1_ns)) / 4
|
|
176
|
+
return qis.pauli_error_from_t1(t_ns, t1_ns)
|
|
171
177
|
|
|
172
178
|
|
|
173
|
-
|
|
179
|
+
@deprecated(deadline='v2.0', fix='use cirq.qis.average_error')
|
|
180
|
+
def average_error(decay_constant: float, num_qubits: int = 1) -> float: # pragma: no cover
|
|
174
181
|
"""Calculates the average error from the depolarization decay constant.
|
|
175
182
|
|
|
176
183
|
Args:
|
|
@@ -180,11 +187,13 @@ def average_error(decay_constant: float, num_qubits: int = 1) -> float:
|
|
|
180
187
|
Returns:
|
|
181
188
|
Calculated average error.
|
|
182
189
|
"""
|
|
183
|
-
|
|
184
|
-
return (1 - decay_constant) * (1 - 1 / N)
|
|
190
|
+
return qis.average_error(decay_constant, num_qubits)
|
|
185
191
|
|
|
186
192
|
|
|
187
|
-
|
|
193
|
+
@deprecated(deadline='v2.0', fix='use cirq.qis.decoherence_pauli_error')
|
|
194
|
+
def decoherence_pauli_error(
|
|
195
|
+
t1_ns: float, tphi_ns: float, gate_time_ns: float
|
|
196
|
+
) -> float: # pragma: no cover
|
|
188
197
|
"""The component of Pauli error caused by decoherence on a single qubit.
|
|
189
198
|
|
|
190
199
|
Args:
|
|
@@ -195,11 +204,4 @@ def decoherence_pauli_error(t1_ns: float, tphi_ns: float, gate_time_ns: float) -
|
|
|
195
204
|
Returns:
|
|
196
205
|
Calculated Pauli error resulting from decoherence.
|
|
197
206
|
"""
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
exp1 = np.exp(-gate_time_ns / t1_ns)
|
|
201
|
-
exp2 = np.exp(-gate_time_ns * gamma_2)
|
|
202
|
-
px = 0.25 * (1 - exp1)
|
|
203
|
-
py = px
|
|
204
|
-
pz = 0.5 * (1 - exp2) - px
|
|
205
|
-
return px + py + pz
|
|
207
|
+
return qis.decoherence_pauli_error(t1_ns, tphi_ns, gate_time_ns)
|
cirq/devices/noise_utils_test.py
CHANGED
|
@@ -12,20 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
import numpy as np
|
|
16
|
-
import pytest
|
|
17
|
-
|
|
18
15
|
import cirq
|
|
19
|
-
from cirq.devices.noise_utils import
|
|
20
|
-
OpIdentifier,
|
|
21
|
-
decay_constant_to_xeb_fidelity,
|
|
22
|
-
decay_constant_to_pauli_error,
|
|
23
|
-
pauli_error_to_decay_constant,
|
|
24
|
-
xeb_fidelity_to_decay_constant,
|
|
25
|
-
pauli_error_from_t1,
|
|
26
|
-
average_error,
|
|
27
|
-
decoherence_pauli_error,
|
|
28
|
-
)
|
|
16
|
+
from cirq.devices.noise_utils import OpIdentifier
|
|
29
17
|
|
|
30
18
|
|
|
31
19
|
def test_op_identifier():
|
|
@@ -67,74 +55,3 @@ def test_op_id_instance():
|
|
|
67
55
|
gate = cirq.SingleQubitCliffordGate.from_xz_map((cirq.X, False), (cirq.Z, False))
|
|
68
56
|
op_id = OpIdentifier(gate, q0)
|
|
69
57
|
cirq.testing.assert_equivalent_repr(op_id)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
@pytest.mark.parametrize(
|
|
73
|
-
'decay_constant,num_qubits,expected_output',
|
|
74
|
-
[(0.01, 1, 1 - (0.99 * 1 / 2)), (0.05, 2, 1 - (0.95 * 3 / 4))],
|
|
75
|
-
)
|
|
76
|
-
def test_decay_constant_to_xeb_fidelity(decay_constant, num_qubits, expected_output):
|
|
77
|
-
val = decay_constant_to_xeb_fidelity(decay_constant, num_qubits)
|
|
78
|
-
assert val == expected_output
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@pytest.mark.parametrize(
|
|
82
|
-
'decay_constant,num_qubits,expected_output',
|
|
83
|
-
[(0.01, 1, 0.99 * 3 / 4), (0.05, 2, 0.95 * 15 / 16)],
|
|
84
|
-
)
|
|
85
|
-
def test_decay_constant_to_pauli_error(decay_constant, num_qubits, expected_output):
|
|
86
|
-
val = decay_constant_to_pauli_error(decay_constant, num_qubits)
|
|
87
|
-
assert val == expected_output
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
@pytest.mark.parametrize(
|
|
91
|
-
'pauli_error,num_qubits,expected_output',
|
|
92
|
-
[(0.01, 1, 1 - (0.01 / (3 / 4))), (0.05, 2, 1 - (0.05 / (15 / 16)))],
|
|
93
|
-
)
|
|
94
|
-
def test_pauli_error_to_decay_constant(pauli_error, num_qubits, expected_output):
|
|
95
|
-
val = pauli_error_to_decay_constant(pauli_error, num_qubits)
|
|
96
|
-
assert val == expected_output
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
@pytest.mark.parametrize(
|
|
100
|
-
'xeb_fidelity,num_qubits,expected_output',
|
|
101
|
-
[(0.01, 1, 1 - 0.99 / (1 / 2)), (0.05, 2, 1 - 0.95 / (3 / 4))],
|
|
102
|
-
)
|
|
103
|
-
def test_xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits, expected_output):
|
|
104
|
-
val = xeb_fidelity_to_decay_constant(xeb_fidelity, num_qubits)
|
|
105
|
-
assert val == expected_output
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
@pytest.mark.parametrize(
|
|
109
|
-
't,t1_ns,expected_output',
|
|
110
|
-
[
|
|
111
|
-
(20, 1e5, (1 - np.exp(-20 / 2e5)) / 2 + (1 - np.exp(-20 / 1e5)) / 4),
|
|
112
|
-
(4000, 1e4, (1 - np.exp(-4000 / 2e4)) / 2 + (1 - np.exp(-4000 / 1e4)) / 4),
|
|
113
|
-
],
|
|
114
|
-
)
|
|
115
|
-
def test_pauli_error_from_t1(t, t1_ns, expected_output):
|
|
116
|
-
val = pauli_error_from_t1(t, t1_ns)
|
|
117
|
-
assert val == expected_output
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@pytest.mark.parametrize(
|
|
121
|
-
'decay_constant,num_qubits,expected_output', [(0.01, 1, 0.99 * 1 / 2), (0.05, 2, 0.95 * 3 / 4)]
|
|
122
|
-
)
|
|
123
|
-
def test_average_error(decay_constant, num_qubits, expected_output):
|
|
124
|
-
val = average_error(decay_constant, num_qubits)
|
|
125
|
-
assert val == expected_output
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
@pytest.mark.parametrize(
|
|
129
|
-
'T1_ns,Tphi_ns,gate_time_ns', [(1e4, 2e4, 25), (1e5, 2e3, 25), (1e4, 2e4, 4000)]
|
|
130
|
-
)
|
|
131
|
-
def test_decoherence_pauli_error(T1_ns, Tphi_ns, gate_time_ns):
|
|
132
|
-
val = decoherence_pauli_error(T1_ns, Tphi_ns, gate_time_ns)
|
|
133
|
-
# Expected value is of the form:
|
|
134
|
-
#
|
|
135
|
-
# (1/4) * [1 - e^(-t/T1)] + (1/2) * [1 - e^(-t/(2*T1) - t/Tphi]
|
|
136
|
-
#
|
|
137
|
-
expected_output = 0.25 * (1 - np.exp(-gate_time_ns / T1_ns)) + 0.5 * (
|
|
138
|
-
1 - np.exp(-gate_time_ns * ((1 / (2 * T1_ns)) + 1 / Tphi_ns))
|
|
139
|
-
)
|
|
140
|
-
assert val == expected_output
|