cirq-core 1.6.0.dev20250501173104__py3-none-any.whl → 1.6.0.dev20250501231232__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/_version.py +1 -1
- cirq/_version_test.py +1 -1
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +211 -107
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +347 -3
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +18 -18
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +18 -19
- cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +8 -10
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +26 -28
- cirq/transformers/drop_empty_moments.py +4 -2
- cirq/transformers/drop_negligible_operations.py +6 -4
- cirq/transformers/dynamical_decoupling.py +6 -4
- cirq/transformers/dynamical_decoupling_test.py +8 -6
- cirq/transformers/eject_phased_paulis.py +14 -12
- cirq/transformers/eject_z.py +8 -6
- cirq/transformers/expand_composite.py +5 -3
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +3 -1
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +4 -1
- cirq/transformers/insertion_sort.py +6 -4
- cirq/transformers/measurement_transformers.py +21 -21
- cirq/transformers/merge_k_qubit_gates.py +11 -9
- cirq/transformers/merge_k_qubit_gates_test.py +5 -3
- cirq/transformers/merge_single_qubit_gates.py +15 -13
- cirq/transformers/optimize_for_target_gateset.py +14 -12
- cirq/transformers/optimize_for_target_gateset_test.py +7 -3
- cirq/transformers/qubit_management_transformers.py +10 -8
- cirq/transformers/randomized_measurements.py +9 -7
- cirq/transformers/routing/initial_mapper.py +5 -3
- cirq/transformers/routing/line_initial_mapper.py +15 -13
- cirq/transformers/routing/mapping_manager.py +9 -9
- cirq/transformers/routing/route_circuit_cqc.py +17 -15
- cirq/transformers/routing/visualize_routed_circuit.py +7 -6
- cirq/transformers/stratify.py +13 -11
- cirq/transformers/synchronize_terminal_measurements.py +9 -9
- cirq/transformers/target_gatesets/compilation_target_gateset.py +19 -17
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +11 -7
- cirq/transformers/target_gatesets/cz_gateset.py +4 -2
- cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +5 -3
- cirq/transformers/transformer_api.py +17 -15
- cirq/transformers/transformer_primitives.py +22 -20
- cirq/transformers/transformer_primitives_test.py +3 -1
- cirq/value/classical_data.py +26 -26
- cirq/value/condition.py +23 -21
- cirq/value/duration.py +11 -8
- cirq/value/linear_dict.py +22 -20
- cirq/value/periodic_value.py +4 -4
- cirq/value/probability.py +3 -1
- cirq/value/product_state.py +14 -12
- cirq/work/collector.py +7 -5
- cirq/work/observable_measurement.py +24 -22
- cirq/work/observable_measurement_data.py +9 -7
- cirq/work/observable_readout_calibration.py +4 -1
- cirq/work/observable_readout_calibration_test.py +4 -1
- cirq/work/observable_settings.py +4 -2
- cirq/work/pauli_sum_collector.py +8 -6
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/RECORD +59 -59
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/top_level.txt +0 -0
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Manages the mapping from logical to physical qubits during a routing procedure."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Dict, List, Sequence, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
import networkx as nx
|
|
@@ -35,9 +37,7 @@ class MappingManager:
|
|
|
35
37
|
logical qubits are mapped to, via `self.logical_qid_to_int` map).
|
|
36
38
|
"""
|
|
37
39
|
|
|
38
|
-
def __init__(
|
|
39
|
-
self, device_graph: nx.Graph, initial_mapping: Dict['cirq.Qid', 'cirq.Qid']
|
|
40
|
-
) -> None:
|
|
40
|
+
def __init__(self, device_graph: nx.Graph, initial_mapping: Dict[cirq.Qid, cirq.Qid]) -> None:
|
|
41
41
|
"""Initializes MappingManager.
|
|
42
42
|
|
|
43
43
|
Args:
|
|
@@ -84,12 +84,12 @@ class MappingManager:
|
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
@property
|
|
87
|
-
def physical_qid_to_int(self) -> Dict[
|
|
87
|
+
def physical_qid_to_int(self) -> Dict[cirq.Qid, int]:
|
|
88
88
|
"""Mapping of physical qubits, that were part of the initial mapping, to unique integers."""
|
|
89
89
|
return self._physical_qid_to_int
|
|
90
90
|
|
|
91
91
|
@property
|
|
92
|
-
def int_to_physical_qid(self) -> List[
|
|
92
|
+
def int_to_physical_qid(self) -> List[cirq.Qid]:
|
|
93
93
|
"""Inverse mapping of unique integers to corresponding physical qubits.
|
|
94
94
|
|
|
95
95
|
`self.physical_qid_to_int[self.int_to_physical_qid[i]] == i` for each i.
|
|
@@ -97,12 +97,12 @@ class MappingManager:
|
|
|
97
97
|
return self._int_to_physical_qid
|
|
98
98
|
|
|
99
99
|
@property
|
|
100
|
-
def logical_qid_to_int(self) -> Dict[
|
|
100
|
+
def logical_qid_to_int(self) -> Dict[cirq.Qid, int]:
|
|
101
101
|
"""Mapping of logical qubits, that were part of the initial mapping, to unique integers."""
|
|
102
102
|
return self._logical_qid_to_int
|
|
103
103
|
|
|
104
104
|
@property
|
|
105
|
-
def int_to_logical_qid(self) -> List[
|
|
105
|
+
def int_to_logical_qid(self) -> List[cirq.Qid]:
|
|
106
106
|
"""Inverse mapping of unique integers to corresponding physical qubits.
|
|
107
107
|
|
|
108
108
|
`self.logical_qid_to_int[self.int_to_logical_qid[i]] == i` for each i.
|
|
@@ -178,7 +178,7 @@ class MappingManager:
|
|
|
178
178
|
self._logical_to_physical[[lq1, lq2]] = self._logical_to_physical[[lq2, lq1]]
|
|
179
179
|
self._physical_to_logical[[pq1, pq2]] = self._physical_to_logical[[pq2, pq1]]
|
|
180
180
|
|
|
181
|
-
def mapped_op(self, op:
|
|
181
|
+
def mapped_op(self, op: cirq.Operation) -> cirq.Operation:
|
|
182
182
|
"""Transforms the given logical operation to act on corresponding physical qubits.
|
|
183
183
|
|
|
184
184
|
Args:
|
|
@@ -189,7 +189,7 @@ class MappingManager:
|
|
|
189
189
|
"""
|
|
190
190
|
logical_ints = [self._logical_qid_to_int[q] for q in op.qubits]
|
|
191
191
|
physical_ints = self.logical_to_physical[logical_ints]
|
|
192
|
-
qubit_map: Dict[
|
|
192
|
+
qubit_map: Dict[cirq.Qid, cirq.Qid] = {
|
|
193
193
|
q: self._int_to_physical_qid[physical_ints[i]] for i, q in enumerate(op.qubits)
|
|
194
194
|
}
|
|
195
195
|
return op.transform_qubits(qubit_map)
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Heuristic qubit routing algorithm based on arxiv:1902.08091."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
import itertools
|
|
18
20
|
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, TYPE_CHECKING
|
|
19
21
|
|
|
@@ -108,13 +110,13 @@ class RouteCQC:
|
|
|
108
110
|
|
|
109
111
|
def __call__(
|
|
110
112
|
self,
|
|
111
|
-
circuit:
|
|
113
|
+
circuit: cirq.AbstractCircuit,
|
|
112
114
|
*,
|
|
113
115
|
lookahead_radius: int = 8,
|
|
114
116
|
tag_inserted_swaps: bool = False,
|
|
115
|
-
initial_mapper: Optional[
|
|
116
|
-
context: Optional[
|
|
117
|
-
) ->
|
|
117
|
+
initial_mapper: Optional[cirq.AbstractInitialMapper] = None,
|
|
118
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
119
|
+
) -> cirq.AbstractCircuit:
|
|
118
120
|
"""Transforms the given circuit to make it executable on the device.
|
|
119
121
|
|
|
120
122
|
This method calls self.route_circuit and returns the routed circuit. See docstring of
|
|
@@ -150,13 +152,13 @@ class RouteCQC:
|
|
|
150
152
|
|
|
151
153
|
def route_circuit(
|
|
152
154
|
self,
|
|
153
|
-
circuit:
|
|
155
|
+
circuit: cirq.AbstractCircuit,
|
|
154
156
|
*,
|
|
155
157
|
lookahead_radius: int = 8,
|
|
156
158
|
tag_inserted_swaps: bool = False,
|
|
157
|
-
initial_mapper: Optional[
|
|
158
|
-
context: Optional[
|
|
159
|
-
) -> Tuple[
|
|
159
|
+
initial_mapper: Optional[cirq.AbstractInitialMapper] = None,
|
|
160
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
161
|
+
) -> Tuple[cirq.AbstractCircuit, Dict[cirq.Qid, cirq.Qid], Dict[cirq.Qid, cirq.Qid]]:
|
|
160
162
|
"""Transforms the given circuit to make it executable on the device.
|
|
161
163
|
|
|
162
164
|
This transformer assumes that all multi-qubit operations have been decomposed into 2-qubit
|
|
@@ -241,8 +243,8 @@ class RouteCQC:
|
|
|
241
243
|
|
|
242
244
|
@classmethod
|
|
243
245
|
def _get_one_and_two_qubit_ops_as_timesteps(
|
|
244
|
-
cls, circuit:
|
|
245
|
-
) -> Tuple[List[List[
|
|
246
|
+
cls, circuit: cirq.AbstractCircuit
|
|
247
|
+
) -> Tuple[List[List[cirq.Operation]], List[List[cirq.Operation]]]:
|
|
246
248
|
"""Gets the single and two qubit operations of the circuit factored into timesteps.
|
|
247
249
|
|
|
248
250
|
The i'th entry in the nested two-qubit and single-qubit ops correspond to the two-qubit
|
|
@@ -286,11 +288,11 @@ class RouteCQC:
|
|
|
286
288
|
def _route(
|
|
287
289
|
cls,
|
|
288
290
|
mm: mapping_manager.MappingManager,
|
|
289
|
-
two_qubit_ops: List[List[
|
|
290
|
-
single_qubit_ops: List[List[
|
|
291
|
+
two_qubit_ops: List[List[cirq.Operation]],
|
|
292
|
+
single_qubit_ops: List[List[cirq.Operation]],
|
|
291
293
|
lookahead_radius: int,
|
|
292
294
|
tag_inserted_swaps: bool = False,
|
|
293
|
-
) -> List[List[
|
|
295
|
+
) -> List[List[cirq.Operation]]:
|
|
294
296
|
"""Main routing procedure that inserts necessary swaps on the given timesteps.
|
|
295
297
|
|
|
296
298
|
The i'th element of the returned list corresponds to the routed operatiosn in the i'th
|
|
@@ -316,10 +318,10 @@ class RouteCQC:
|
|
|
316
318
|
]
|
|
317
319
|
for timestep_ops in two_qubit_ops
|
|
318
320
|
]
|
|
319
|
-
routed_ops: List[List[
|
|
321
|
+
routed_ops: List[List[cirq.Operation]] = []
|
|
320
322
|
|
|
321
323
|
def process_executable_two_qubit_ops(timestep: int) -> int:
|
|
322
|
-
unexecutable_ops: List[
|
|
324
|
+
unexecutable_ops: List[cirq.Operation] = []
|
|
323
325
|
unexecutable_ops_ints: List[QidIntPair] = []
|
|
324
326
|
for op, op_ints in zip(two_qubit_ops[timestep], two_qubit_ops_ints[timestep]):
|
|
325
327
|
if mm.is_adjacent(*op_ints):
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
from typing import Dict, Optional, Tuple, TYPE_CHECKING
|
|
16
18
|
|
|
17
19
|
from cirq import circuits, ops
|
|
@@ -23,20 +25,19 @@ if TYPE_CHECKING:
|
|
|
23
25
|
class _SwapPrintGate(ops.Gate):
|
|
24
26
|
"""A gate that displays the string representation of each qubits on the circuit."""
|
|
25
27
|
|
|
26
|
-
def __init__(self, qubits: Tuple[Tuple[
|
|
28
|
+
def __init__(self, qubits: Tuple[Tuple[cirq.Qid, cirq.Qid], ...]) -> None:
|
|
27
29
|
self.qubits = qubits
|
|
28
30
|
|
|
29
31
|
def num_qubits(self):
|
|
30
32
|
return len(self.qubits)
|
|
31
33
|
|
|
32
|
-
def _circuit_diagram_info_(self, args:
|
|
34
|
+
def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Tuple[str, ...]:
|
|
33
35
|
return tuple(f'{str(q[1])}' for q in self.qubits)
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
def routed_circuit_with_mapping(
|
|
37
|
-
routed_circuit:
|
|
38
|
-
|
|
39
|
-
) -> 'cirq.AbstractCircuit':
|
|
39
|
+
routed_circuit: cirq.AbstractCircuit, initial_map: Optional[Dict[cirq.Qid, cirq.Qid]] = None
|
|
40
|
+
) -> cirq.AbstractCircuit:
|
|
40
41
|
"""Returns the same circuits with information about the permutation of qubits after each swap.
|
|
41
42
|
|
|
42
43
|
Args:
|
|
@@ -54,7 +55,7 @@ def routed_circuit_with_mapping(
|
|
|
54
55
|
initial_map = qdict.copy()
|
|
55
56
|
inverse_map = {v: k for k, v in initial_map.items()}
|
|
56
57
|
|
|
57
|
-
def swap_print_moment() ->
|
|
58
|
+
def swap_print_moment() -> cirq.Operation:
|
|
58
59
|
return _SwapPrintGate(
|
|
59
60
|
tuple(zip(qdict.values(), [inverse_map[x] for x in qdict.values()]))
|
|
60
61
|
).on(*all_qubits)
|
cirq/transformers/stratify.py
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass to repack circuits avoiding simultaneous operations with different classes."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
import itertools
|
|
18
20
|
from typing import Callable, Dict, Iterable, List, Optional, Sequence, Type, TYPE_CHECKING, Union
|
|
19
21
|
|
|
@@ -37,11 +39,11 @@ Category = Union[
|
|
|
37
39
|
|
|
38
40
|
@transformer_api.transformer(add_deep_support=True)
|
|
39
41
|
def stratified_circuit(
|
|
40
|
-
circuit:
|
|
42
|
+
circuit: cirq.AbstractCircuit,
|
|
41
43
|
*,
|
|
42
|
-
context: Optional[
|
|
44
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
43
45
|
categories: Iterable[Category] = (),
|
|
44
|
-
) ->
|
|
46
|
+
) -> cirq.Circuit:
|
|
45
47
|
"""Repacks avoiding simultaneous operations with different classes.
|
|
46
48
|
|
|
47
49
|
This transforms the given circuit to ensure that no operations of different categories are
|
|
@@ -96,9 +98,9 @@ def stratified_circuit(
|
|
|
96
98
|
def _stratify_circuit(
|
|
97
99
|
circuit: circuits.AbstractCircuit,
|
|
98
100
|
*,
|
|
99
|
-
context:
|
|
101
|
+
context: cirq.TransformerContext,
|
|
100
102
|
classifiers: Sequence[Classifier],
|
|
101
|
-
) ->
|
|
103
|
+
) -> cirq.Circuit:
|
|
102
104
|
"""Performs the stratification by iterating through the operations in the
|
|
103
105
|
circuit and using the given classifiers to align them.
|
|
104
106
|
|
|
@@ -115,12 +117,12 @@ def _stratify_circuit(
|
|
|
115
117
|
The stratified circuit.
|
|
116
118
|
"""
|
|
117
119
|
num_classes = len(classifiers) + 1 # include one "extra" category for ignored operations
|
|
118
|
-
new_moments: List[List[
|
|
120
|
+
new_moments: List[List[cirq.Operation]] = []
|
|
119
121
|
|
|
120
122
|
# Keep track of the latest time index for each qubit, measurement key, and control key.
|
|
121
|
-
qubit_time_index: Dict[
|
|
122
|
-
measurement_time_index: Dict[
|
|
123
|
-
control_time_index: Dict[
|
|
123
|
+
qubit_time_index: Dict[cirq.Qid, int] = {}
|
|
124
|
+
measurement_time_index: Dict[cirq.MeasurementKey, int] = {}
|
|
125
|
+
control_time_index: Dict[cirq.MeasurementKey, int] = {}
|
|
124
126
|
|
|
125
127
|
# The minimum time index for operations with a tag in context.tags_to_ignore.
|
|
126
128
|
last_ignored_ops_time_index = 0
|
|
@@ -221,12 +223,12 @@ def _category_to_classifier(category) -> Classifier:
|
|
|
221
223
|
)
|
|
222
224
|
|
|
223
225
|
|
|
224
|
-
def _mock_classifier(op:
|
|
226
|
+
def _mock_classifier(op: cirq.Operation) -> bool:
|
|
225
227
|
"""Mock classifier, used to "complete" a collection of classifiers and make it exhaustive."""
|
|
226
228
|
return False # pragma: no cover
|
|
227
229
|
|
|
228
230
|
|
|
229
|
-
def _get_op_class(op:
|
|
231
|
+
def _get_op_class(op: cirq.Operation, classifiers: Sequence[Classifier]) -> int:
|
|
230
232
|
"""Get the "class" of an operator, by index."""
|
|
231
233
|
for class_index, classifier in enumerate(classifiers):
|
|
232
234
|
if classifier is _mock_classifier:
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass to move terminal measurements to the end of circuit."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import List, Optional, Set, Tuple, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, protocols
|
|
@@ -23,9 +25,7 @@ if TYPE_CHECKING:
|
|
|
23
25
|
import cirq
|
|
24
26
|
|
|
25
27
|
|
|
26
|
-
def find_terminal_measurements(
|
|
27
|
-
circuit: 'cirq.AbstractCircuit',
|
|
28
|
-
) -> List[Tuple[int, 'cirq.Operation']]:
|
|
28
|
+
def find_terminal_measurements(circuit: cirq.AbstractCircuit) -> List[Tuple[int, cirq.Operation]]:
|
|
29
29
|
"""Finds all terminal measurements in the given circuit.
|
|
30
30
|
|
|
31
31
|
A measurement is terminal if there are no other operations acting on the measured qubits
|
|
@@ -39,9 +39,9 @@ def find_terminal_measurements(
|
|
|
39
39
|
(moment_index, measurement_operation).
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
open_qubits: Set[
|
|
43
|
-
seen_control_keys: Set[
|
|
44
|
-
terminal_measurements: Set[Tuple[int,
|
|
42
|
+
open_qubits: Set[cirq.Qid] = set(circuit.all_qubits())
|
|
43
|
+
seen_control_keys: Set[cirq.MeasurementKey] = set()
|
|
44
|
+
terminal_measurements: Set[Tuple[int, cirq.Operation]] = set()
|
|
45
45
|
for i in range(len(circuit) - 1, -1, -1):
|
|
46
46
|
moment = circuit[i]
|
|
47
47
|
for q in open_qubits:
|
|
@@ -62,11 +62,11 @@ def find_terminal_measurements(
|
|
|
62
62
|
|
|
63
63
|
@transformer_api.transformer(add_deep_support=True)
|
|
64
64
|
def synchronize_terminal_measurements(
|
|
65
|
-
circuit:
|
|
65
|
+
circuit: cirq.AbstractCircuit,
|
|
66
66
|
*,
|
|
67
|
-
context: Optional[
|
|
67
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
68
68
|
after_other_operations: bool = True,
|
|
69
|
-
) ->
|
|
69
|
+
) -> cirq.Circuit:
|
|
70
70
|
"""Move measurements to the end of the circuit.
|
|
71
71
|
|
|
72
72
|
Move all measurements in a circuit to the final moment, if it can accommodate them (without
|
|
@@ -14,18 +14,20 @@
|
|
|
14
14
|
|
|
15
15
|
"""Base class for creating custom target gatesets which can be used for compilation."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
import abc
|
|
18
20
|
from typing import Hashable, List, Optional, Type, TYPE_CHECKING, Union
|
|
19
21
|
|
|
20
22
|
from cirq import circuits, ops, protocols, transformers
|
|
21
|
-
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
22
23
|
from cirq.transformers import merge_k_qubit_gates, merge_single_qubit_gates
|
|
23
24
|
|
|
24
25
|
if TYPE_CHECKING:
|
|
25
26
|
import cirq
|
|
27
|
+
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
26
28
|
|
|
27
29
|
|
|
28
|
-
def create_transformer_with_kwargs(transformer:
|
|
30
|
+
def create_transformer_with_kwargs(transformer: cirq.TRANSFORMER, **kwargs) -> cirq.TRANSFORMER:
|
|
29
31
|
"""Method to capture additional keyword arguments to transformers while preserving mypy type.
|
|
30
32
|
|
|
31
33
|
Returns a `cirq.TRANSFORMER` which, when called with a circuit and transformer context, is
|
|
@@ -33,13 +35,13 @@ def create_transformer_with_kwargs(transformer: 'cirq.TRANSFORMER', **kwargs) ->
|
|
|
33
35
|
capture keyword arguments of a transformer before passing them as an argument to an API that
|
|
34
36
|
expects `cirq.TRANSFORMER`. For example:
|
|
35
37
|
|
|
36
|
-
>>> def run_transformers(transformers:
|
|
38
|
+
>>> def run_transformers(transformers: list[cirq.TRANSFORMER]):
|
|
37
39
|
... circuit = cirq.Circuit(cirq.X(cirq.q(0)))
|
|
38
40
|
... context = cirq.TransformerContext()
|
|
39
41
|
... for transformer in transformers:
|
|
40
42
|
... transformer(circuit, context=context)
|
|
41
43
|
...
|
|
42
|
-
>>> transformers:
|
|
44
|
+
>>> transformers: list[cirq.TRANSFORMER] = []
|
|
43
45
|
>>> transformers.append(
|
|
44
46
|
... cirq.create_transformer_with_kwargs(
|
|
45
47
|
... cirq.expand_composite, no_decomp=lambda op: cirq.num_qubits(op) <= 2
|
|
@@ -65,8 +67,8 @@ def create_transformer_with_kwargs(transformer: 'cirq.TRANSFORMER', **kwargs) ->
|
|
|
65
67
|
raise SyntaxError('**kwargs to be captured must not contain `context`.')
|
|
66
68
|
|
|
67
69
|
def transformer_with_kwargs(
|
|
68
|
-
circuit:
|
|
69
|
-
) ->
|
|
70
|
+
circuit: cirq.AbstractCircuit, *, context: Optional[cirq.TransformerContext] = None
|
|
71
|
+
) -> cirq.AbstractCircuit:
|
|
70
72
|
return transformer(circuit, context=context, **kwargs)
|
|
71
73
|
|
|
72
74
|
return transformer_with_kwargs
|
|
@@ -81,7 +83,7 @@ class CompilationTargetGateset(ops.Gateset, metaclass=abc.ABCMeta):
|
|
|
81
83
|
|
|
82
84
|
def __init__(
|
|
83
85
|
self,
|
|
84
|
-
*gates: Union[Type[
|
|
86
|
+
*gates: Union[Type[cirq.Gate], cirq.Gate, cirq.GateFamily],
|
|
85
87
|
name: Optional[str] = None,
|
|
86
88
|
unroll_circuit_op: bool = True,
|
|
87
89
|
preserve_moment_structure: bool = True,
|
|
@@ -116,7 +118,7 @@ class CompilationTargetGateset(ops.Gateset, metaclass=abc.ABCMeta):
|
|
|
116
118
|
"""Maximum number of qubits on which a gate from this gateset can act upon."""
|
|
117
119
|
|
|
118
120
|
@abc.abstractmethod
|
|
119
|
-
def decompose_to_target_gateset(self, op:
|
|
121
|
+
def decompose_to_target_gateset(self, op: cirq.Operation, moment_idx: int) -> DecomposeResult:
|
|
120
122
|
"""Method to rewrite the given operation using gates from this gateset.
|
|
121
123
|
|
|
122
124
|
Args:
|
|
@@ -128,7 +130,7 @@ class CompilationTargetGateset(ops.Gateset, metaclass=abc.ABCMeta):
|
|
|
128
130
|
- `None` or `NotImplemented` if does not know how to decompose `op`.
|
|
129
131
|
"""
|
|
130
132
|
|
|
131
|
-
def _validate_operation(self, op:
|
|
133
|
+
def _validate_operation(self, op: cirq.Operation) -> bool:
|
|
132
134
|
"""Validates whether the given `cirq.Operation` is contained in this Gateset.
|
|
133
135
|
|
|
134
136
|
Overrides the method on the base gateset class to ensure that operations which created
|
|
@@ -153,7 +155,7 @@ class CompilationTargetGateset(ops.Gateset, metaclass=abc.ABCMeta):
|
|
|
153
155
|
return "_default_merged_k_qubit_unitaries"
|
|
154
156
|
|
|
155
157
|
@property
|
|
156
|
-
def preprocess_transformers(self) -> List[
|
|
158
|
+
def preprocess_transformers(self) -> List[cirq.TRANSFORMER]:
|
|
157
159
|
"""List of transformers which should be run before decomposing individual operations."""
|
|
158
160
|
reorder_transfomers = (
|
|
159
161
|
[transformers.insertion_sort_transformer] if self._reorder_operations else []
|
|
@@ -172,9 +174,9 @@ class CompilationTargetGateset(ops.Gateset, metaclass=abc.ABCMeta):
|
|
|
172
174
|
]
|
|
173
175
|
|
|
174
176
|
@property
|
|
175
|
-
def postprocess_transformers(self) -> List[
|
|
177
|
+
def postprocess_transformers(self) -> List[cirq.TRANSFORMER]:
|
|
176
178
|
"""List of transformers which should be run after decomposing individual operations."""
|
|
177
|
-
processors: List[
|
|
179
|
+
processors: List[cirq.TRANSFORMER] = [
|
|
178
180
|
merge_single_qubit_gates.merge_single_qubit_moments_to_phxz,
|
|
179
181
|
transformers.drop_negligible_operations,
|
|
180
182
|
transformers.drop_empty_moments,
|
|
@@ -221,7 +223,7 @@ class TwoQubitCompilationTargetGateset(CompilationTargetGateset):
|
|
|
221
223
|
def num_qubits(self) -> int:
|
|
222
224
|
return 2
|
|
223
225
|
|
|
224
|
-
def decompose_to_target_gateset(self, op:
|
|
226
|
+
def decompose_to_target_gateset(self, op: cirq.Operation, moment_idx: int) -> DecomposeResult:
|
|
225
227
|
if not 1 <= protocols.num_qubits(op) <= 2:
|
|
226
228
|
return self._decompose_multi_qubit_operation(op, moment_idx)
|
|
227
229
|
if protocols.num_qubits(op) == 1:
|
|
@@ -248,7 +250,7 @@ class TwoQubitCompilationTargetGateset(CompilationTargetGateset):
|
|
|
248
250
|
)
|
|
249
251
|
if switch_to_new:
|
|
250
252
|
return new_optree
|
|
251
|
-
mapped_old_optree: List[
|
|
253
|
+
mapped_old_optree: List[cirq.OP_TREE] = []
|
|
252
254
|
for old_op in ops.flatten_to_ops(old_optree):
|
|
253
255
|
if old_op in self:
|
|
254
256
|
mapped_old_optree.append(old_op)
|
|
@@ -260,7 +262,7 @@ class TwoQubitCompilationTargetGateset(CompilationTargetGateset):
|
|
|
260
262
|
return mapped_old_optree
|
|
261
263
|
|
|
262
264
|
def _decompose_single_qubit_operation(
|
|
263
|
-
self, op:
|
|
265
|
+
self, op: cirq.Operation, moment_idx: int
|
|
264
266
|
) -> DecomposeResult:
|
|
265
267
|
"""Decomposes (connected component of) 1-qubit operations using gates from this gateset.
|
|
266
268
|
|
|
@@ -282,7 +284,7 @@ class TwoQubitCompilationTargetGateset(CompilationTargetGateset):
|
|
|
282
284
|
)
|
|
283
285
|
|
|
284
286
|
def _decompose_multi_qubit_operation(
|
|
285
|
-
self, op:
|
|
287
|
+
self, op: cirq.Operation, moment_idx: int
|
|
286
288
|
) -> DecomposeResult:
|
|
287
289
|
"""Decomposes operations acting on more than 2 qubits using gates from this gateset.
|
|
288
290
|
|
|
@@ -298,7 +300,7 @@ class TwoQubitCompilationTargetGateset(CompilationTargetGateset):
|
|
|
298
300
|
|
|
299
301
|
@abc.abstractmethod
|
|
300
302
|
def _decompose_two_qubit_operation(
|
|
301
|
-
self, op:
|
|
303
|
+
self, op: cirq.Operation, moment_idx: int
|
|
302
304
|
) -> DecomposeResult:
|
|
303
305
|
"""Decomposes (connected component of) 2-qubit operations using gates from this gateset.
|
|
304
306
|
|
|
@@ -12,12 +12,16 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import List, TYPE_CHECKING
|
|
16
18
|
|
|
17
19
|
import pytest
|
|
18
20
|
|
|
19
21
|
import cirq
|
|
20
|
-
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
def test_compilation_target_gateset():
|
|
@@ -29,7 +33,7 @@ def test_compilation_target_gateset():
|
|
|
29
33
|
def num_qubits(self) -> int:
|
|
30
34
|
return 2
|
|
31
35
|
|
|
32
|
-
def decompose_to_target_gateset(self, op:
|
|
36
|
+
def decompose_to_target_gateset(self, op: cirq.Operation, _) -> DecomposeResult:
|
|
33
37
|
return op if cirq.num_qubits(op) == 2 and cirq.has_unitary(op) else NotImplemented
|
|
34
38
|
|
|
35
39
|
@property
|
|
@@ -63,7 +67,7 @@ class ExampleCXTargetGateset(cirq.TwoQubitCompilationTargetGateset):
|
|
|
63
67
|
def __init__(self):
|
|
64
68
|
super().__init__(cirq.AnyUnitaryGateFamily(1), cirq.CNOT)
|
|
65
69
|
|
|
66
|
-
def _decompose_two_qubit_operation(self, op:
|
|
70
|
+
def _decompose_two_qubit_operation(self, op: cirq.Operation, _) -> DecomposeResult:
|
|
67
71
|
if not cirq.has_unitary(op):
|
|
68
72
|
return NotImplemented
|
|
69
73
|
|
|
@@ -77,7 +81,7 @@ class ExampleCXTargetGateset(cirq.TwoQubitCompilationTargetGateset):
|
|
|
77
81
|
cirq.Z.on_each(q0, q1),
|
|
78
82
|
]
|
|
79
83
|
|
|
80
|
-
def _decompose_single_qubit_operation(self, op:
|
|
84
|
+
def _decompose_single_qubit_operation(self, op: cirq.Operation, _) -> DecomposeResult:
|
|
81
85
|
if not cirq.has_unitary(op):
|
|
82
86
|
return NotImplemented
|
|
83
87
|
assert self._intermediate_result_tag in op.tags
|
|
@@ -209,11 +213,11 @@ def test_two_qubit_compilation_replaces_only_if_2q_gate_count_is_less():
|
|
|
209
213
|
def __init__(self):
|
|
210
214
|
super().__init__(cirq.X, cirq.CNOT)
|
|
211
215
|
|
|
212
|
-
def _decompose_two_qubit_operation(self, op:
|
|
216
|
+
def _decompose_two_qubit_operation(self, op: cirq.Operation, _) -> DecomposeResult:
|
|
213
217
|
q0, q1 = op.qubits
|
|
214
218
|
return [cirq.X.on_each(q0, q1), cirq.CNOT(q0, q1)] * 10
|
|
215
219
|
|
|
216
|
-
def _decompose_single_qubit_operation(self, op:
|
|
220
|
+
def _decompose_single_qubit_operation(self, op: cirq.Operation, _) -> DecomposeResult:
|
|
217
221
|
return cirq.X(*op.qubits) if op.gate == cirq.Y else NotImplemented
|
|
218
222
|
|
|
219
223
|
q = cirq.LineQubit.range(2)
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Target gateset used for compiling circuits to CZ + 1-q rotations + measurement gates."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Any, Dict, Sequence, Type, TYPE_CHECKING, Union
|
|
18
20
|
|
|
19
21
|
from cirq import ops, protocols
|
|
@@ -47,7 +49,7 @@ class CZTargetGateset(compilation_target_gateset.TwoQubitCompilationTargetGatese
|
|
|
47
49
|
*,
|
|
48
50
|
atol: float = 1e-8,
|
|
49
51
|
allow_partial_czs: bool = False,
|
|
50
|
-
additional_gates: Sequence[Union[Type[
|
|
52
|
+
additional_gates: Sequence[Union[Type[cirq.Gate], cirq.Gate, cirq.GateFamily]] = (),
|
|
51
53
|
preserve_moment_structure: bool = True,
|
|
52
54
|
reorder_operations: bool = False,
|
|
53
55
|
) -> None:
|
|
@@ -83,7 +85,7 @@ class CZTargetGateset(compilation_target_gateset.TwoQubitCompilationTargetGatese
|
|
|
83
85
|
self.atol = atol
|
|
84
86
|
self.allow_partial_czs = allow_partial_czs
|
|
85
87
|
|
|
86
|
-
def _decompose_two_qubit_operation(self, op:
|
|
88
|
+
def _decompose_two_qubit_operation(self, op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
87
89
|
if not protocols.has_unitary(op):
|
|
88
90
|
return NotImplemented
|
|
89
91
|
return two_qubit_to_cz.two_qubit_matrix_to_cz_operations(
|
|
@@ -14,15 +14,17 @@
|
|
|
14
14
|
|
|
15
15
|
"""Target gateset used for compiling circuits to √iSWAP + 1-q rotations + measurement gates."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Any, Dict, Optional, Sequence, Type, TYPE_CHECKING, Union
|
|
18
20
|
|
|
19
21
|
from cirq import ops, protocols
|
|
20
|
-
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
21
22
|
from cirq.transformers.analytical_decompositions import two_qubit_to_sqrt_iswap
|
|
22
23
|
from cirq.transformers.target_gatesets import compilation_target_gateset
|
|
23
24
|
|
|
24
25
|
if TYPE_CHECKING:
|
|
25
26
|
import cirq
|
|
27
|
+
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
class SqrtIswapTargetGateset(compilation_target_gateset.TwoQubitCompilationTargetGateset):
|
|
@@ -49,7 +51,7 @@ class SqrtIswapTargetGateset(compilation_target_gateset.TwoQubitCompilationTarge
|
|
|
49
51
|
atol: float = 1e-8,
|
|
50
52
|
required_sqrt_iswap_count: Optional[int] = None,
|
|
51
53
|
use_sqrt_iswap_inv: bool = False,
|
|
52
|
-
additional_gates: Sequence[Union[Type[
|
|
54
|
+
additional_gates: Sequence[Union[Type[cirq.Gate], cirq.Gate, cirq.GateFamily]] = (),
|
|
53
55
|
):
|
|
54
56
|
"""Initializes `cirq.SqrtIswapTargetGateset`
|
|
55
57
|
|
|
@@ -87,7 +89,7 @@ class SqrtIswapTargetGateset(compilation_target_gateset.TwoQubitCompilationTarge
|
|
|
87
89
|
self.required_sqrt_iswap_count = required_sqrt_iswap_count
|
|
88
90
|
self.use_sqrt_iswap_inv = use_sqrt_iswap_inv
|
|
89
91
|
|
|
90
|
-
def _decompose_two_qubit_operation(self, op:
|
|
92
|
+
def _decompose_two_qubit_operation(self, op: cirq.Operation, _) -> DecomposeResult:
|
|
91
93
|
if protocols.has_unitary(op):
|
|
92
94
|
return two_qubit_to_sqrt_iswap.two_qubit_matrix_to_sqrt_iswap_operations(
|
|
93
95
|
op.qubits[0],
|