cirq-core 1.3.0.dev20231201141002__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.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/METADATA +10 -19
- {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/RECORD +157 -130
- {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.3.0.dev20231201141002.dist-info → cirq_core-1.4.0.dist-info}/top_level.txt +0 -0
cirq/ops/gate_operation.py
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"""Basic types defining qubits, gates, and operations."""
|
|
16
16
|
|
|
17
17
|
import re
|
|
18
|
+
import warnings
|
|
18
19
|
from typing import (
|
|
19
20
|
AbstractSet,
|
|
20
21
|
Any,
|
|
@@ -35,7 +36,7 @@ from typing_extensions import Self
|
|
|
35
36
|
|
|
36
37
|
import numpy as np
|
|
37
38
|
|
|
38
|
-
from cirq import protocols, value
|
|
39
|
+
from cirq import ops, protocols, value
|
|
39
40
|
from cirq.ops import raw_types, gate_features, control_values as cv
|
|
40
41
|
from cirq.type_workarounds import NotImplementedType
|
|
41
42
|
|
|
@@ -348,6 +349,14 @@ class GateOperation(raw_types.Operation):
|
|
|
348
349
|
return self.gate._rmul_with_qubits(self._qubits, other)
|
|
349
350
|
|
|
350
351
|
def _qasm_(self, args: 'protocols.QasmArgs') -> Optional[str]:
|
|
352
|
+
if isinstance(self.gate, ops.GlobalPhaseGate):
|
|
353
|
+
warnings.warn(
|
|
354
|
+
"OpenQASM 2.0 does not support global phase."
|
|
355
|
+
"Since the global phase does not affect the measurement results, "
|
|
356
|
+
"the conversion to QASM is disregarded."
|
|
357
|
+
)
|
|
358
|
+
return ""
|
|
359
|
+
|
|
351
360
|
return protocols.qasm(self.gate, args=args, qubits=self.qubits, default=None)
|
|
352
361
|
|
|
353
362
|
def _equal_up_to_global_phase_(
|
cirq/ops/named_qubit.py
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import functools
|
|
15
|
-
|
|
15
|
+
import weakref
|
|
16
|
+
from typing import Any, Dict, List, Optional, Tuple, TYPE_CHECKING
|
|
16
17
|
|
|
17
18
|
from cirq import protocols
|
|
18
19
|
from cirq.ops import raw_types
|
|
@@ -31,34 +32,55 @@ class _BaseNamedQid(raw_types.Qid):
|
|
|
31
32
|
_comp_key: Optional[str] = None
|
|
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 or "_comp_key" in state:
|
|
38
|
-
state = state.copy()
|
|
39
|
-
if "_hash" in state:
|
|
40
|
-
del state["_hash"]
|
|
41
|
-
if "_comp_key" in state:
|
|
42
|
-
del state["_comp_key"]
|
|
43
|
-
return state
|
|
44
|
-
|
|
45
35
|
def __hash__(self) -> int:
|
|
46
36
|
if self._hash is None:
|
|
47
37
|
self._hash = hash((self._name, self._dimension))
|
|
48
38
|
return self._hash
|
|
49
39
|
|
|
50
|
-
def __eq__(self, other):
|
|
40
|
+
def __eq__(self, other) -> bool:
|
|
51
41
|
# Explicitly implemented for performance (vs delegating to Qid).
|
|
52
42
|
if isinstance(other, _BaseNamedQid):
|
|
53
|
-
return self
|
|
43
|
+
return self is other or (
|
|
44
|
+
self._name == other._name and self._dimension == other._dimension
|
|
45
|
+
)
|
|
54
46
|
return NotImplemented
|
|
55
47
|
|
|
56
|
-
def __ne__(self, other):
|
|
48
|
+
def __ne__(self, other) -> bool:
|
|
57
49
|
# Explicitly implemented for performance (vs delegating to Qid).
|
|
58
50
|
if isinstance(other, _BaseNamedQid):
|
|
59
|
-
return self
|
|
51
|
+
return self is not other and (
|
|
52
|
+
self._name != other._name or self._dimension != other._dimension
|
|
53
|
+
)
|
|
60
54
|
return NotImplemented
|
|
61
55
|
|
|
56
|
+
def __lt__(self, other) -> bool:
|
|
57
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
58
|
+
if isinstance(other, _BaseNamedQid):
|
|
59
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
60
|
+
return k0 < k1 or (k0 == k1 and self._dimension < other._dimension)
|
|
61
|
+
return super().__lt__(other)
|
|
62
|
+
|
|
63
|
+
def __le__(self, other) -> bool:
|
|
64
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
65
|
+
if isinstance(other, _BaseNamedQid):
|
|
66
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
67
|
+
return k0 < k1 or (k0 == k1 and self._dimension <= other._dimension)
|
|
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, _BaseNamedQid):
|
|
73
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
74
|
+
return k0 > k1 or (k0 == k1 and self._dimension >= other._dimension)
|
|
75
|
+
return super().__ge__(other)
|
|
76
|
+
|
|
77
|
+
def __gt__(self, other) -> bool:
|
|
78
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
79
|
+
if isinstance(other, _BaseNamedQid):
|
|
80
|
+
k0, k1 = self._comparison_key(), other._comparison_key()
|
|
81
|
+
return k0 > k1 or (k0 == k1 and self._dimension > other._dimension)
|
|
82
|
+
return super().__gt__(other)
|
|
83
|
+
|
|
62
84
|
def _comparison_key(self):
|
|
63
85
|
if self._comp_key is None:
|
|
64
86
|
self._comp_key = _pad_digits(self._name)
|
|
@@ -86,7 +108,11 @@ class NamedQid(_BaseNamedQid):
|
|
|
86
108
|
correctly come before 'qid22'.
|
|
87
109
|
"""
|
|
88
110
|
|
|
89
|
-
|
|
111
|
+
# Cache of existing NamedQid instances, returned by __new__ if available.
|
|
112
|
+
# Holds weak references so instances can still be garbage collected.
|
|
113
|
+
_cache = weakref.WeakValueDictionary[Tuple[str, int], 'cirq.NamedQid']()
|
|
114
|
+
|
|
115
|
+
def __new__(cls, name: str, dimension: int) -> 'cirq.NamedQid':
|
|
90
116
|
"""Initializes a `NamedQid` with a given name and dimension.
|
|
91
117
|
|
|
92
118
|
Args:
|
|
@@ -94,9 +120,19 @@ class NamedQid(_BaseNamedQid):
|
|
|
94
120
|
dimension: The dimension of the qid's Hilbert space, i.e.
|
|
95
121
|
the number of quantum levels.
|
|
96
122
|
"""
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
key = (name, dimension)
|
|
124
|
+
inst = cls._cache.get(key)
|
|
125
|
+
if inst is None:
|
|
126
|
+
cls.validate_dimension(dimension)
|
|
127
|
+
inst = super().__new__(cls)
|
|
128
|
+
inst._name = name
|
|
129
|
+
inst._dimension = dimension
|
|
130
|
+
cls._cache[key] = inst
|
|
131
|
+
return inst
|
|
132
|
+
|
|
133
|
+
def __getnewargs__(self):
|
|
134
|
+
"""Returns a tuple of args to pass to __new__ when unpickling."""
|
|
135
|
+
return (self._name, self._dimension)
|
|
100
136
|
|
|
101
137
|
def __repr__(self) -> str:
|
|
102
138
|
return f'cirq.NamedQid({self._name!r}, dimension={self._dimension})'
|
|
@@ -143,18 +179,28 @@ class NamedQubit(_BaseNamedQid):
|
|
|
143
179
|
|
|
144
180
|
_dimension = 2
|
|
145
181
|
|
|
146
|
-
|
|
147
|
-
|
|
182
|
+
# Cache of existing NamedQubit instances, returned by __new__ if available.
|
|
183
|
+
# Holds weak references so instances can still be garbage collected.
|
|
184
|
+
_cache = weakref.WeakValueDictionary[str, 'cirq.NamedQubit']()
|
|
185
|
+
|
|
186
|
+
def __new__(cls, name: str) -> 'cirq.NamedQubit':
|
|
187
|
+
"""Initializes a `NamedQid` with a given name and dimension.
|
|
148
188
|
|
|
149
189
|
Args:
|
|
150
190
|
name: The name.
|
|
191
|
+
dimension: The dimension of the qid's Hilbert space, i.e.
|
|
192
|
+
the number of quantum levels.
|
|
151
193
|
"""
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return
|
|
194
|
+
inst = cls._cache.get(name)
|
|
195
|
+
if inst is None:
|
|
196
|
+
inst = super().__new__(cls)
|
|
197
|
+
inst._name = name
|
|
198
|
+
cls._cache[name] = inst
|
|
199
|
+
return inst
|
|
200
|
+
|
|
201
|
+
def __getnewargs__(self):
|
|
202
|
+
"""Returns a tuple of args to pass to __new__ when unpickling."""
|
|
203
|
+
return (self._name,)
|
|
158
204
|
|
|
159
205
|
def __str__(self) -> str:
|
|
160
206
|
return self._name
|
cirq/ops/named_qubit_test.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import cirq
|
|
16
|
+
from cirq.devices.grid_qubit_test import _test_qid_pickled_hash
|
|
16
17
|
from cirq.ops.named_qubit import _pad_digits
|
|
17
18
|
|
|
18
19
|
|
|
@@ -41,6 +42,24 @@ def test_named_qubit_repr():
|
|
|
41
42
|
assert repr(qid) == "cirq.NamedQid('a', dimension=3)"
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
def test_named_qubit_pickled_hash():
|
|
46
|
+
# Use a name that is unlikely to be used by any other tests.
|
|
47
|
+
x = "test_named_qubit_pickled_hash"
|
|
48
|
+
q_bad = cirq.NamedQubit(x)
|
|
49
|
+
cirq.NamedQubit._cache.pop(x)
|
|
50
|
+
q = cirq.NamedQubit(x)
|
|
51
|
+
_test_qid_pickled_hash(q, q_bad)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_named_qid_pickled_hash():
|
|
55
|
+
# Use a name that is unlikely to be used by any other tests.
|
|
56
|
+
x = "test_named_qid_pickled_hash"
|
|
57
|
+
q_bad = cirq.NamedQid(x, dimension=3)
|
|
58
|
+
cirq.NamedQid._cache.pop((x, 3))
|
|
59
|
+
q = cirq.NamedQid(x, dimension=3)
|
|
60
|
+
_test_qid_pickled_hash(q, q_bad)
|
|
61
|
+
|
|
62
|
+
|
|
44
63
|
def test_named_qubit_order():
|
|
45
64
|
order = cirq.testing.OrderTester()
|
|
46
65
|
order.add_ascending(
|
cirq/ops/parity_gates.py
CHANGED
|
@@ -399,6 +399,11 @@ class MSGate(XXPowGate):
|
|
|
399
399
|
return 'cirq.ms(np.pi/2)'
|
|
400
400
|
return f'cirq.ms({self._exponent!r}*np.pi/2)'
|
|
401
401
|
|
|
402
|
+
# the default namespace is already occupied by cirq_ionq.MSGate
|
|
403
|
+
@classmethod
|
|
404
|
+
def _json_namespace_(cls) -> str:
|
|
405
|
+
return 'cirq'
|
|
406
|
+
|
|
402
407
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
403
408
|
return protocols.obj_to_dict_helper(self, ["rads"])
|
|
404
409
|
|
cirq/ops/parity_gates_test.py
CHANGED
|
@@ -258,7 +258,7 @@ def test_trace_distance():
|
|
|
258
258
|
def test_ms_arguments():
|
|
259
259
|
eq_tester = cirq.testing.EqualsTester()
|
|
260
260
|
eq_tester.add_equality_group(
|
|
261
|
-
cirq.ms(np.pi / 2), cirq.
|
|
261
|
+
cirq.ms(np.pi / 2), cirq.MSGate(rads=np.pi / 2), cirq.XXPowGate(global_shift=-0.5)
|
|
262
262
|
)
|
|
263
263
|
eq_tester.add_equality_group(
|
|
264
264
|
cirq.ms(np.pi / 4), cirq.XXPowGate(exponent=0.5, global_shift=-0.5)
|
|
@@ -323,15 +323,7 @@ b: ───×───────────MS(π)───
|
|
|
323
323
|
|
|
324
324
|
|
|
325
325
|
def test_json_serialization():
|
|
326
|
-
|
|
327
|
-
if cirq_type == "MSGate":
|
|
328
|
-
return cirq.ops.MSGate
|
|
329
|
-
return None
|
|
330
|
-
|
|
331
|
-
assert cirq.read_json(
|
|
332
|
-
json_text=cirq.to_json(cirq.ms(np.pi / 2)), resolvers=[custom_resolver]
|
|
333
|
-
) == cirq.ms(np.pi / 2)
|
|
334
|
-
assert custom_resolver('X') is None
|
|
326
|
+
assert cirq.read_json(json_text=cirq.to_json(cirq.ms(np.pi / 2))) == cirq.ms(np.pi / 2)
|
|
335
327
|
|
|
336
328
|
|
|
337
329
|
@pytest.mark.parametrize('gate_cls', (cirq.XXPowGate, cirq.YYPowGate, cirq.ZZPowGate))
|
cirq/ops/pauli_gates.py
CHANGED
|
@@ -15,6 +15,7 @@ import abc
|
|
|
15
15
|
from typing import Any, cast, Tuple, TYPE_CHECKING, Union, Dict
|
|
16
16
|
|
|
17
17
|
from cirq._doc import document
|
|
18
|
+
from cirq._import import LazyLoader
|
|
18
19
|
from cirq.ops import common_gates, raw_types, identity
|
|
19
20
|
from cirq.type_workarounds import NotImplementedType
|
|
20
21
|
|
|
@@ -29,6 +30,9 @@ if TYPE_CHECKING:
|
|
|
29
30
|
) # pragma: no cover
|
|
30
31
|
|
|
31
32
|
|
|
33
|
+
pauli_string = LazyLoader("pauli_string", globals(), "cirq.ops.pauli_string")
|
|
34
|
+
|
|
35
|
+
|
|
32
36
|
class Pauli(raw_types.Gate, metaclass=abc.ABCMeta):
|
|
33
37
|
"""Represents the Pauli gates.
|
|
34
38
|
|
|
@@ -97,9 +101,8 @@ class Pauli(raw_types.Gate, metaclass=abc.ABCMeta):
|
|
|
97
101
|
"""
|
|
98
102
|
if len(qubits) != 1:
|
|
99
103
|
raise ValueError(f'Expected a single qubit, got <{qubits!r}>.')
|
|
100
|
-
from cirq.ops.pauli_string import SingleQubitPauliStringGateOperation
|
|
101
104
|
|
|
102
|
-
return SingleQubitPauliStringGateOperation(self, qubits[0])
|
|
105
|
+
return pauli_string.SingleQubitPauliStringGateOperation(self, qubits[0])
|
|
103
106
|
|
|
104
107
|
@property
|
|
105
108
|
def _canonical_exponent(self):
|
cirq/ops/pauli_string.py
CHANGED
|
@@ -42,7 +42,7 @@ import numpy as np
|
|
|
42
42
|
import sympy
|
|
43
43
|
|
|
44
44
|
import cirq
|
|
45
|
-
from cirq import value, protocols, linalg, qis
|
|
45
|
+
from cirq import value, protocols, linalg, qis, _compat
|
|
46
46
|
from cirq._doc import document
|
|
47
47
|
from cirq._import import LazyLoader
|
|
48
48
|
from cirq.ops import (
|
|
@@ -184,7 +184,7 @@ class PauliString(raw_types.Operation, Generic[TKey]):
|
|
|
184
184
|
Raises:
|
|
185
185
|
TypeError: If the `qubit_pauli_map` has values that are not Paulis.
|
|
186
186
|
"""
|
|
187
|
-
if qubit_pauli_map is not None:
|
|
187
|
+
if _compat.__cirq_debug__.get() and qubit_pauli_map is not None:
|
|
188
188
|
for v in qubit_pauli_map.values():
|
|
189
189
|
if not isinstance(v, pauli_gates.Pauli):
|
|
190
190
|
raise TypeError(f'{v} is not a Pauli')
|
cirq/ops/permutation_gate.py
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from typing import Any, Dict,
|
|
15
|
+
from typing import Any, Dict, Sequence, Tuple, TYPE_CHECKING
|
|
16
16
|
|
|
17
17
|
from cirq import protocols, value
|
|
18
18
|
from cirq.ops import raw_types, swap_gates
|
|
@@ -74,23 +74,21 @@ class QubitPermutationGate(raw_types.Gate):
|
|
|
74
74
|
return True
|
|
75
75
|
|
|
76
76
|
def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE':
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
for
|
|
91
|
-
yield
|
|
92
|
-
for i in range(1, n - 1, 2):
|
|
93
|
-
yield from _swap_if_out_of_order(i)
|
|
77
|
+
permutation = [p for p in self.permutation]
|
|
78
|
+
|
|
79
|
+
for i in range(len(permutation)):
|
|
80
|
+
|
|
81
|
+
if permutation[i] == -1:
|
|
82
|
+
continue
|
|
83
|
+
cycle = [i]
|
|
84
|
+
while permutation[cycle[-1]] != i:
|
|
85
|
+
cycle.append(permutation[cycle[-1]])
|
|
86
|
+
|
|
87
|
+
for j in cycle:
|
|
88
|
+
permutation[j] = -1
|
|
89
|
+
|
|
90
|
+
for idx in cycle[1:]:
|
|
91
|
+
yield swap_gates.SWAP(qubits[cycle[0]], qubits[idx])
|
|
94
92
|
|
|
95
93
|
def _apply_unitary_(self, args: 'cirq.ApplyUnitaryArgs'):
|
|
96
94
|
# Compute the permutation index list.
|
|
@@ -34,9 +34,7 @@ def test_phased_iswap_init():
|
|
|
34
34
|
|
|
35
35
|
def test_phased_iswap_equality():
|
|
36
36
|
eq = cirq.testing.EqualsTester()
|
|
37
|
-
eq.add_equality_group(
|
|
38
|
-
cirq.PhasedISwapPowGate(phase_exponent=0, exponent=0.4), cirq.ISWAP**0.4
|
|
39
|
-
)
|
|
37
|
+
eq.add_equality_group(cirq.PhasedISwapPowGate(phase_exponent=0, exponent=0.4), cirq.ISWAP**0.4)
|
|
40
38
|
eq.add_equality_group(
|
|
41
39
|
cirq.PhasedISwapPowGate(phase_exponent=0, exponent=0.4, global_shift=0.3),
|
|
42
40
|
cirq.ISwapPowGate(global_shift=0.3) ** 0.4,
|
cirq/ops/phased_x_gate.py
CHANGED
|
@@ -28,7 +28,7 @@ from cirq.type_workarounds import NotImplementedType
|
|
|
28
28
|
|
|
29
29
|
@value.value_equality(manual_cls=True, approximate=True)
|
|
30
30
|
class PhasedXPowGate(raw_types.Gate):
|
|
31
|
-
r"""A gate equivalent to $Z^{p} X^t Z^{
|
|
31
|
+
r"""A gate equivalent to $Z^{-p} X^t Z^{p}$ (in time order).
|
|
32
32
|
|
|
33
33
|
The unitary matrix of `cirq.PhasedXPowGate(exponent=t, phase_exponent=p)` is:
|
|
34
34
|
$$
|
cirq/ops/phased_x_z_gate.py
CHANGED
|
@@ -27,7 +27,7 @@ if TYPE_CHECKING:
|
|
|
27
27
|
|
|
28
28
|
@value.value_equality(approximate=True)
|
|
29
29
|
class PhasedXZGate(raw_types.Gate):
|
|
30
|
-
r"""A single qubit gate equivalent to the circuit $Z^
|
|
30
|
+
r"""A single qubit gate equivalent to the circuit $Z^{-a} X^x Z^{a} Z^z$ (in time order).
|
|
31
31
|
|
|
32
32
|
The unitary matrix of `cirq.PhasedXZGate(x_exponent=x, z_exponent=z, axis_phase_exponent=a)` is:
|
|
33
33
|
$$
|
|
@@ -67,6 +67,22 @@ class PhasedXZGate(raw_types.Gate):
|
|
|
67
67
|
self._z_exponent = z_exponent
|
|
68
68
|
self._axis_phase_exponent = axis_phase_exponent
|
|
69
69
|
|
|
70
|
+
@classmethod
|
|
71
|
+
def from_zyz_angles(cls, z0_rad: float, y_rad: float, z1_rad: float) -> 'cirq.PhasedXZGate':
|
|
72
|
+
"""Create a PhasedXZGate from ZYZ angles.
|
|
73
|
+
|
|
74
|
+
The returned gate is equivalent to $Rz(z0_rad) Ry(y_rad) Rz(z1_rad)$ (in time order).
|
|
75
|
+
"""
|
|
76
|
+
return cls.from_zyz_exponents(z0=z0_rad / np.pi, y=y_rad / np.pi, z1=z1_rad / np.pi)
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def from_zyz_exponents(cls, z0: float, y: float, z1: float) -> 'cirq.PhasedXZGate':
|
|
80
|
+
"""Create a PhasedXZGate from ZYZ exponents.
|
|
81
|
+
|
|
82
|
+
The returned gate is equivalent to $Z^z0 Y^y Z^z1$ (in time order).
|
|
83
|
+
"""
|
|
84
|
+
return PhasedXZGate(axis_phase_exponent=-z0 + 0.5, x_exponent=y, z_exponent=z0 + z1)
|
|
85
|
+
|
|
70
86
|
def _canonical(self) -> 'cirq.PhasedXZGate':
|
|
71
87
|
x = self.x_exponent
|
|
72
88
|
z = self.z_exponent
|
cirq/ops/phased_x_z_gate_test.py
CHANGED
|
@@ -34,6 +34,30 @@ def test_eq():
|
|
|
34
34
|
eq.add_equality_group(cirq.PhasedXZGate(x_exponent=1, z_exponent=0, axis_phase_exponent=0))
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
@pytest.mark.parametrize('z0_rad', [-np.pi / 5, 0, np.pi / 5, np.pi / 4, np.pi / 2, np.pi])
|
|
38
|
+
@pytest.mark.parametrize('y_rad', [0, np.pi / 5, np.pi / 4, np.pi / 2, np.pi])
|
|
39
|
+
@pytest.mark.parametrize('z1_rad', [-np.pi / 5, 0, np.pi / 5, np.pi / 4, np.pi / 2, np.pi])
|
|
40
|
+
def test_from_zyz_angles(z0_rad: float, y_rad: float, z1_rad: float) -> None:
|
|
41
|
+
q = cirq.q(0)
|
|
42
|
+
phxz = cirq.PhasedXZGate.from_zyz_angles(z0_rad, y_rad, z1_rad)
|
|
43
|
+
zyz = cirq.Circuit(cirq.rz(z0_rad).on(q), cirq.ry(y_rad).on(q), cirq.rz(z1_rad).on(q))
|
|
44
|
+
cirq.testing.assert_allclose_up_to_global_phase(
|
|
45
|
+
cirq.unitary(phxz), cirq.unitary(zyz), atol=1e-8
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@pytest.mark.parametrize('z0', [-0.2, 0, 0.2, 0.25, 0.5, 1])
|
|
50
|
+
@pytest.mark.parametrize('y', [0, 0.2, 0.25, 0.5, 1])
|
|
51
|
+
@pytest.mark.parametrize('z1', [-0.2, 0, 0.2, 0.25, 0.5, 1])
|
|
52
|
+
def test_from_zyz_exponents(z0: float, y: float, z1: float) -> None:
|
|
53
|
+
q = cirq.q(0)
|
|
54
|
+
phxz = cirq.PhasedXZGate.from_zyz_exponents(z0, y, z1)
|
|
55
|
+
zyz = cirq.Circuit(cirq.Z(q) ** z0, cirq.Y(q) ** y, cirq.Z(q) ** z1)
|
|
56
|
+
cirq.testing.assert_allclose_up_to_global_phase(
|
|
57
|
+
cirq.unitary(phxz), cirq.unitary(zyz), atol=1e-8
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
37
61
|
def test_canonicalization():
|
|
38
62
|
def f(x, z, a):
|
|
39
63
|
return cirq.PhasedXZGate(x_exponent=x, z_exponent=z, axis_phase_exponent=a)
|
cirq/ops/qid_util.py
CHANGED
|
@@ -19,18 +19,15 @@ if TYPE_CHECKING:
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
@overload
|
|
22
|
-
def q(__x: int) -> 'cirq.LineQubit':
|
|
23
|
-
...
|
|
22
|
+
def q(__x: int) -> 'cirq.LineQubit': ...
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
@overload
|
|
27
|
-
def q(__row: int, __col: int) -> 'cirq.GridQubit':
|
|
28
|
-
...
|
|
26
|
+
def q(__row: int, __col: int) -> 'cirq.GridQubit': ...
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
@overload
|
|
32
|
-
def q(__name: str) -> 'cirq.NamedQubit':
|
|
33
|
-
...
|
|
30
|
+
def q(__name: str) -> 'cirq.NamedQubit': ...
|
|
34
31
|
|
|
35
32
|
|
|
36
33
|
def q(*args: Union[int, str]) -> Union['cirq.LineQubit', 'cirq.GridQubit', 'cirq.NamedQubit']:
|
|
@@ -44,8 +41,7 @@ def q(*args: Union[int, str]) -> Union['cirq.LineQubit', 'cirq.GridQubit', 'cirq
|
|
|
44
41
|
>>> cirq.q("foo") == cirq.NamedQubit("foo")
|
|
45
42
|
True
|
|
46
43
|
|
|
47
|
-
Note that arguments should be treated as positional only
|
|
48
|
-
though this is only enforceable in python 3.8 or later.
|
|
44
|
+
Note that arguments should be treated as positional only.
|
|
49
45
|
|
|
50
46
|
Args:
|
|
51
47
|
*args: One or two ints, or a single str, as described above.
|
cirq/ops/qubit_manager.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import abc
|
|
16
16
|
import dataclasses
|
|
17
|
-
from typing import Iterable, List, TYPE_CHECKING
|
|
17
|
+
from typing import Iterable, List, TYPE_CHECKING, Tuple
|
|
18
18
|
from cirq.ops import raw_types
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
@@ -41,16 +41,19 @@ class _BaseAncillaQid(raw_types.Qid):
|
|
|
41
41
|
dim: int = 2
|
|
42
42
|
prefix: str = ''
|
|
43
43
|
|
|
44
|
-
def _comparison_key(self) -> int:
|
|
45
|
-
return self.id
|
|
44
|
+
def _comparison_key(self) -> Tuple[str, int]:
|
|
45
|
+
return self.prefix, self.id
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def dimension(self) -> int:
|
|
49
49
|
return self.dim
|
|
50
50
|
|
|
51
|
+
def with_dimension(self, dimension: int) -> '_BaseAncillaQid':
|
|
52
|
+
return dataclasses.replace(self, dim=dimension)
|
|
53
|
+
|
|
51
54
|
def __repr__(self) -> str:
|
|
52
55
|
dim_str = f', dim={self.dim}' if self.dim != 2 else ''
|
|
53
|
-
prefix_str = f', prefix={self.prefix}' if self.prefix != '' else ''
|
|
56
|
+
prefix_str = f', prefix={self.prefix!r}' if self.prefix != '' else ''
|
|
54
57
|
return f"cirq.ops.{type(self).__name__}({self.id}{dim_str}{prefix_str})"
|
|
55
58
|
|
|
56
59
|
|
cirq/ops/qubit_manager_test.py
CHANGED
|
@@ -27,12 +27,27 @@ def test_clean_qubits():
|
|
|
27
27
|
q = cqi.CleanQubit(2, dim=3)
|
|
28
28
|
assert q.id == 2
|
|
29
29
|
assert q.dimension == 3
|
|
30
|
+
assert q.with_dimension(4) == cqi.CleanQubit(2, dim=4)
|
|
30
31
|
assert str(q) == '_c(2) (d=3)'
|
|
31
32
|
assert repr(q) == 'cirq.ops.CleanQubit(2, dim=3)'
|
|
32
33
|
|
|
34
|
+
q = cqi.CleanQubit(3, dim=4, prefix="a")
|
|
35
|
+
assert str(q) == 'a_c(3) (d=4)'
|
|
36
|
+
assert repr(q) == "cirq.ops.CleanQubit(3, dim=4, prefix='a')"
|
|
37
|
+
|
|
33
38
|
assert cqi.CleanQubit(1) < cqi.CleanQubit(2)
|
|
34
39
|
|
|
35
40
|
|
|
41
|
+
def test_ancilla_qubits_prefix():
|
|
42
|
+
assert cqi.CleanQubit(1, prefix="1") != cqi.CleanQubit(1, prefix="2")
|
|
43
|
+
assert cqi.CleanQubit(1, prefix="1") < cqi.CleanQubit(1, prefix="2")
|
|
44
|
+
assert cqi.CleanQubit(1, prefix="1") < cqi.CleanQubit(2, prefix="1")
|
|
45
|
+
assert cqi.BorrowableQubit(1, prefix="1") != cqi.BorrowableQubit(1, prefix="2")
|
|
46
|
+
assert cqi.BorrowableQubit(1, prefix="1") < cqi.BorrowableQubit(1, prefix="2")
|
|
47
|
+
assert cqi.BorrowableQubit(1, prefix="1") < cqi.BorrowableQubit(2, prefix="1")
|
|
48
|
+
assert cqi.CleanQubit(1, prefix="1") != cqi.BorrowableQubit(1, prefix="1")
|
|
49
|
+
|
|
50
|
+
|
|
36
51
|
def test_borrow_qubits():
|
|
37
52
|
q = cqi.BorrowableQubit(10)
|
|
38
53
|
assert q.id == 10
|
|
@@ -43,9 +58,14 @@ def test_borrow_qubits():
|
|
|
43
58
|
q = cqi.BorrowableQubit(20, dim=4)
|
|
44
59
|
assert q.id == 20
|
|
45
60
|
assert q.dimension == 4
|
|
61
|
+
assert q.with_dimension(10) == cqi.BorrowableQubit(20, dim=10)
|
|
46
62
|
assert str(q) == '_b(20) (d=4)'
|
|
47
63
|
assert repr(q) == 'cirq.ops.BorrowableQubit(20, dim=4)'
|
|
48
64
|
|
|
65
|
+
q = cqi.BorrowableQubit(30, dim=4, prefix="a")
|
|
66
|
+
assert str(q) == 'a_b(30) (d=4)'
|
|
67
|
+
assert repr(q) == "cirq.ops.BorrowableQubit(30, dim=4, prefix='a')"
|
|
68
|
+
|
|
49
69
|
assert cqi.BorrowableQubit(1) < cqi.BorrowableQubit(2)
|
|
50
70
|
|
|
51
71
|
|
cirq/ops/raw_types.py
CHANGED
|
@@ -230,7 +230,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
230
230
|
Returns: a `cirq.Operation` which is this gate applied to the given
|
|
231
231
|
qubits.
|
|
232
232
|
"""
|
|
233
|
-
return ops.gate_operation.GateOperation(self,
|
|
233
|
+
return ops.gate_operation.GateOperation(self, qubits)
|
|
234
234
|
|
|
235
235
|
def on_each(self, *targets: Union[Qid, Iterable[Any]]) -> List['cirq.Operation']:
|
|
236
236
|
"""Returns a list of operations applying the gate to all targets.
|
|
@@ -921,7 +921,7 @@ class TaggedOperation(Operation):
|
|
|
921
921
|
# Add tag to wire symbol if it exists.
|
|
922
922
|
if sub_op_info is not NotImplemented and args.include_tags and sub_op_info.wire_symbols:
|
|
923
923
|
sub_op_info.wire_symbols = (
|
|
924
|
-
sub_op_info.wire_symbols[0] +
|
|
924
|
+
sub_op_info.wire_symbols[0] + f"[{', '.join(map(str, self._tags))}]",
|
|
925
925
|
) + sub_op_info.wire_symbols[1:]
|
|
926
926
|
return sub_op_info
|
|
927
927
|
|
|
@@ -1032,6 +1032,9 @@ class _InverseCompositeGate(Gate):
|
|
|
1032
1032
|
def __repr__(self) -> str:
|
|
1033
1033
|
return f'({self._original!r}**-1)'
|
|
1034
1034
|
|
|
1035
|
+
def __str__(self) -> str:
|
|
1036
|
+
return f'{self._original!s}†'
|
|
1037
|
+
|
|
1035
1038
|
|
|
1036
1039
|
def _validate_qid_shape(val: Any, qubits: Sequence['cirq.Qid']) -> None:
|
|
1037
1040
|
"""Helper function to validate qubits for gates and operations.
|