cirq-core 1.6.0.dev20250501173104__py3-none-any.whl → 1.6.0.dev20250501192724__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/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.dev20250501192724.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/RECORD +57 -57
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250501173104.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/top_level.txt +0 -0
|
@@ -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, Set, Tuple, TYPE_CHECKING
|
|
16
18
|
|
|
17
19
|
from cirq import circuits, ops
|
|
@@ -21,8 +23,8 @@ if TYPE_CHECKING:
|
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
def _get_qubit_mapping_first_and_last_moment(
|
|
24
|
-
circuit:
|
|
25
|
-
) -> Dict[
|
|
26
|
+
circuit: cirq.AbstractCircuit,
|
|
27
|
+
) -> Dict[cirq.Qid, Tuple[int, int]]:
|
|
26
28
|
"""Computes `(first_moment_idx, last_moment_idx)` tuple for each qubit in the input circuit.
|
|
27
29
|
|
|
28
30
|
Args:
|
|
@@ -41,13 +43,13 @@ def _get_qubit_mapping_first_and_last_moment(
|
|
|
41
43
|
return ret
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
def _is_temp(q:
|
|
46
|
+
def _is_temp(q: cirq.Qid) -> bool:
|
|
45
47
|
return isinstance(q, (ops.CleanQubit, ops.BorrowableQubit))
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
def map_clean_and_borrowable_qubits(
|
|
49
|
-
circuit:
|
|
50
|
-
) ->
|
|
51
|
+
circuit: cirq.AbstractCircuit, *, qm: Optional[cirq.QubitManager] = None
|
|
52
|
+
) -> cirq.Circuit:
|
|
51
53
|
"""Uses `qm: QubitManager` to map all `CleanQubit`/`BorrowableQubit`s to system qubits.
|
|
52
54
|
|
|
53
55
|
`CleanQubit` and `BorrowableQubit` are internal qubit types that are used as placeholder qubits
|
|
@@ -97,11 +99,11 @@ def map_clean_and_borrowable_qubits(
|
|
|
97
99
|
trivial_map = {q: q for q in all_qubits}
|
|
98
100
|
# `allocated_map` maintains the mapping of all temporary qubits seen so far, mapping each of
|
|
99
101
|
# them to either a newly allocated managed ancilla or an existing borrowed system qubit.
|
|
100
|
-
allocated_map: Dict[
|
|
101
|
-
to_free: Set[
|
|
102
|
+
allocated_map: Dict[cirq.Qid, cirq.Qid] = {}
|
|
103
|
+
to_free: Set[cirq.Qid] = set()
|
|
102
104
|
last_op_idx = -1
|
|
103
105
|
|
|
104
|
-
def map_func(op:
|
|
106
|
+
def map_func(op: cirq.Operation, idx: int) -> cirq.OP_TREE:
|
|
105
107
|
nonlocal last_op_idx, to_free
|
|
106
108
|
assert isinstance(qm, ops.QubitManager)
|
|
107
109
|
|
|
@@ -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 collections.abc import Sequence
|
|
16
18
|
from typing import Any
|
|
17
19
|
|
|
@@ -39,12 +41,12 @@ class RandomizedMeasurements:
|
|
|
39
41
|
|
|
40
42
|
def __call__(
|
|
41
43
|
self,
|
|
42
|
-
circuit:
|
|
44
|
+
circuit: cirq.AbstractCircuit,
|
|
43
45
|
unitary_ensemble: str = "pauli",
|
|
44
46
|
rng: np.random.Generator | None = None,
|
|
45
47
|
*,
|
|
46
48
|
context: transformer_api.TransformerContext | None = None,
|
|
47
|
-
) ->
|
|
49
|
+
) -> cirq.Circuit:
|
|
48
50
|
"""Apply the transformer to the given circuit. Given an input circuit returns
|
|
49
51
|
a new circuit with the pre-measurement unitaries and measurements gates added.
|
|
50
52
|
to the qubits in the subsystem provided.If no subsystem is specified in the
|
|
@@ -80,7 +82,7 @@ class RandomizedMeasurements:
|
|
|
80
82
|
|
|
81
83
|
def random_single_qubit_unitary_moment(
|
|
82
84
|
self, unitary_ensemble: str, qubits: Sequence[Any], rng: np.random.Generator
|
|
83
|
-
) ->
|
|
85
|
+
) -> cirq.Moment:
|
|
84
86
|
"""Outputs the cirq moment associated with the pre-measurement rotations.
|
|
85
87
|
|
|
86
88
|
Args:
|
|
@@ -115,7 +117,7 @@ class RandomizedMeasurements:
|
|
|
115
117
|
return cirq.Moment.from_ops(*op_list)
|
|
116
118
|
|
|
117
119
|
|
|
118
|
-
def _pauli_basis_rotation(rng: np.random.Generator) ->
|
|
120
|
+
def _pauli_basis_rotation(rng: np.random.Generator) -> cirq.Gate:
|
|
119
121
|
"""Randomly generate a Pauli basis rotation.
|
|
120
122
|
|
|
121
123
|
Args:
|
|
@@ -127,7 +129,7 @@ def _pauli_basis_rotation(rng: np.random.Generator) -> "cirq.Gate":
|
|
|
127
129
|
basis_idx = rng.choice(np.arange(3))
|
|
128
130
|
|
|
129
131
|
if basis_idx == 0:
|
|
130
|
-
gate:
|
|
132
|
+
gate: cirq.Gate = cirq.Ry(rads=-np.pi / 2)
|
|
131
133
|
elif basis_idx == 1:
|
|
132
134
|
gate = cirq.Rx(rads=np.pi / 2)
|
|
133
135
|
else:
|
|
@@ -135,7 +137,7 @@ def _pauli_basis_rotation(rng: np.random.Generator) -> "cirq.Gate":
|
|
|
135
137
|
return gate
|
|
136
138
|
|
|
137
139
|
|
|
138
|
-
def _single_qubit_clifford(rng: np.random.Generator) ->
|
|
140
|
+
def _single_qubit_clifford(rng: np.random.Generator) -> cirq.Gate:
|
|
139
141
|
"""Randomly generate a single-qubit Clifford rotation.
|
|
140
142
|
|
|
141
143
|
Args:
|
|
@@ -153,7 +155,7 @@ def _single_qubit_clifford(rng: np.random.Generator) -> "cirq.Gate":
|
|
|
153
155
|
)
|
|
154
156
|
|
|
155
157
|
|
|
156
|
-
def _single_qubit_cue(rng: np.random.Generator) ->
|
|
158
|
+
def _single_qubit_cue(rng: np.random.Generator) -> cirq.Gate:
|
|
157
159
|
"""Randomly generate a CUE gate.
|
|
158
160
|
|
|
159
161
|
Args:
|
|
@@ -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
|
import abc
|
|
16
18
|
from typing import Dict, TYPE_CHECKING
|
|
17
19
|
|
|
@@ -37,7 +39,7 @@ class AbstractInitialMapper(metaclass=abc.ABCMeta):
|
|
|
37
39
|
"""
|
|
38
40
|
|
|
39
41
|
@abc.abstractmethod
|
|
40
|
-
def initial_mapping(self, circuit:
|
|
42
|
+
def initial_mapping(self, circuit: cirq.AbstractCircuit) -> Dict[cirq.Qid, cirq.Qid]:
|
|
41
43
|
"""Maps the logical qubits of a circuit onto physical qubits on a device.
|
|
42
44
|
|
|
43
45
|
Args:
|
|
@@ -52,10 +54,10 @@ class AbstractInitialMapper(metaclass=abc.ABCMeta):
|
|
|
52
54
|
class HardCodedInitialMapper(AbstractInitialMapper):
|
|
53
55
|
"""Initial Mapper class takes a hard-coded mapping and returns it."""
|
|
54
56
|
|
|
55
|
-
def __init__(self, _map: Dict[
|
|
57
|
+
def __init__(self, _map: Dict[cirq.Qid, cirq.Qid]) -> None:
|
|
56
58
|
self._map = _map
|
|
57
59
|
|
|
58
|
-
def initial_mapping(self, circuit:
|
|
60
|
+
def initial_mapping(self, circuit: cirq.AbstractCircuit) -> Dict[cirq.Qid, cirq.Qid]:
|
|
59
61
|
"""Returns the hard-coded initial mapping.
|
|
60
62
|
|
|
61
63
|
Args:
|
|
@@ -30,6 +30,8 @@ If some logical qubits are unampped after this first procedure then there are tw
|
|
|
30
30
|
the nearest available neighbor to the center of the device.
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
33
35
|
from collections import deque
|
|
34
36
|
from typing import Deque, Dict, List, Set, Tuple, TYPE_CHECKING
|
|
35
37
|
|
|
@@ -82,8 +84,8 @@ class LineInitialMapper(initial_mapper.AbstractInitialMapper):
|
|
|
82
84
|
self.center = nx.center(self.device_graph)[0]
|
|
83
85
|
|
|
84
86
|
def _make_circuit_graph(
|
|
85
|
-
self, circuit:
|
|
86
|
-
) -> Tuple[List[Deque[
|
|
87
|
+
self, circuit: cirq.AbstractCircuit
|
|
88
|
+
) -> Tuple[List[Deque[cirq.Qid]], Dict[cirq.Qid, cirq.Qid]]:
|
|
87
89
|
"""Creates a (potentially incomplete) qubit connectivity graph of the circuit.
|
|
88
90
|
|
|
89
91
|
Iterates over moments in the circuit from left to right and adds edges between logical
|
|
@@ -99,11 +101,11 @@ class LineInitialMapper(initial_mapper.AbstractInitialMapper):
|
|
|
99
101
|
The (potentially incomplete) qubit connectivity graph of the circuit, which is
|
|
100
102
|
guaranteed to be a forest of line graphs.
|
|
101
103
|
"""
|
|
102
|
-
circuit_graph: List[Deque[
|
|
103
|
-
component_id: Dict[
|
|
104
|
-
partners: Dict[
|
|
104
|
+
circuit_graph: List[Deque[cirq.Qid]] = [deque([q]) for q in sorted(circuit.all_qubits())]
|
|
105
|
+
component_id: Dict[cirq.Qid, int] = {q[0]: i for i, q in enumerate(circuit_graph)}
|
|
106
|
+
partners: Dict[cirq.Qid, cirq.Qid] = {}
|
|
105
107
|
|
|
106
|
-
def degree_lt_two(q:
|
|
108
|
+
def degree_lt_two(q: cirq.Qid):
|
|
107
109
|
return any(circuit_graph[component_id[q]][i] == q for i in [-1, 0])
|
|
108
110
|
|
|
109
111
|
for op in circuit.all_operations():
|
|
@@ -141,7 +143,7 @@ class LineInitialMapper(initial_mapper.AbstractInitialMapper):
|
|
|
141
143
|
)
|
|
142
144
|
return graph, partners
|
|
143
145
|
|
|
144
|
-
def initial_mapping(self, circuit:
|
|
146
|
+
def initial_mapping(self, circuit: cirq.AbstractCircuit) -> Dict[cirq.Qid, cirq.Qid]:
|
|
145
147
|
"""Maps disjoint lines of logical qubits onto lines of physical qubits.
|
|
146
148
|
|
|
147
149
|
Args:
|
|
@@ -151,13 +153,13 @@ class LineInitialMapper(initial_mapper.AbstractInitialMapper):
|
|
|
151
153
|
a dictionary that maps logical qubits in the circuit (keys) to physical qubits on the
|
|
152
154
|
device (values).
|
|
153
155
|
"""
|
|
154
|
-
mapped_physicals: Set[
|
|
155
|
-
qubit_map: Dict[
|
|
156
|
+
mapped_physicals: Set[cirq.Qid] = set()
|
|
157
|
+
qubit_map: Dict[cirq.Qid, cirq.Qid] = {}
|
|
156
158
|
circuit_graph, partners = self._make_circuit_graph(circuit)
|
|
157
159
|
|
|
158
160
|
def next_physical(
|
|
159
|
-
current_physical:
|
|
160
|
-
) ->
|
|
161
|
+
current_physical: cirq.Qid, partner: cirq.Qid, isolated: bool = False
|
|
162
|
+
) -> cirq.Qid:
|
|
161
163
|
# Handle the first physical qubit getting mapped.
|
|
162
164
|
if current_physical not in mapped_physicals:
|
|
163
165
|
return current_physical
|
|
@@ -189,8 +191,8 @@ class LineInitialMapper(initial_mapper.AbstractInitialMapper):
|
|
|
189
191
|
return qubit_map
|
|
190
192
|
|
|
191
193
|
def _closest_unmapped_qubit(
|
|
192
|
-
self, source:
|
|
193
|
-
) ->
|
|
194
|
+
self, source: cirq.Qid, mapped_physicals: Set[cirq.Qid]
|
|
195
|
+
) -> cirq.Qid:
|
|
194
196
|
"""Finds the closest available neighbor to a physical qubit 'source' on the device.
|
|
195
197
|
|
|
196
198
|
Args:
|
|
@@ -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
|