cirq-core 1.6.0.dev20250501172111__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.dev20250501172111.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250501172111.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/RECORD +57 -57
- {cirq_core-1.6.0.dev20250501172111.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250501172111.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250501172111.dist-info → cirq_core-1.6.0.dev20250501192724.dist-info}/top_level.txt +0 -0
|
@@ -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],
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Defines the API for circuit transformers in Cirq."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
import dataclasses
|
|
18
20
|
import enum
|
|
19
21
|
import functools
|
|
@@ -83,8 +85,8 @@ class _LoggerNode:
|
|
|
83
85
|
|
|
84
86
|
transformer_id: int
|
|
85
87
|
transformer_name: str
|
|
86
|
-
initial_circuit:
|
|
87
|
-
final_circuit:
|
|
88
|
+
initial_circuit: cirq.AbstractCircuit
|
|
89
|
+
final_circuit: cirq.AbstractCircuit
|
|
88
90
|
logs: List[Tuple[LogLevel, Tuple[str, ...]]] = dataclasses.field(default_factory=list)
|
|
89
91
|
nested_loggers: List[int] = dataclasses.field(default_factory=list)
|
|
90
92
|
|
|
@@ -116,7 +118,7 @@ class TransformerLogger:
|
|
|
116
118
|
self._logs: List[_LoggerNode] = []
|
|
117
119
|
self._stack: List[int] = []
|
|
118
120
|
|
|
119
|
-
def register_initial(self, circuit:
|
|
121
|
+
def register_initial(self, circuit: cirq.AbstractCircuit, transformer_name: str) -> None:
|
|
120
122
|
"""Register the beginning of a new transformer stage.
|
|
121
123
|
|
|
122
124
|
Args:
|
|
@@ -143,7 +145,7 @@ class TransformerLogger:
|
|
|
143
145
|
raise ValueError('No active transformer found.')
|
|
144
146
|
self._logs[self._stack[-1]].logs.append((level, args))
|
|
145
147
|
|
|
146
|
-
def register_final(self, circuit:
|
|
148
|
+
def register_final(self, circuit: cirq.AbstractCircuit, transformer_name: str) -> None:
|
|
147
149
|
"""Register the end of the currently active transformer stage.
|
|
148
150
|
|
|
149
151
|
Args:
|
|
@@ -195,13 +197,13 @@ class TransformerLogger:
|
|
|
195
197
|
class NoOpTransformerLogger(TransformerLogger):
|
|
196
198
|
"""All calls to this logger are a no-op"""
|
|
197
199
|
|
|
198
|
-
def register_initial(self, circuit:
|
|
200
|
+
def register_initial(self, circuit: cirq.AbstractCircuit, transformer_name: str) -> None:
|
|
199
201
|
pass
|
|
200
202
|
|
|
201
203
|
def log(self, *args: str, level: LogLevel = LogLevel.INFO) -> None:
|
|
202
204
|
pass
|
|
203
205
|
|
|
204
|
-
def register_final(self, circuit:
|
|
206
|
+
def register_final(self, circuit: cirq.AbstractCircuit, transformer_name: str) -> None:
|
|
205
207
|
pass
|
|
206
208
|
|
|
207
209
|
def show(self, level: LogLevel = LogLevel.INFO) -> None:
|
|
@@ -262,8 +264,8 @@ class TRANSFORMER(Protocol):
|
|
|
262
264
|
"""
|
|
263
265
|
|
|
264
266
|
def __call__(
|
|
265
|
-
self, circuit:
|
|
266
|
-
) ->
|
|
267
|
+
self, circuit: cirq.AbstractCircuit, *, context: Optional[TransformerContext] = None
|
|
268
|
+
) -> cirq.AbstractCircuit: ...
|
|
267
269
|
|
|
268
270
|
|
|
269
271
|
_TRANSFORMER_T = TypeVar('_TRANSFORMER_T', bound=TRANSFORMER)
|
|
@@ -357,8 +359,8 @@ def transformer(cls_or_func: Any = None, *, add_deep_support: bool = False) -> A
|
|
|
357
359
|
|
|
358
360
|
@functools.wraps(method)
|
|
359
361
|
def method_with_logging(
|
|
360
|
-
self, circuit:
|
|
361
|
-
) ->
|
|
362
|
+
self, circuit: cirq.AbstractCircuit, **kwargs
|
|
363
|
+
) -> cirq.AbstractCircuit:
|
|
362
364
|
return _transform_and_log(
|
|
363
365
|
add_deep_support,
|
|
364
366
|
lambda circuit, **kwargs: method(self, circuit, **kwargs),
|
|
@@ -376,7 +378,7 @@ def transformer(cls_or_func: Any = None, *, add_deep_support: bool = False) -> A
|
|
|
376
378
|
default_context = _get_default_context(func)
|
|
377
379
|
|
|
378
380
|
@functools.wraps(func)
|
|
379
|
-
def func_with_logging(circuit:
|
|
381
|
+
def func_with_logging(circuit: cirq.AbstractCircuit, **kwargs) -> cirq.AbstractCircuit:
|
|
380
382
|
return _transform_and_log(
|
|
381
383
|
add_deep_support,
|
|
382
384
|
func,
|
|
@@ -401,10 +403,10 @@ def _get_default_context(func: TRANSFORMER) -> TransformerContext:
|
|
|
401
403
|
def _run_transformer_on_circuit(
|
|
402
404
|
add_deep_support: bool,
|
|
403
405
|
func: TRANSFORMER,
|
|
404
|
-
circuit:
|
|
406
|
+
circuit: cirq.AbstractCircuit,
|
|
405
407
|
extracted_context: Optional[TransformerContext],
|
|
406
408
|
**kwargs,
|
|
407
|
-
) ->
|
|
409
|
+
) -> cirq.AbstractCircuit:
|
|
408
410
|
mutable_circuit = None
|
|
409
411
|
if extracted_context and extracted_context.deep and add_deep_support:
|
|
410
412
|
batch_replace = []
|
|
@@ -429,10 +431,10 @@ def _transform_and_log(
|
|
|
429
431
|
add_deep_support: bool,
|
|
430
432
|
func: TRANSFORMER,
|
|
431
433
|
transformer_name: str,
|
|
432
|
-
circuit:
|
|
434
|
+
circuit: cirq.AbstractCircuit,
|
|
433
435
|
extracted_context: Optional[TransformerContext],
|
|
434
436
|
**kwargs,
|
|
435
|
-
) ->
|
|
437
|
+
) -> cirq.AbstractCircuit:
|
|
436
438
|
"""Helper to log initial and final circuits before and after calling the transformer."""
|
|
437
439
|
if extracted_context:
|
|
438
440
|
extracted_context.logger.register_initial(circuit, transformer_name)
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Defines primitives for common transformer patterns."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
import bisect
|
|
18
20
|
import dataclasses
|
|
19
21
|
from collections import defaultdict
|
|
@@ -157,7 +159,7 @@ def _map_operations_impl(
|
|
|
157
159
|
"""
|
|
158
160
|
tags_to_ignore_set = set(tags_to_ignore)
|
|
159
161
|
|
|
160
|
-
def apply_map_func(op:
|
|
162
|
+
def apply_map_func(op: cirq.Operation, idx: int) -> List[cirq.Operation]:
|
|
161
163
|
if tags_to_ignore_set.intersection(op.tags):
|
|
162
164
|
return [op]
|
|
163
165
|
if deep and isinstance(op.untagged, circuits.CircuitOperation):
|
|
@@ -173,7 +175,7 @@ def _map_operations_impl(
|
|
|
173
175
|
).with_tags(*op.tags)
|
|
174
176
|
mapped_ops = [*ops.flatten_to_ops(map_func(op, idx))]
|
|
175
177
|
op_qubits = set(op.qubits)
|
|
176
|
-
mapped_ops_qubits: Set[
|
|
178
|
+
mapped_ops_qubits: Set[cirq.Qid] = set()
|
|
177
179
|
has_overlapping_ops = False
|
|
178
180
|
for mapped_op in mapped_ops:
|
|
179
181
|
if raise_if_add_qubits and not op_qubits.issuperset(mapped_op.qubits):
|
|
@@ -194,9 +196,9 @@ def _map_operations_impl(
|
|
|
194
196
|
]
|
|
195
197
|
return mapped_ops
|
|
196
198
|
|
|
197
|
-
new_moments: List[List[
|
|
199
|
+
new_moments: List[List[cirq.Operation]] = []
|
|
198
200
|
for idx, moment in enumerate(circuit):
|
|
199
|
-
curr_moments: List[List[
|
|
201
|
+
curr_moments: List[List[cirq.Operation]] = [[]] if wrap_in_circuit_op else []
|
|
200
202
|
placement_cache = circuits.circuit._PlacementCache()
|
|
201
203
|
for op in moment:
|
|
202
204
|
mapped_ops = apply_map_func(op, idx)
|
|
@@ -305,21 +307,21 @@ class _MergedCircuit:
|
|
|
305
307
|
of a set to store operations to preserve insertion order.
|
|
306
308
|
"""
|
|
307
309
|
|
|
308
|
-
qubit_indexes: Dict[
|
|
310
|
+
qubit_indexes: Dict[cirq.Qid, List[int]] = dataclasses.field(
|
|
309
311
|
default_factory=lambda: defaultdict(lambda: [-1])
|
|
310
312
|
)
|
|
311
|
-
mkey_indexes: Dict[
|
|
313
|
+
mkey_indexes: Dict[cirq.MeasurementKey, List[int]] = dataclasses.field(
|
|
312
314
|
default_factory=lambda: defaultdict(lambda: [-1])
|
|
313
315
|
)
|
|
314
|
-
ckey_indexes: Dict[
|
|
316
|
+
ckey_indexes: Dict[cirq.MeasurementKey, List[int]] = dataclasses.field(
|
|
315
317
|
default_factory=lambda: defaultdict(lambda: [-1])
|
|
316
318
|
)
|
|
317
|
-
ops_by_index: List[Dict[
|
|
319
|
+
ops_by_index: List[Dict[cirq.Operation, int]] = dataclasses.field(default_factory=list)
|
|
318
320
|
|
|
319
321
|
def append_empty_moment(self) -> None:
|
|
320
322
|
self.ops_by_index.append({})
|
|
321
323
|
|
|
322
|
-
def add_op_to_moment(self, moment_index: int, op:
|
|
324
|
+
def add_op_to_moment(self, moment_index: int, op: cirq.Operation) -> None:
|
|
323
325
|
self.ops_by_index[moment_index][op] = 0
|
|
324
326
|
for q in op.qubits:
|
|
325
327
|
if moment_index > self.qubit_indexes[q][-1]:
|
|
@@ -331,7 +333,7 @@ class _MergedCircuit:
|
|
|
331
333
|
for ckey in protocols.control_keys(op):
|
|
332
334
|
bisect.insort(self.ckey_indexes[ckey], moment_index)
|
|
333
335
|
|
|
334
|
-
def remove_op_from_moment(self, moment_index: int, op:
|
|
336
|
+
def remove_op_from_moment(self, moment_index: int, op: cirq.Operation) -> None:
|
|
335
337
|
self.ops_by_index[moment_index].pop(op)
|
|
336
338
|
for q in op.qubits:
|
|
337
339
|
if self.qubit_indexes[q][-1] == moment_index:
|
|
@@ -344,8 +346,8 @@ class _MergedCircuit:
|
|
|
344
346
|
self.ckey_indexes[ckey].remove(moment_index)
|
|
345
347
|
|
|
346
348
|
def get_mergeable_ops(
|
|
347
|
-
self, op:
|
|
348
|
-
) -> Tuple[int, List[
|
|
349
|
+
self, op: cirq.Operation, op_qs: Set[cirq.Qid]
|
|
350
|
+
) -> Tuple[int, List[cirq.Operation]]:
|
|
349
351
|
# Find the index of previous moment which can be merged with `op`.
|
|
350
352
|
idx = max([self.qubit_indexes[q][-1] for q in op_qs], default=-1)
|
|
351
353
|
idx = max([idx] + [self.mkey_indexes[ckey][-1] for ckey in protocols.control_keys(op)])
|
|
@@ -360,7 +362,7 @@ class _MergedCircuit:
|
|
|
360
362
|
left_op for left_op in self.ops_by_index[idx] if not op_qs.isdisjoint(left_op.qubits)
|
|
361
363
|
]
|
|
362
364
|
|
|
363
|
-
def get_cirq_circuit(self) ->
|
|
365
|
+
def get_cirq_circuit(self) -> cirq.Circuit:
|
|
364
366
|
return circuits.Circuit(circuits.Moment(m.keys()) for m in self.ops_by_index)
|
|
365
367
|
|
|
366
368
|
|
|
@@ -493,7 +495,7 @@ def merge_operations(
|
|
|
493
495
|
|
|
494
496
|
def merge_operations_to_circuit_op(
|
|
495
497
|
circuit: CIRCUIT_TYPE,
|
|
496
|
-
can_merge: Callable[[Sequence[
|
|
498
|
+
can_merge: Callable[[Sequence[cirq.Operation], Sequence[cirq.Operation]], bool],
|
|
497
499
|
*,
|
|
498
500
|
tags_to_ignore: Sequence[Hashable] = (),
|
|
499
501
|
merged_circuit_op_tag: str = "Merged connected component",
|
|
@@ -524,8 +526,8 @@ def merge_operations_to_circuit_op(
|
|
|
524
526
|
Copy of input circuit with valid connected components wrapped in tagged circuit operations.
|
|
525
527
|
"""
|
|
526
528
|
|
|
527
|
-
def merge_func(op1:
|
|
528
|
-
def get_ops(op:
|
|
529
|
+
def merge_func(op1: cirq.Operation, op2: cirq.Operation) -> Optional[cirq.Operation]:
|
|
530
|
+
def get_ops(op: cirq.Operation):
|
|
529
531
|
op_untagged = op.untagged
|
|
530
532
|
return (
|
|
531
533
|
[*op_untagged.circuit.all_operations()]
|
|
@@ -573,7 +575,7 @@ def merge_k_qubit_unitaries_to_circuit_op(
|
|
|
573
575
|
Copy of input circuit with valid connected components wrapped in tagged circuit operations.
|
|
574
576
|
"""
|
|
575
577
|
|
|
576
|
-
def can_merge(ops1: Sequence[
|
|
578
|
+
def can_merge(ops1: Sequence[cirq.Operation], ops2: Sequence[cirq.Operation]) -> bool:
|
|
577
579
|
return all(
|
|
578
580
|
protocols.num_qubits(op) <= k and protocols.has_unitary(op)
|
|
579
581
|
for op_list in [ops1, ops2]
|
|
@@ -659,7 +661,7 @@ def unroll_circuit_op(
|
|
|
659
661
|
"""
|
|
660
662
|
|
|
661
663
|
def map_func(m: circuits.Moment, _: int):
|
|
662
|
-
to_zip: List[
|
|
664
|
+
to_zip: List[cirq.AbstractCircuit] = []
|
|
663
665
|
for op in m:
|
|
664
666
|
op_untagged = op.untagged
|
|
665
667
|
if isinstance(op_untagged, circuits.CircuitOperation):
|
|
@@ -751,7 +753,7 @@ def unroll_circuit_op_greedy_frontier(
|
|
|
751
753
|
Copy of input circuit with (Tagged) CircuitOperation's expanded inline at qubit frontier.
|
|
752
754
|
"""
|
|
753
755
|
unrolled_circuit = circuit.unfreeze(copy=True)
|
|
754
|
-
frontier: Dict[
|
|
756
|
+
frontier: Dict[cirq.Qid, int] = defaultdict(lambda: 0)
|
|
755
757
|
idx = 0
|
|
756
758
|
while idx < len(unrolled_circuit):
|
|
757
759
|
for op in unrolled_circuit[idx].operations:
|
|
@@ -799,7 +801,7 @@ def toggle_tags(circuit: CIRCUIT_TYPE, tags: Sequence[Hashable], *, deep: bool =
|
|
|
799
801
|
"""
|
|
800
802
|
tags_to_xor = set(tags)
|
|
801
803
|
|
|
802
|
-
def map_func(op:
|
|
804
|
+
def map_func(op: cirq.Operation, _) -> cirq.Operation:
|
|
803
805
|
return (
|
|
804
806
|
op
|
|
805
807
|
if deep and isinstance(op, circuits.CircuitOperation)
|
|
@@ -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 Iterator, List, Optional
|
|
16
18
|
|
|
17
19
|
import pytest
|
|
@@ -721,7 +723,7 @@ def test_merge_operations_to_circuit_op_merges_connected_component():
|
|
|
721
723
|
''',
|
|
722
724
|
)
|
|
723
725
|
|
|
724
|
-
def can_merge(ops1: List[
|
|
726
|
+
def can_merge(ops1: List[cirq.Operation], ops2: List[cirq.Operation]) -> bool:
|
|
725
727
|
"""Artificial example where a CZ will absorb any merge-able operation."""
|
|
726
728
|
return any(o.gate == cirq.CZ for op_list in [ops1, ops2] for o in op_list)
|
|
727
729
|
|