cirq-core 1.2.0.dev20230717232332__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.dev20230717232332.dist-info → cirq_core-1.3.0.dist-info}/METADATA +11 -19
- {cirq_core-1.2.0.dev20230717232332.dist-info → cirq_core-1.3.0.dist-info}/RECORD +158 -150
- {cirq_core-1.2.0.dev20230717232332.dist-info → cirq_core-1.3.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.2.0.dev20230717232332.dist-info → cirq_core-1.3.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.2.0.dev20230717232332.dist-info → cirq_core-1.3.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Copyright 2023 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import cirq
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GateAllocInDecompose(cirq.Gate):
|
|
19
|
+
def __init__(self, num_alloc: int = 1):
|
|
20
|
+
self.num_alloc = num_alloc
|
|
21
|
+
|
|
22
|
+
def _num_qubits_(self) -> int:
|
|
23
|
+
return 1
|
|
24
|
+
|
|
25
|
+
def _decompose_with_context_(self, qubits, context):
|
|
26
|
+
assert context is not None
|
|
27
|
+
qm = context.qubit_manager
|
|
28
|
+
for q in qm.qalloc(self.num_alloc):
|
|
29
|
+
yield cirq.CNOT(qubits[0], q)
|
|
30
|
+
qm.qfree([q])
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_greedy_qubit_manager():
|
|
34
|
+
def make_circuit(qm: cirq.QubitManager):
|
|
35
|
+
q = cirq.LineQubit.range(2)
|
|
36
|
+
g = GateAllocInDecompose(1)
|
|
37
|
+
context = cirq.DecompositionContext(qubit_manager=qm)
|
|
38
|
+
circuit = cirq.Circuit(
|
|
39
|
+
cirq.decompose_once(g.on(q[0]), context=context),
|
|
40
|
+
cirq.decompose_once(g.on(q[1]), context=context),
|
|
41
|
+
)
|
|
42
|
+
return circuit
|
|
43
|
+
|
|
44
|
+
qm = cirq.GreedyQubitManager(prefix="ancilla", size=1)
|
|
45
|
+
# Qubit manager with only 1 managed qubit. Will always repeat the same qubit.
|
|
46
|
+
circuit = make_circuit(qm)
|
|
47
|
+
cirq.testing.assert_has_diagram(
|
|
48
|
+
circuit,
|
|
49
|
+
"""
|
|
50
|
+
0: ───────────@───────
|
|
51
|
+
│
|
|
52
|
+
1: ───────────┼───@───
|
|
53
|
+
│ │
|
|
54
|
+
ancilla_0: ───X───X───
|
|
55
|
+
""",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
qm = cirq.GreedyQubitManager(prefix="ancilla", size=2)
|
|
59
|
+
# Qubit manager with 2 managed qubits and maximize_reuse=False, tries to minimize adding
|
|
60
|
+
# additional data dependencies by minimizing qubit reuse.
|
|
61
|
+
circuit = make_circuit(qm)
|
|
62
|
+
cirq.testing.assert_has_diagram(
|
|
63
|
+
circuit,
|
|
64
|
+
"""
|
|
65
|
+
┌──┐
|
|
66
|
+
0: ────────────@─────
|
|
67
|
+
│
|
|
68
|
+
1: ────────────┼@────
|
|
69
|
+
││
|
|
70
|
+
ancilla_0: ────X┼────
|
|
71
|
+
│
|
|
72
|
+
ancilla_1: ─────X────
|
|
73
|
+
└──┘
|
|
74
|
+
""",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
qm = cirq.GreedyQubitManager(prefix="ancilla", size=2, maximize_reuse=True)
|
|
78
|
+
# Qubit manager with 2 managed qubits and maximize_reuse=True, tries to maximize reuse by
|
|
79
|
+
# potentially adding new data dependencies.
|
|
80
|
+
circuit = make_circuit(qm)
|
|
81
|
+
cirq.testing.assert_has_diagram(
|
|
82
|
+
circuit,
|
|
83
|
+
"""
|
|
84
|
+
0: ───────────@───────
|
|
85
|
+
│
|
|
86
|
+
1: ───────────┼───@───
|
|
87
|
+
│ │
|
|
88
|
+
ancilla_1: ───X───X───
|
|
89
|
+
""",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_greedy_qubit_manager_preserves_order():
|
|
94
|
+
qm = cirq.GreedyQubitManager(prefix="anc")
|
|
95
|
+
ancillae = [cirq.q(f"anc_{i}") for i in range(100)]
|
|
96
|
+
assert qm.qalloc(100) == ancillae
|
|
97
|
+
qm.qfree(ancillae)
|
|
98
|
+
assert qm.qalloc(100) == ancillae
|
cirq/ops/linear_combinations.py
CHANGED
|
@@ -357,7 +357,7 @@ def _pauli_string_from_unit(unit: UnitPauliStringT, coefficient: Union[int, floa
|
|
|
357
357
|
return PauliString(qubit_pauli_map=dict(unit), coefficient=coefficient)
|
|
358
358
|
|
|
359
359
|
|
|
360
|
-
@value.value_equality(approximate=True)
|
|
360
|
+
@value.value_equality(approximate=True, unhashable=True)
|
|
361
361
|
class PauliSum:
|
|
362
362
|
"""Represents operator defined by linear combination of PauliStrings.
|
|
363
363
|
|
cirq/ops/named_qubit.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
|
import functools
|
|
15
|
-
from typing import Any, Dict, List, TYPE_CHECKING
|
|
15
|
+
from typing import Any, Dict, List, Optional, TYPE_CHECKING
|
|
16
16
|
|
|
17
17
|
from cirq import protocols
|
|
18
18
|
from cirq.ops import raw_types
|
|
@@ -26,17 +26,52 @@ if TYPE_CHECKING:
|
|
|
26
26
|
class _BaseNamedQid(raw_types.Qid):
|
|
27
27
|
"""The base class for `NamedQid` and `NamedQubit`."""
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
_name: str
|
|
30
|
+
_dimension: int
|
|
31
|
+
_comp_key: Optional[str] = None
|
|
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 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
|
+
def __hash__(self) -> int:
|
|
46
|
+
if self._hash is None:
|
|
47
|
+
self._hash = hash((self._name, 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, _BaseNamedQid):
|
|
53
|
+
return self._name == other._name and self._dimension == other._dimension
|
|
54
|
+
return NotImplemented
|
|
55
|
+
|
|
56
|
+
def __ne__(self, other):
|
|
57
|
+
# Explicitly implemented for performance (vs delegating to Qid).
|
|
58
|
+
if isinstance(other, _BaseNamedQid):
|
|
59
|
+
return self._name != other._name or self._dimension != other._dimension
|
|
60
|
+
return NotImplemented
|
|
32
61
|
|
|
33
62
|
def _comparison_key(self):
|
|
63
|
+
if self._comp_key is None:
|
|
64
|
+
self._comp_key = _pad_digits(self._name)
|
|
34
65
|
return self._comp_key
|
|
35
66
|
|
|
36
67
|
@property
|
|
37
68
|
def name(self) -> str:
|
|
38
69
|
return self._name
|
|
39
70
|
|
|
71
|
+
@property
|
|
72
|
+
def dimension(self) -> int:
|
|
73
|
+
return self._dimension
|
|
74
|
+
|
|
40
75
|
def with_dimension(self, dimension: int) -> 'NamedQid':
|
|
41
76
|
return NamedQid(self._name, dimension=dimension)
|
|
42
77
|
|
|
@@ -59,19 +94,15 @@ class NamedQid(_BaseNamedQid):
|
|
|
59
94
|
dimension: The dimension of the qid's Hilbert space, i.e.
|
|
60
95
|
the number of quantum levels.
|
|
61
96
|
"""
|
|
62
|
-
super().__init__(name)
|
|
63
|
-
self._dimension = dimension
|
|
64
97
|
self.validate_dimension(dimension)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def dimension(self) -> int:
|
|
68
|
-
return self._dimension
|
|
98
|
+
self._name = name
|
|
99
|
+
self._dimension = dimension
|
|
69
100
|
|
|
70
101
|
def __repr__(self) -> str:
|
|
71
|
-
return f'cirq.NamedQid({self.
|
|
102
|
+
return f'cirq.NamedQid({self._name!r}, dimension={self._dimension})'
|
|
72
103
|
|
|
73
104
|
def __str__(self) -> str:
|
|
74
|
-
return f'{self.
|
|
105
|
+
return f'{self._name} (d={self._dimension})'
|
|
75
106
|
|
|
76
107
|
@staticmethod
|
|
77
108
|
def range(*args, prefix: str, dimension: int) -> List['NamedQid']:
|
|
@@ -95,7 +126,7 @@ class NamedQid(_BaseNamedQid):
|
|
|
95
126
|
Returns:
|
|
96
127
|
A list of ``NamedQid``\\s.
|
|
97
128
|
"""
|
|
98
|
-
return [NamedQid(prefix
|
|
129
|
+
return [NamedQid(f"{prefix}{i}", dimension=dimension) for i in range(*args)]
|
|
99
130
|
|
|
100
131
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
101
132
|
return protocols.obj_to_dict_helper(self, ['name', 'dimension'])
|
|
@@ -110,14 +141,20 @@ class NamedQubit(_BaseNamedQid):
|
|
|
110
141
|
wire for 'qubit3' will correctly come before 'qubit22'.
|
|
111
142
|
"""
|
|
112
143
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
144
|
+
_dimension = 2
|
|
145
|
+
|
|
146
|
+
def __init__(self, name: str) -> None:
|
|
147
|
+
"""Initializes a `NamedQubit` with a given name.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
name: The name.
|
|
151
|
+
"""
|
|
152
|
+
self._name = name
|
|
116
153
|
|
|
117
154
|
def _cmp_tuple(self):
|
|
118
155
|
cls = NamedQid if type(self) is NamedQubit else type(self)
|
|
119
156
|
# Must be same as Qid._cmp_tuple but with cls in place of type(self).
|
|
120
|
-
return (cls.__name__, repr(cls), self._comparison_key(), self.
|
|
157
|
+
return (cls.__name__, repr(cls), self._comparison_key(), self._dimension)
|
|
121
158
|
|
|
122
159
|
def __str__(self) -> str:
|
|
123
160
|
return self._name
|
|
@@ -146,7 +183,7 @@ class NamedQubit(_BaseNamedQid):
|
|
|
146
183
|
Returns:
|
|
147
184
|
A list of ``NamedQubit``\\s.
|
|
148
185
|
"""
|
|
149
|
-
return [NamedQubit(prefix
|
|
186
|
+
return [NamedQubit(f"{prefix}{i}") for i in range(*args)]
|
|
150
187
|
|
|
151
188
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
152
189
|
return protocols.obj_to_dict_helper(self, ['name'])
|
cirq/ops/parity_gates.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
"""Quantum gates that phase with respect to product-of-pauli observables."""
|
|
16
16
|
|
|
17
|
-
from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING
|
|
17
|
+
from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING, Sequence
|
|
18
18
|
from typing_extensions import Self
|
|
19
19
|
|
|
20
20
|
import numpy as np
|
|
@@ -22,12 +22,21 @@ import numpy as np
|
|
|
22
22
|
from cirq import protocols, value
|
|
23
23
|
from cirq._compat import proper_repr
|
|
24
24
|
from cirq._doc import document
|
|
25
|
-
from cirq.ops import
|
|
25
|
+
from cirq.ops import (
|
|
26
|
+
gate_features,
|
|
27
|
+
eigen_gate,
|
|
28
|
+
common_gates,
|
|
29
|
+
pauli_gates,
|
|
30
|
+
clifford_gate,
|
|
31
|
+
pauli_interaction_gate,
|
|
32
|
+
)
|
|
33
|
+
|
|
26
34
|
|
|
27
35
|
if TYPE_CHECKING:
|
|
28
36
|
import cirq
|
|
29
37
|
|
|
30
38
|
|
|
39
|
+
@value.value_equality
|
|
31
40
|
class XXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
32
41
|
r"""The X-parity gate, possibly raised to a power.
|
|
33
42
|
|
|
@@ -86,25 +95,29 @@ class XXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
86
95
|
return abs(np.sin(self._exponent * 0.5 * np.pi))
|
|
87
96
|
|
|
88
97
|
def _decompose_into_clifford_with_qubits_(self, qubits):
|
|
89
|
-
from cirq.ops.clifford_gate import SingleQubitCliffordGate
|
|
90
|
-
from cirq.ops.pauli_interaction_gate import PauliInteractionGate
|
|
91
|
-
|
|
92
98
|
if self.exponent % 2 == 0:
|
|
93
99
|
return []
|
|
94
100
|
if self.exponent % 2 == 0.5:
|
|
95
101
|
return [
|
|
96
|
-
PauliInteractionGate(
|
|
97
|
-
|
|
102
|
+
pauli_interaction_gate.PauliInteractionGate(
|
|
103
|
+
pauli_gates.X, False, pauli_gates.X, False
|
|
104
|
+
).on(*qubits),
|
|
105
|
+
clifford_gate.SingleQubitCliffordGate.X_sqrt.on_each(*qubits),
|
|
98
106
|
]
|
|
99
107
|
if self.exponent % 2 == 1:
|
|
100
|
-
return [SingleQubitCliffordGate.X.on_each(*qubits)]
|
|
108
|
+
return [clifford_gate.SingleQubitCliffordGate.X.on_each(*qubits)]
|
|
101
109
|
if self.exponent % 2 == 1.5:
|
|
102
110
|
return [
|
|
103
|
-
PauliInteractionGate(
|
|
104
|
-
|
|
111
|
+
pauli_interaction_gate.PauliInteractionGate(
|
|
112
|
+
pauli_gates.X, False, pauli_gates.X, False
|
|
113
|
+
).on(*qubits),
|
|
114
|
+
clifford_gate.SingleQubitCliffordGate.X_nsqrt.on_each(*qubits),
|
|
105
115
|
]
|
|
106
116
|
return NotImplemented
|
|
107
117
|
|
|
118
|
+
def _has_stabilizer_effect_(self) -> bool:
|
|
119
|
+
return self.exponent % 2 in (0, 0.5, 1, 1.5)
|
|
120
|
+
|
|
108
121
|
def _decompose_(self, qubits: Tuple['cirq.Qid', ...]) -> 'cirq.OP_TREE':
|
|
109
122
|
yield common_gates.YPowGate(exponent=-0.5).on_each(*qubits)
|
|
110
123
|
yield ZZPowGate(exponent=self.exponent, global_shift=self.global_shift)(*qubits)
|
|
@@ -133,6 +146,7 @@ class XXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
133
146
|
)
|
|
134
147
|
|
|
135
148
|
|
|
149
|
+
@value.value_equality
|
|
136
150
|
class YYPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
137
151
|
r"""The Y-parity gate, possibly raised to a power.
|
|
138
152
|
|
|
@@ -190,25 +204,29 @@ class YYPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
190
204
|
return abs(np.sin(self._exponent * 0.5 * np.pi))
|
|
191
205
|
|
|
192
206
|
def _decompose_into_clifford_with_qubits_(self, qubits):
|
|
193
|
-
from cirq.ops.clifford_gate import SingleQubitCliffordGate
|
|
194
|
-
from cirq.ops.pauli_interaction_gate import PauliInteractionGate
|
|
195
|
-
|
|
196
207
|
if self.exponent % 2 == 0:
|
|
197
208
|
return []
|
|
198
209
|
if self.exponent % 2 == 0.5:
|
|
199
210
|
return [
|
|
200
|
-
PauliInteractionGate(
|
|
201
|
-
|
|
211
|
+
pauli_interaction_gate.PauliInteractionGate(
|
|
212
|
+
pauli_gates.Y, False, pauli_gates.Y, False
|
|
213
|
+
).on(*qubits),
|
|
214
|
+
clifford_gate.SingleQubitCliffordGate.Y_sqrt.on_each(*qubits),
|
|
202
215
|
]
|
|
203
216
|
if self.exponent % 2 == 1:
|
|
204
|
-
return [SingleQubitCliffordGate.Y.on_each(*qubits)]
|
|
217
|
+
return [clifford_gate.SingleQubitCliffordGate.Y.on_each(*qubits)]
|
|
205
218
|
if self.exponent % 2 == 1.5:
|
|
206
219
|
return [
|
|
207
|
-
PauliInteractionGate(
|
|
208
|
-
|
|
220
|
+
pauli_interaction_gate.PauliInteractionGate(
|
|
221
|
+
pauli_gates.Y, False, pauli_gates.Y, False
|
|
222
|
+
).on(*qubits),
|
|
223
|
+
clifford_gate.SingleQubitCliffordGate.Y_nsqrt.on_each(*qubits),
|
|
209
224
|
]
|
|
210
225
|
return NotImplemented
|
|
211
226
|
|
|
227
|
+
def _has_stabilizer_effect_(self) -> bool:
|
|
228
|
+
return self.exponent % 2 in (0, 0.5, 1, 1.5)
|
|
229
|
+
|
|
212
230
|
def _decompose_(self, qubits: Tuple['cirq.Qid', ...]) -> 'cirq.OP_TREE':
|
|
213
231
|
yield common_gates.XPowGate(exponent=0.5).on_each(*qubits)
|
|
214
232
|
yield ZZPowGate(exponent=self.exponent, global_shift=self.global_shift)(*qubits)
|
|
@@ -237,6 +255,7 @@ class YYPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
237
255
|
)
|
|
238
256
|
|
|
239
257
|
|
|
258
|
+
@value.value_equality
|
|
240
259
|
class ZZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
241
260
|
r"""The Z-parity gate, possibly raised to a power.
|
|
242
261
|
|
|
@@ -262,6 +281,34 @@ class ZZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
262
281
|
exponent=-2 * self.exponent, global_shift=-self.global_shift / 2
|
|
263
282
|
)(qubits[0], qubits[1])
|
|
264
283
|
|
|
284
|
+
def _decompose_into_clifford_with_qubits_(
|
|
285
|
+
self, qubits: Sequence['cirq.Qid']
|
|
286
|
+
) -> Sequence[Union['cirq.Operation', Sequence['cirq.Operation']]]:
|
|
287
|
+
if not self._has_stabilizer_effect_():
|
|
288
|
+
return NotImplemented
|
|
289
|
+
if self.exponent % 2 == 0:
|
|
290
|
+
return []
|
|
291
|
+
if self.exponent % 2 == 1:
|
|
292
|
+
return clifford_gate.SingleQubitCliffordGate.Z.on_each(*qubits)
|
|
293
|
+
|
|
294
|
+
if self.exponent % 2 == 0.5:
|
|
295
|
+
return [
|
|
296
|
+
pauli_interaction_gate.PauliInteractionGate(
|
|
297
|
+
pauli_gates.Z, False, pauli_gates.Z, False
|
|
298
|
+
).on(*qubits),
|
|
299
|
+
clifford_gate.SingleQubitCliffordGate.Z_sqrt.on_each(*qubits),
|
|
300
|
+
]
|
|
301
|
+
else:
|
|
302
|
+
return [
|
|
303
|
+
pauli_interaction_gate.PauliInteractionGate(
|
|
304
|
+
pauli_gates.Z, False, pauli_gates.Z, False
|
|
305
|
+
).on(*qubits),
|
|
306
|
+
clifford_gate.SingleQubitCliffordGate.Z_nsqrt.on_each(*qubits),
|
|
307
|
+
]
|
|
308
|
+
|
|
309
|
+
def _has_stabilizer_effect_(self) -> bool:
|
|
310
|
+
return self.exponent % 2 in (0, 0.5, 1, 1.5)
|
|
311
|
+
|
|
265
312
|
def _eigen_components(self) -> List[Tuple[float, np.ndarray]]:
|
|
266
313
|
return [(0, np.diag([1, 0, 0, 1])), (1, np.diag([0, 1, 1, 0]))]
|
|
267
314
|
|
cirq/ops/parity_gates_test.py
CHANGED
|
@@ -257,8 +257,24 @@ def test_trace_distance():
|
|
|
257
257
|
|
|
258
258
|
def test_ms_arguments():
|
|
259
259
|
eq_tester = cirq.testing.EqualsTester()
|
|
260
|
-
eq_tester.add_equality_group(
|
|
261
|
-
|
|
260
|
+
eq_tester.add_equality_group(
|
|
261
|
+
cirq.ms(np.pi / 2), cirq.ops.MSGate(rads=np.pi / 2), cirq.XXPowGate(global_shift=-0.5)
|
|
262
|
+
)
|
|
263
|
+
eq_tester.add_equality_group(
|
|
264
|
+
cirq.ms(np.pi / 4), cirq.XXPowGate(exponent=0.5, global_shift=-0.5)
|
|
265
|
+
)
|
|
266
|
+
eq_tester.add_equality_group(cirq.XX)
|
|
267
|
+
eq_tester.add_equality_group(cirq.XX**0.5)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def test_ms_equal_up_to_global_phase():
|
|
271
|
+
assert cirq.equal_up_to_global_phase(cirq.ms(np.pi / 2), cirq.XX)
|
|
272
|
+
assert cirq.equal_up_to_global_phase(cirq.ms(np.pi / 4), cirq.XX**0.5)
|
|
273
|
+
assert not cirq.equal_up_to_global_phase(cirq.ms(np.pi / 4), cirq.XX)
|
|
274
|
+
|
|
275
|
+
assert cirq.ms(np.pi / 2) in cirq.GateFamily(cirq.XX)
|
|
276
|
+
assert cirq.ms(np.pi / 4) in cirq.GateFamily(cirq.XX**0.5)
|
|
277
|
+
assert cirq.ms(np.pi / 4) not in cirq.GateFamily(cirq.XX)
|
|
262
278
|
|
|
263
279
|
|
|
264
280
|
def test_ms_str():
|
|
@@ -316,3 +332,26 @@ def test_json_serialization():
|
|
|
316
332
|
json_text=cirq.to_json(cirq.ms(np.pi / 2)), resolvers=[custom_resolver]
|
|
317
333
|
) == cirq.ms(np.pi / 2)
|
|
318
334
|
assert custom_resolver('X') is None
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@pytest.mark.parametrize('gate_cls', (cirq.XXPowGate, cirq.YYPowGate, cirq.ZZPowGate))
|
|
338
|
+
@pytest.mark.parametrize(
|
|
339
|
+
'exponent,is_clifford',
|
|
340
|
+
((0, True), (0.5, True), (0.75, False), (1, True), (1.5, True), (-1.5, True)),
|
|
341
|
+
)
|
|
342
|
+
def test_clifford_protocols(gate_cls: type[cirq.EigenGate], exponent: float, is_clifford: bool):
|
|
343
|
+
gate = gate_cls(exponent=exponent)
|
|
344
|
+
assert hasattr(gate, '_decompose_into_clifford_with_qubits_')
|
|
345
|
+
if is_clifford:
|
|
346
|
+
clifford_decomposition = cirq.Circuit(
|
|
347
|
+
gate._decompose_into_clifford_with_qubits_(cirq.LineQubit.range(2))
|
|
348
|
+
)
|
|
349
|
+
assert cirq.has_stabilizer_effect(gate)
|
|
350
|
+
assert cirq.has_stabilizer_effect(clifford_decomposition)
|
|
351
|
+
if exponent == 0:
|
|
352
|
+
assert clifford_decomposition == cirq.Circuit()
|
|
353
|
+
else:
|
|
354
|
+
np.testing.assert_allclose(cirq.unitary(gate), cirq.unitary(clifford_decomposition))
|
|
355
|
+
else:
|
|
356
|
+
assert not cirq.has_stabilizer_effect(gate)
|
|
357
|
+
assert gate._decompose_into_clifford_with_qubits_(cirq.LineQubit.range(2)) is NotImplemented
|
cirq/ops/pauli_gates.py
CHANGED
|
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
|
|
|
26
26
|
_XEigenState,
|
|
27
27
|
_YEigenState,
|
|
28
28
|
_ZEigenState,
|
|
29
|
-
) #
|
|
29
|
+
) # pragma: no cover
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class Pauli(raw_types.Gate, metaclass=abc.ABCMeta):
|
|
@@ -186,7 +186,7 @@ document(
|
|
|
186
186
|
|
|
187
187
|
This is the `exponent=1` instance of the `cirq.XPowGate`.
|
|
188
188
|
|
|
189
|
-
The
|
|
189
|
+
The unitary matrix of `cirq.X` is:
|
|
190
190
|
$$
|
|
191
191
|
\begin{bmatrix}
|
|
192
192
|
0 & 1 \\
|
cirq/ops/pauli_string.py
CHANGED
|
@@ -92,7 +92,7 @@ document(
|
|
|
92
92
|
""",
|
|
93
93
|
)
|
|
94
94
|
|
|
95
|
-
PAULI_GATE_LIKE = Union['cirq.Pauli', 'cirq.IdentityGate', str, int
|
|
95
|
+
PAULI_GATE_LIKE = Union['cirq.Pauli', 'cirq.IdentityGate', str, int]
|
|
96
96
|
document(
|
|
97
97
|
PAULI_GATE_LIKE,
|
|
98
98
|
"""An object that can be interpreted as a Pauli gate.
|
|
@@ -1387,8 +1387,7 @@ class MutablePauliString(Generic[TKey]):
|
|
|
1387
1387
|
if gate.invert1:
|
|
1388
1388
|
self.inplace_after(gate.pauli0(q0))
|
|
1389
1389
|
|
|
1390
|
-
else:
|
|
1391
|
-
# coverage: ignore
|
|
1390
|
+
else: # pragma: no cover
|
|
1392
1391
|
raise NotImplementedError(f"Unrecognized decomposed Clifford: {op!r}")
|
|
1393
1392
|
return self
|
|
1394
1393
|
|
|
@@ -1617,7 +1616,7 @@ def _pass_single_clifford_gate_over(
|
|
|
1617
1616
|
after_to_before: bool = False,
|
|
1618
1617
|
) -> bool:
|
|
1619
1618
|
if qubit not in pauli_map:
|
|
1620
|
-
return False #
|
|
1619
|
+
return False # pragma: no cover
|
|
1621
1620
|
if not after_to_before:
|
|
1622
1621
|
gate **= -1
|
|
1623
1622
|
pauli, inv = gate.pauli_tuple(pauli_map[qubit])
|
|
@@ -48,12 +48,12 @@ def test_op_calls_validate():
|
|
|
48
48
|
def test_on_wrong_number_qubits():
|
|
49
49
|
q0, q1, q2 = _make_qubits(3)
|
|
50
50
|
|
|
51
|
-
class
|
|
51
|
+
class ExampleGate(cirq.PauliStringGateOperation):
|
|
52
52
|
def map_qubits(self, qubit_map):
|
|
53
53
|
ps = self.pauli_string.map_qubits(qubit_map)
|
|
54
|
-
return
|
|
54
|
+
return ExampleGate(ps)
|
|
55
55
|
|
|
56
|
-
g =
|
|
56
|
+
g = ExampleGate(cirq.PauliString({q0: cirq.X, q1: cirq.Y}))
|
|
57
57
|
|
|
58
58
|
_ = g.with_qubits(q1, q2)
|
|
59
59
|
with pytest.raises(ValueError):
|
cirq/ops/pauli_string_test.py
CHANGED
|
@@ -732,11 +732,11 @@ def test_pass_operations_over_cz():
|
|
|
732
732
|
|
|
733
733
|
|
|
734
734
|
def test_pass_operations_over_no_common_qubits():
|
|
735
|
-
class
|
|
735
|
+
class ExampleGate(cirq.testing.SingleQubitGate):
|
|
736
736
|
pass
|
|
737
737
|
|
|
738
738
|
q0, q1 = _make_qubits(2)
|
|
739
|
-
op0 =
|
|
739
|
+
op0 = ExampleGate()(q1)
|
|
740
740
|
ps_before = cirq.PauliString({q0: cirq.Z})
|
|
741
741
|
ps_after = cirq.PauliString({q0: cirq.Z})
|
|
742
742
|
_assert_pass_over([op0], ps_before, ps_after)
|
|
@@ -1765,8 +1765,7 @@ def test_mutable_pauli_string_inplace_conjugate_by():
|
|
|
1765
1765
|
self._qubits = qubits
|
|
1766
1766
|
|
|
1767
1767
|
@property
|
|
1768
|
-
def qubits(self):
|
|
1769
|
-
# coverage: ignore
|
|
1768
|
+
def qubits(self): # pragma: no cover
|
|
1770
1769
|
return self._qubits
|
|
1771
1770
|
|
|
1772
1771
|
def with_qubits(self, *new_qubits):
|
|
@@ -219,13 +219,13 @@ def test_stabilizer_supports_probability():
|
|
|
219
219
|
|
|
220
220
|
|
|
221
221
|
def test_unsupported_stabilizer_safety():
|
|
222
|
-
from cirq.protocols.act_on_protocol_test import
|
|
222
|
+
from cirq.protocols.act_on_protocol_test import ExampleSimulationState
|
|
223
223
|
|
|
224
224
|
with pytest.raises(TypeError, match="act_on"):
|
|
225
225
|
for _ in range(100):
|
|
226
|
-
cirq.act_on(cirq.X.with_probability(0.5),
|
|
226
|
+
cirq.act_on(cirq.X.with_probability(0.5), ExampleSimulationState(), qubits=())
|
|
227
227
|
with pytest.raises(TypeError, match="act_on"):
|
|
228
|
-
cirq.act_on(cirq.X.with_probability(sympy.Symbol('x')),
|
|
228
|
+
cirq.act_on(cirq.X.with_probability(sympy.Symbol('x')), ExampleSimulationState(), qubits=())
|
|
229
229
|
|
|
230
230
|
q = cirq.LineQubit(0)
|
|
231
231
|
c = cirq.Circuit((cirq.X(q) ** 0.25).with_probability(0.5), cirq.measure(q, key='m'))
|
cirq/ops/raw_types.py
CHANGED
|
@@ -671,7 +671,7 @@ class Operation(metaclass=abc.ABCMeta):
|
|
|
671
671
|
# Don't create gigantic matrices.
|
|
672
672
|
shape = protocols.qid_shape_protocol.qid_shape(circuit12)
|
|
673
673
|
if np.prod(shape, dtype=np.int64) > 2**10:
|
|
674
|
-
return NotImplemented #
|
|
674
|
+
return NotImplemented # pragma: no cover
|
|
675
675
|
|
|
676
676
|
m12 = protocols.unitary_protocol.unitary(circuit12, default=None)
|
|
677
677
|
m21 = protocols.unitary_protocol.unitary(circuit21, default=None)
|
cirq/ops/raw_types_test.py
CHANGED
|
@@ -356,7 +356,7 @@ def test_gate_shape_protocol():
|
|
|
356
356
|
def test_operation_shape():
|
|
357
357
|
class FixedQids(cirq.Operation):
|
|
358
358
|
def with_qubits(self, *new_qids):
|
|
359
|
-
raise NotImplementedError #
|
|
359
|
+
raise NotImplementedError # pragma: no cover
|
|
360
360
|
|
|
361
361
|
class QubitOp(FixedQids):
|
|
362
362
|
@property
|
|
@@ -787,9 +787,9 @@ def test_tagged_act_on():
|
|
|
787
787
|
pass
|
|
788
788
|
|
|
789
789
|
q = cirq.LineQubit(1)
|
|
790
|
-
from cirq.protocols.act_on_protocol_test import
|
|
790
|
+
from cirq.protocols.act_on_protocol_test import ExampleSimulationState
|
|
791
791
|
|
|
792
|
-
args =
|
|
792
|
+
args = ExampleSimulationState()
|
|
793
793
|
cirq.act_on(YesActOn()(q).with_tags("test"), args)
|
|
794
794
|
with pytest.raises(TypeError, match="Failed to act"):
|
|
795
795
|
cirq.act_on(NoActOn()(q).with_tags("test"), args)
|
|
@@ -798,11 +798,11 @@ def test_tagged_act_on():
|
|
|
798
798
|
|
|
799
799
|
|
|
800
800
|
def test_single_qubit_gate_validates_on_each():
|
|
801
|
-
class
|
|
801
|
+
class Example(cirq.testing.SingleQubitGate):
|
|
802
802
|
def matrix(self):
|
|
803
803
|
pass
|
|
804
804
|
|
|
805
|
-
g =
|
|
805
|
+
g = Example()
|
|
806
806
|
assert g.num_qubits() == 1
|
|
807
807
|
|
|
808
808
|
test_qubits = [cirq.NamedQubit(str(i)) for i in range(3)]
|
cirq/ops/three_qubit_gates.py
CHANGED
|
@@ -206,11 +206,13 @@ class CCZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
206
206
|
"""
|
|
207
207
|
if num_controls == 0:
|
|
208
208
|
return self
|
|
209
|
+
sub_gate: 'cirq.Gate' = self
|
|
210
|
+
if self._global_shift == 0:
|
|
211
|
+
sub_gate = controlled_gate.ControlledGate(
|
|
212
|
+
common_gates.ZPowGate(exponent=self._exponent), num_controls=2
|
|
213
|
+
)
|
|
209
214
|
return controlled_gate.ControlledGate(
|
|
210
|
-
|
|
211
|
-
common_gates.ZPowGate(exponent=self._exponent, global_shift=self._global_shift),
|
|
212
|
-
num_controls=2,
|
|
213
|
-
),
|
|
215
|
+
sub_gate,
|
|
214
216
|
num_controls=num_controls,
|
|
215
217
|
control_values=control_values,
|
|
216
218
|
control_qid_shape=control_qid_shape,
|
|
@@ -518,11 +520,13 @@ class CCXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
518
520
|
"""
|
|
519
521
|
if num_controls == 0:
|
|
520
522
|
return self
|
|
523
|
+
sub_gate: 'cirq.Gate' = self
|
|
524
|
+
if self._global_shift == 0:
|
|
525
|
+
sub_gate = controlled_gate.ControlledGate(
|
|
526
|
+
common_gates.XPowGate(exponent=self._exponent), num_controls=2
|
|
527
|
+
)
|
|
521
528
|
return controlled_gate.ControlledGate(
|
|
522
|
-
|
|
523
|
-
common_gates.XPowGate(exponent=self._exponent, global_shift=self._global_shift),
|
|
524
|
-
num_controls=2,
|
|
525
|
-
),
|
|
529
|
+
sub_gate,
|
|
526
530
|
num_controls=num_controls,
|
|
527
531
|
control_values=control_values,
|
|
528
532
|
control_qid_shape=control_qid_shape,
|