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,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass that pushes 180° rotations around axes in the XY plane later in the circuit."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import cast, Dict, Iterable, Iterator, Optional, Tuple, TYPE_CHECKING, Union
|
|
18
20
|
|
|
19
21
|
import numpy as np
|
|
@@ -29,12 +31,12 @@ if TYPE_CHECKING:
|
|
|
29
31
|
|
|
30
32
|
@transformer_api.transformer(add_deep_support=True)
|
|
31
33
|
def eject_phased_paulis(
|
|
32
|
-
circuit:
|
|
34
|
+
circuit: cirq.AbstractCircuit,
|
|
33
35
|
*,
|
|
34
|
-
context: Optional[
|
|
36
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
35
37
|
atol: float = 1e-8,
|
|
36
38
|
eject_parameterized: bool = False,
|
|
37
|
-
) ->
|
|
39
|
+
) -> cirq.Circuit:
|
|
38
40
|
"""Transformer pass to push X, Y, PhasedX & (certain) PhasedXZ gates to the end of the circuit.
|
|
39
41
|
|
|
40
42
|
As the gates get pushed, they may absorb Z gates, cancel against other
|
|
@@ -60,7 +62,7 @@ def eject_phased_paulis(
|
|
|
60
62
|
held_w_phases: Dict[ops.Qid, value.TParamVal] = {}
|
|
61
63
|
tags_to_ignore = set(context.tags_to_ignore) if context else set()
|
|
62
64
|
|
|
63
|
-
def map_func(op:
|
|
65
|
+
def map_func(op: cirq.Operation, _: int) -> cirq.OP_TREE:
|
|
64
66
|
# Dump if `op` marked with a no compile tag.
|
|
65
67
|
if set(op.tags) & tags_to_ignore:
|
|
66
68
|
return [_dump_held(op.qubits, held_w_phases, atol), op]
|
|
@@ -107,7 +109,7 @@ def eject_phased_paulis(
|
|
|
107
109
|
|
|
108
110
|
def _absorb_z_into_w(
|
|
109
111
|
op: ops.Operation, held_w_phases: Dict[ops.Qid, value.TParamVal]
|
|
110
|
-
) ->
|
|
112
|
+
) -> cirq.OP_TREE:
|
|
111
113
|
"""Absorbs a Z^t gate into a W(a) flip.
|
|
112
114
|
|
|
113
115
|
[Where W(a) is shorthand for PhasedX(phase_exponent=a).]
|
|
@@ -128,7 +130,7 @@ def _absorb_z_into_w(
|
|
|
128
130
|
|
|
129
131
|
def _dump_held(
|
|
130
132
|
qubits: Iterable[ops.Qid], held_w_phases: Dict[ops.Qid, value.TParamVal], atol: float
|
|
131
|
-
) -> Iterator[
|
|
133
|
+
) -> Iterator[cirq.OP_TREE]:
|
|
132
134
|
# Note: sorting is to avoid non-determinism in the insertion order.
|
|
133
135
|
for q in sorted(qubits):
|
|
134
136
|
p = held_w_phases.get(q)
|
|
@@ -140,7 +142,7 @@ def _dump_held(
|
|
|
140
142
|
|
|
141
143
|
def _dump_into_measurement(
|
|
142
144
|
op: ops.Operation, held_w_phases: Dict[ops.Qid, value.TParamVal]
|
|
143
|
-
) ->
|
|
145
|
+
) -> cirq.OP_TREE:
|
|
144
146
|
measurement = cast(ops.MeasurementGate, cast(ops.GateOperation, op).gate)
|
|
145
147
|
new_measurement = measurement.with_bits_flipped(
|
|
146
148
|
*[i for i, q in enumerate(op.qubits) if q in held_w_phases]
|
|
@@ -152,7 +154,7 @@ def _dump_into_measurement(
|
|
|
152
154
|
|
|
153
155
|
def _potential_cross_whole_w(
|
|
154
156
|
op: ops.Operation, atol: float, held_w_phases: Dict[ops.Qid, value.TParamVal]
|
|
155
|
-
) ->
|
|
157
|
+
) -> cirq.OP_TREE:
|
|
156
158
|
"""Grabs or cancels a held W gate against an existing W gate.
|
|
157
159
|
|
|
158
160
|
[Where W(a) is shorthand for PhasedX(phase_exponent=a).]
|
|
@@ -185,7 +187,7 @@ def _potential_cross_whole_w(
|
|
|
185
187
|
|
|
186
188
|
def _potential_cross_partial_w(
|
|
187
189
|
op: ops.Operation, held_w_phases: Dict[ops.Qid, value.TParamVal], atol: float
|
|
188
|
-
) ->
|
|
190
|
+
) -> cirq.OP_TREE:
|
|
189
191
|
"""Cross the held W over a partial W gate.
|
|
190
192
|
|
|
191
193
|
[Where W(a) is shorthand for PhasedX(phase_exponent=a).]
|
|
@@ -210,7 +212,7 @@ def _potential_cross_partial_w(
|
|
|
210
212
|
return gate.on(op.qubits[0])
|
|
211
213
|
|
|
212
214
|
|
|
213
|
-
def _single_cross_over_cz(op: ops.Operation, qubit_with_w:
|
|
215
|
+
def _single_cross_over_cz(op: ops.Operation, qubit_with_w: cirq.Qid) -> cirq.OP_TREE:
|
|
214
216
|
"""Crosses exactly one W flip over a partial CZ.
|
|
215
217
|
|
|
216
218
|
[Where W(a) is shorthand for PhasedX(phase_exponent=a).]
|
|
@@ -251,7 +253,7 @@ def _single_cross_over_cz(op: ops.Operation, qubit_with_w: 'cirq.Qid') -> 'cirq.
|
|
|
251
253
|
|
|
252
254
|
def _double_cross_over_cz(
|
|
253
255
|
op: ops.Operation, held_w_phases: Dict[ops.Qid, value.TParamVal]
|
|
254
|
-
) ->
|
|
256
|
+
) -> cirq.OP_TREE:
|
|
255
257
|
"""Crosses two W flips over a partial CZ.
|
|
256
258
|
|
|
257
259
|
[Where W(a) is shorthand for PhasedX(phase_exponent=a).]
|
|
@@ -355,7 +357,7 @@ def _try_get_known_z_half_turns(
|
|
|
355
357
|
|
|
356
358
|
def _phased_x_or_pauli_gate(
|
|
357
359
|
exponent: Union[float, sympy.Expr], phase_exponent: Union[float, sympy.Expr], atol: float
|
|
358
|
-
) -> Union[
|
|
360
|
+
) -> Union[cirq.PhasedXPowGate, cirq.XPowGate, cirq.YPowGate]:
|
|
359
361
|
"""Return PhasedXPowGate or X or Y gate if equivalent within atol in z-axis turns."""
|
|
360
362
|
if not isinstance(phase_exponent, sympy.Expr) or phase_exponent.is_constant():
|
|
361
363
|
half_turns = value.canonicalize_half_turns(float(phase_exponent))
|
cirq/transformers/eject_z.py
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass that pushes Z gates later and later in the circuit."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from collections import defaultdict
|
|
18
20
|
from typing import Dict, Iterable, Iterator, Optional, Tuple, TYPE_CHECKING
|
|
19
21
|
|
|
@@ -31,7 +33,7 @@ def _is_integer(n):
|
|
|
31
33
|
return np.isclose(n, np.round(n))
|
|
32
34
|
|
|
33
35
|
|
|
34
|
-
def _is_swaplike(gate:
|
|
36
|
+
def _is_swaplike(gate: cirq.Gate):
|
|
35
37
|
if isinstance(gate, ops.SwapPowGate):
|
|
36
38
|
return gate.exponent == 1
|
|
37
39
|
|
|
@@ -46,12 +48,12 @@ def _is_swaplike(gate: 'cirq.Gate'):
|
|
|
46
48
|
|
|
47
49
|
@transformer_api.transformer(add_deep_support=True)
|
|
48
50
|
def eject_z(
|
|
49
|
-
circuit:
|
|
51
|
+
circuit: cirq.AbstractCircuit,
|
|
50
52
|
*,
|
|
51
|
-
context: Optional[
|
|
53
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
52
54
|
atol: float = 0.0,
|
|
53
55
|
eject_parameterized: bool = False,
|
|
54
|
-
) ->
|
|
56
|
+
) -> cirq.Circuit:
|
|
55
57
|
"""Pushes Z gates towards the end of the circuit.
|
|
56
58
|
|
|
57
59
|
As the Z gates get pushed they may absorb other Z gates, get absorbed into
|
|
@@ -77,7 +79,7 @@ def eject_z(
|
|
|
77
79
|
lambda: None
|
|
78
80
|
)
|
|
79
81
|
|
|
80
|
-
def dump_tracked_phase(qubits: Iterable[ops.Qid]) -> Iterator[
|
|
82
|
+
def dump_tracked_phase(qubits: Iterable[ops.Qid]) -> Iterator[cirq.OP_TREE]:
|
|
81
83
|
"""Zeroes qubit_phase entries by emitting Z gates."""
|
|
82
84
|
for q in qubits:
|
|
83
85
|
p, key = qubit_phase[q], last_phased_xz_op[q]
|
|
@@ -87,7 +89,7 @@ def eject_z(
|
|
|
87
89
|
elif key:
|
|
88
90
|
phased_xz_replacements[key] = phased_xz_replacements[key].with_z_exponent(p * 2)
|
|
89
91
|
|
|
90
|
-
def map_func(op:
|
|
92
|
+
def map_func(op: cirq.Operation, moment_index: int) -> cirq.OP_TREE:
|
|
91
93
|
last_phased_xz_op.update({q: None for q in op.qubits})
|
|
92
94
|
|
|
93
95
|
if tags_to_ignore & set(op.tags):
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass that expands composite operations via `cirq.decompose`."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Callable, Optional, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, ops, protocols
|
|
@@ -25,9 +27,9 @@ if TYPE_CHECKING:
|
|
|
25
27
|
|
|
26
28
|
@transformer_api.transformer
|
|
27
29
|
def expand_composite(
|
|
28
|
-
circuit:
|
|
30
|
+
circuit: cirq.AbstractCircuit,
|
|
29
31
|
*,
|
|
30
|
-
context: Optional[
|
|
32
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
31
33
|
no_decomp: Callable[[ops.Operation], bool] = (lambda _: False),
|
|
32
34
|
):
|
|
33
35
|
"""A transformer that expands composite operations via `cirq.decompose`.
|
|
@@ -48,7 +50,7 @@ def expand_composite(
|
|
|
48
50
|
Copy of the transformed input circuit.
|
|
49
51
|
"""
|
|
50
52
|
|
|
51
|
-
def map_func(op:
|
|
53
|
+
def map_func(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
52
54
|
if context and context.deep and isinstance(op.untagged, circuits.CircuitOperation):
|
|
53
55
|
return op
|
|
54
56
|
return protocols.decompose(op, keep=no_decomp, on_stuck_raise=None)
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"""A Gauge transformer for CZ**0.5 and CZ**-0.5 gates."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
18
20
|
from numbers import Real
|
|
19
21
|
from typing import Dict, Sequence, Tuple, TYPE_CHECKING
|
|
20
22
|
|
|
@@ -42,7 +44,7 @@ class SqrtCZGauge(Gauge):
|
|
|
42
44
|
def weight(self) -> float:
|
|
43
45
|
return 3.0
|
|
44
46
|
|
|
45
|
-
def sample(self, gate:
|
|
47
|
+
def sample(self, gate: cirq.Gate, prng: np.random.Generator) -> ConstantGauge:
|
|
46
48
|
if prng.choice([True, False]):
|
|
47
49
|
return ConstantGauge(two_qubit_gate=gate)
|
|
48
50
|
swap_qubits = prng.choice([True, False])
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Attempt to tabulate single qubit gates required to generate a target 2Q gate
|
|
16
16
|
with a product A k A."""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
17
20
|
from dataclasses import dataclass
|
|
18
21
|
from functools import reduce
|
|
19
22
|
from typing import List, NamedTuple, Sequence, Tuple
|
|
@@ -316,7 +319,7 @@ def two_qubit_gate_product_tabulation(
|
|
|
316
319
|
*,
|
|
317
320
|
sample_scaling: int = 50,
|
|
318
321
|
allow_missed_points: bool = True,
|
|
319
|
-
random_state:
|
|
322
|
+
random_state: cirq.RANDOM_STATE_OR_SEED_LIKE = None,
|
|
320
323
|
) -> TwoQubitGateTabulation:
|
|
321
324
|
r"""Generate a TwoQubitGateTabulation for a base two qubit unitary.
|
|
322
325
|
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer that sorts commuting operations in increasing order of their `.qubits` tuple."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Dict, List, Optional, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, protocols
|
|
@@ -25,8 +27,8 @@ if TYPE_CHECKING:
|
|
|
25
27
|
|
|
26
28
|
@transformer_api.transformer(add_deep_support=True)
|
|
27
29
|
def insertion_sort_transformer(
|
|
28
|
-
circuit:
|
|
29
|
-
) ->
|
|
30
|
+
circuit: cirq.AbstractCircuit, *, context: Optional[cirq.TransformerContext] = None
|
|
31
|
+
) -> cirq.Circuit:
|
|
30
32
|
"""Sorts the operations using their sorted `.qubits` property as comparison key.
|
|
31
33
|
|
|
32
34
|
Operations are swapped only if they commute.
|
|
@@ -35,8 +37,8 @@ def insertion_sort_transformer(
|
|
|
35
37
|
circuit: input circuit.
|
|
36
38
|
context: optional TransformerContext (not used),
|
|
37
39
|
"""
|
|
38
|
-
final_operations: List[
|
|
39
|
-
qubit_index: Dict[
|
|
40
|
+
final_operations: List[cirq.Operation] = []
|
|
41
|
+
qubit_index: Dict[cirq.Qid, int] = {
|
|
40
42
|
q: idx for idx, q in enumerate(sorted(circuit.all_qubits()))
|
|
41
43
|
}
|
|
42
44
|
cached_qubit_indices: Dict[int, List[int]] = {}
|
|
@@ -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 itertools
|
|
16
18
|
from collections import defaultdict
|
|
17
19
|
from typing import Any, cast, Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
|
|
@@ -33,7 +35,7 @@ class _MeasurementQid(ops.Qid):
|
|
|
33
35
|
Exactly one qubit will be created per qubit in the measurement gate.
|
|
34
36
|
"""
|
|
35
37
|
|
|
36
|
-
def __init__(self, key: Union[str,
|
|
38
|
+
def __init__(self, key: Union[str, cirq.MeasurementKey], qid: cirq.Qid, index: int = 0):
|
|
37
39
|
"""Initializes the qubit.
|
|
38
40
|
|
|
39
41
|
Args:
|
|
@@ -63,8 +65,8 @@ class _MeasurementQid(ops.Qid):
|
|
|
63
65
|
|
|
64
66
|
@transformer_api.transformer
|
|
65
67
|
def defer_measurements(
|
|
66
|
-
circuit:
|
|
67
|
-
) ->
|
|
68
|
+
circuit: cirq.AbstractCircuit, *, context: Optional[cirq.TransformerContext] = None
|
|
69
|
+
) -> cirq.Circuit:
|
|
68
70
|
"""Implements the Deferred Measurement Principle.
|
|
69
71
|
|
|
70
72
|
Uses the Deferred Measurement Principle to move all measurements to the
|
|
@@ -94,11 +96,9 @@ def defer_measurements(
|
|
|
94
96
|
|
|
95
97
|
circuit = transformer_primitives.unroll_circuit_op(circuit, deep=True, tags_to_check=None)
|
|
96
98
|
terminal_measurements = {op for _, op in find_terminal_measurements(circuit)}
|
|
97
|
-
measurement_qubits: Dict[
|
|
98
|
-
list
|
|
99
|
-
)
|
|
99
|
+
measurement_qubits: Dict[cirq.MeasurementKey, List[Tuple[cirq.Qid, ...]]] = defaultdict(list)
|
|
100
100
|
|
|
101
|
-
def defer(op:
|
|
101
|
+
def defer(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
102
102
|
if op in terminal_measurements:
|
|
103
103
|
return op
|
|
104
104
|
gate = op.gate
|
|
@@ -169,9 +169,9 @@ def defer_measurements(
|
|
|
169
169
|
|
|
170
170
|
|
|
171
171
|
def _all_possible_datastore_states(
|
|
172
|
-
keys: Iterable[Tuple[
|
|
173
|
-
measurement_qubits: Dict[
|
|
174
|
-
) -> Iterable[
|
|
172
|
+
keys: Iterable[Tuple[cirq.MeasurementKey, int]],
|
|
173
|
+
measurement_qubits: Dict[cirq.MeasurementKey, List[Tuple[cirq.Qid, ...]]],
|
|
174
|
+
) -> Iterable[cirq.ClassicalDataStoreReader]:
|
|
175
175
|
"""The cartesian product of all possible DataStore states for the given keys."""
|
|
176
176
|
# First we get the list of all possible values. So if we have a key mapped to qubits of shape
|
|
177
177
|
# (2, 2) and a key mapped to a qutrit, the possible measurement values are:
|
|
@@ -214,10 +214,10 @@ def _all_possible_datastore_states(
|
|
|
214
214
|
|
|
215
215
|
@transformer_api.transformer
|
|
216
216
|
def dephase_measurements(
|
|
217
|
-
circuit:
|
|
217
|
+
circuit: cirq.AbstractCircuit,
|
|
218
218
|
*,
|
|
219
|
-
context: Optional[
|
|
220
|
-
) ->
|
|
219
|
+
context: Optional[cirq.TransformerContext] = transformer_api.TransformerContext(deep=True),
|
|
220
|
+
) -> cirq.Circuit:
|
|
221
221
|
"""Changes all measurements to a dephase operation.
|
|
222
222
|
|
|
223
223
|
This transformer is useful when using a density matrix simulator, when
|
|
@@ -240,7 +240,7 @@ def dephase_measurements(
|
|
|
240
240
|
surprises.
|
|
241
241
|
"""
|
|
242
242
|
|
|
243
|
-
def dephase(op:
|
|
243
|
+
def dephase(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
244
244
|
gate = op.gate
|
|
245
245
|
if isinstance(gate, ops.MeasurementGate):
|
|
246
246
|
key = value.MeasurementKey.parse_serialized(gate.key)
|
|
@@ -257,10 +257,10 @@ def dephase_measurements(
|
|
|
257
257
|
|
|
258
258
|
@transformer_api.transformer
|
|
259
259
|
def drop_terminal_measurements(
|
|
260
|
-
circuit:
|
|
260
|
+
circuit: cirq.AbstractCircuit,
|
|
261
261
|
*,
|
|
262
|
-
context: Optional[
|
|
263
|
-
) ->
|
|
262
|
+
context: Optional[cirq.TransformerContext] = transformer_api.TransformerContext(deep=True),
|
|
263
|
+
) -> cirq.Circuit:
|
|
264
264
|
"""Removes terminal measurements from a circuit.
|
|
265
265
|
|
|
266
266
|
This transformer is helpful when trying to capture the final state vector
|
|
@@ -289,7 +289,7 @@ def drop_terminal_measurements(
|
|
|
289
289
|
if not circuit.are_all_measurements_terminal():
|
|
290
290
|
raise ValueError('Circuit contains a non-terminal measurement.')
|
|
291
291
|
|
|
292
|
-
def flip_inversion(op:
|
|
292
|
+
def flip_inversion(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
293
293
|
if isinstance(op.gate, ops.MeasurementGate):
|
|
294
294
|
return [
|
|
295
295
|
(
|
|
@@ -432,7 +432,7 @@ class _ConfusionChannel(ops.Gate):
|
|
|
432
432
|
def _kraus_(self) -> Tuple[np.ndarray, ...]:
|
|
433
433
|
return self._kraus
|
|
434
434
|
|
|
435
|
-
def _apply_channel_(self, args:
|
|
435
|
+
def _apply_channel_(self, args: cirq.ApplyChannelArgs):
|
|
436
436
|
configs: List[transformations._BuildFromSlicesArgs] = []
|
|
437
437
|
for i in range(np.prod(self._shape) ** 2):
|
|
438
438
|
scale = cast(complex, self._confusion_map.flat[i])
|
|
@@ -472,7 +472,7 @@ class _ModAdd(ops.ArithmeticGate):
|
|
|
472
472
|
def registers(self) -> Tuple[Tuple[int], Tuple[int]]:
|
|
473
473
|
return (self._dimension,), (self._dimension,)
|
|
474
474
|
|
|
475
|
-
def with_registers(self, *new_registers) ->
|
|
475
|
+
def with_registers(self, *new_registers) -> _ModAdd:
|
|
476
476
|
raise NotImplementedError()
|
|
477
477
|
|
|
478
478
|
def apply(self, *register_values: int) -> Tuple[int, int]:
|
|
@@ -482,7 +482,7 @@ class _ModAdd(ops.ArithmeticGate):
|
|
|
482
482
|
return self._dimension
|
|
483
483
|
|
|
484
484
|
|
|
485
|
-
def _mod_add(source:
|
|
485
|
+
def _mod_add(source: cirq.Qid, target: cirq.Qid) -> cirq.Operation:
|
|
486
486
|
assert source.dimension == target.dimension
|
|
487
487
|
if source.dimension == 2:
|
|
488
488
|
# Use a CX gate in 2D case for simplicity.
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass to merge connected components of k-qubit unitary operations."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Callable, cast, Optional, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, ops, protocols
|
|
@@ -24,16 +26,16 @@ if TYPE_CHECKING:
|
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
def _rewrite_merged_k_qubit_unitaries(
|
|
27
|
-
circuit:
|
|
29
|
+
circuit: cirq.AbstractCircuit,
|
|
28
30
|
*,
|
|
29
|
-
context: Optional[
|
|
31
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
30
32
|
k: int = 0,
|
|
31
|
-
rewriter: Optional[Callable[[
|
|
33
|
+
rewriter: Optional[Callable[[cirq.CircuitOperation], cirq.OP_TREE]] = None,
|
|
32
34
|
merged_circuit_op_tag: str = "_merged_k_qubit_unitaries_component",
|
|
33
|
-
) ->
|
|
35
|
+
) -> cirq.Circuit:
|
|
34
36
|
deep = context.deep if context else False
|
|
35
37
|
|
|
36
|
-
def map_func(op:
|
|
38
|
+
def map_func(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
37
39
|
op_untagged = op.untagged
|
|
38
40
|
if (
|
|
39
41
|
deep
|
|
@@ -66,12 +68,12 @@ def _rewrite_merged_k_qubit_unitaries(
|
|
|
66
68
|
|
|
67
69
|
@transformer_api.transformer
|
|
68
70
|
def merge_k_qubit_unitaries(
|
|
69
|
-
circuit:
|
|
71
|
+
circuit: cirq.AbstractCircuit,
|
|
70
72
|
*,
|
|
71
|
-
context: Optional[
|
|
73
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
72
74
|
k: int = 0,
|
|
73
|
-
rewriter: Optional[Callable[[
|
|
74
|
-
) ->
|
|
75
|
+
rewriter: Optional[Callable[[cirq.CircuitOperation], cirq.OP_TREE]] = None,
|
|
76
|
+
) -> cirq.Circuit:
|
|
75
77
|
"""Merges connected components of unitary operations, acting on <= k qubits.
|
|
76
78
|
|
|
77
79
|
Uses rewriter to convert a connected component of unitary operations acting on <= k-qubits
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
# pylint: skip-file
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import List
|
|
18
20
|
|
|
19
21
|
import numpy as np
|
|
@@ -133,7 +135,7 @@ a: ═════════════════════════
|
|
|
133
135
|
)
|
|
134
136
|
component_id = 0
|
|
135
137
|
|
|
136
|
-
def rewriter_merge_to_circuit_op(op:
|
|
138
|
+
def rewriter_merge_to_circuit_op(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
137
139
|
nonlocal component_id
|
|
138
140
|
component_id = component_id + 1
|
|
139
141
|
return op.with_tags(f'{component_id}')
|
|
@@ -160,7 +162,7 @@ a: ═════════════════════════
|
|
|
160
162
|
|
|
161
163
|
component_id = 0
|
|
162
164
|
|
|
163
|
-
def rewriter_replace_with_decomp(op:
|
|
165
|
+
def rewriter_replace_with_decomp(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
164
166
|
nonlocal component_id
|
|
165
167
|
component_id = component_id + 1
|
|
166
168
|
tag = f'{component_id}'
|
|
@@ -220,7 +222,7 @@ def test_merge_k_qubit_unitaries_deep():
|
|
|
220
222
|
|
|
221
223
|
component_id = 0
|
|
222
224
|
|
|
223
|
-
def rewriter_merge_to_circuit_op(op:
|
|
225
|
+
def rewriter_merge_to_circuit_op(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
224
226
|
nonlocal component_id
|
|
225
227
|
component_id = component_id + 1
|
|
226
228
|
return op.with_tags(f'{component_id}')
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer passes to combine adjacent single-qubit rotations."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Optional, TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, ops, protocols
|
|
@@ -26,11 +28,11 @@ if TYPE_CHECKING:
|
|
|
26
28
|
|
|
27
29
|
@transformer_api.transformer
|
|
28
30
|
def merge_single_qubit_gates_to_phased_x_and_z(
|
|
29
|
-
circuit:
|
|
31
|
+
circuit: cirq.AbstractCircuit,
|
|
30
32
|
*,
|
|
31
|
-
context: Optional[
|
|
33
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
32
34
|
atol: float = 1e-8,
|
|
33
|
-
) ->
|
|
35
|
+
) -> cirq.Circuit:
|
|
34
36
|
"""Replaces runs of single qubit rotations with `cirq.PhasedXPowGate` and `cirq.ZPowGate`.
|
|
35
37
|
|
|
36
38
|
Specifically, any run of non-parameterized single-qubit unitaries will be replaced by an
|
|
@@ -46,7 +48,7 @@ def merge_single_qubit_gates_to_phased_x_and_z(
|
|
|
46
48
|
Copy of the transformed input circuit.
|
|
47
49
|
"""
|
|
48
50
|
|
|
49
|
-
def rewriter(op:
|
|
51
|
+
def rewriter(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
50
52
|
u = protocols.unitary(op)
|
|
51
53
|
if protocols.num_qubits(op) == 0:
|
|
52
54
|
return ops.GlobalPhaseGate(u[0, 0]).on()
|
|
@@ -62,11 +64,11 @@ def merge_single_qubit_gates_to_phased_x_and_z(
|
|
|
62
64
|
|
|
63
65
|
@transformer_api.transformer
|
|
64
66
|
def merge_single_qubit_gates_to_phxz(
|
|
65
|
-
circuit:
|
|
67
|
+
circuit: cirq.AbstractCircuit,
|
|
66
68
|
*,
|
|
67
|
-
context: Optional[
|
|
69
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
68
70
|
atol: float = 1e-8,
|
|
69
|
-
) ->
|
|
71
|
+
) -> cirq.Circuit:
|
|
70
72
|
"""Replaces runs of single qubit rotations with a single optional `cirq.PhasedXZGate`.
|
|
71
73
|
|
|
72
74
|
Specifically, any run of non-parameterized single-qubit unitaries will be replaced by an
|
|
@@ -82,7 +84,7 @@ def merge_single_qubit_gates_to_phxz(
|
|
|
82
84
|
Copy of the transformed input circuit.
|
|
83
85
|
"""
|
|
84
86
|
|
|
85
|
-
def rewriter(op:
|
|
87
|
+
def rewriter(op: cirq.CircuitOperation) -> cirq.OP_TREE:
|
|
86
88
|
u = protocols.unitary(op)
|
|
87
89
|
if protocols.num_qubits(op) == 0:
|
|
88
90
|
return ops.GlobalPhaseGate(u[0, 0]).on()
|
|
@@ -96,11 +98,11 @@ def merge_single_qubit_gates_to_phxz(
|
|
|
96
98
|
|
|
97
99
|
@transformer_api.transformer
|
|
98
100
|
def merge_single_qubit_moments_to_phxz(
|
|
99
|
-
circuit:
|
|
101
|
+
circuit: cirq.AbstractCircuit,
|
|
100
102
|
*,
|
|
101
|
-
context: Optional[
|
|
103
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
102
104
|
atol: float = 1e-8,
|
|
103
|
-
) ->
|
|
105
|
+
) -> cirq.Circuit:
|
|
104
106
|
"""Merges adjacent moments with only 1-qubit rotations to a single moment with PhasedXZ gates.
|
|
105
107
|
|
|
106
108
|
Args:
|
|
@@ -114,7 +116,7 @@ def merge_single_qubit_moments_to_phxz(
|
|
|
114
116
|
"""
|
|
115
117
|
tags_to_ignore = set(context.tags_to_ignore) if context else set()
|
|
116
118
|
|
|
117
|
-
def can_merge_moment(m:
|
|
119
|
+
def can_merge_moment(m: cirq.Moment):
|
|
118
120
|
return all(
|
|
119
121
|
protocols.num_qubits(op) == 1
|
|
120
122
|
and protocols.has_unitary(op)
|
|
@@ -122,7 +124,7 @@ def merge_single_qubit_moments_to_phxz(
|
|
|
122
124
|
for op in m
|
|
123
125
|
)
|
|
124
126
|
|
|
125
|
-
def merge_func(m1:
|
|
127
|
+
def merge_func(m1: cirq.Moment, m2: cirq.Moment) -> Optional[cirq.Moment]:
|
|
126
128
|
if not (can_merge_moment(m1) and can_merge_moment(m2)):
|
|
127
129
|
return None
|
|
128
130
|
ret_ops = []
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformers to rewrite a circuit using gates from a given target gateset."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
from typing import Callable, Hashable, Optional, Sequence, TYPE_CHECKING, Union
|
|
18
20
|
|
|
19
21
|
from cirq import circuits
|
|
@@ -24,8 +26,8 @@ if TYPE_CHECKING:
|
|
|
24
26
|
import cirq
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
def _create_on_stuck_raise_error(gateset:
|
|
28
|
-
def _value_error_describing_bad_operation(op:
|
|
29
|
+
def _create_on_stuck_raise_error(gateset: cirq.Gateset):
|
|
30
|
+
def _value_error_describing_bad_operation(op: cirq.Operation) -> ValueError:
|
|
29
31
|
return ValueError(f"Unable to convert {op} to target gateset {gateset!r}")
|
|
30
32
|
|
|
31
33
|
return _value_error_describing_bad_operation
|
|
@@ -33,14 +35,14 @@ def _create_on_stuck_raise_error(gateset: 'cirq.Gateset'):
|
|
|
33
35
|
|
|
34
36
|
@transformer_api.transformer
|
|
35
37
|
def _decompose_operations_to_target_gateset(
|
|
36
|
-
circuit:
|
|
38
|
+
circuit: cirq.AbstractCircuit,
|
|
37
39
|
*,
|
|
38
|
-
context: Optional[
|
|
39
|
-
gateset: Optional[
|
|
40
|
-
decomposer: Callable[[
|
|
40
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
41
|
+
gateset: Optional[cirq.Gateset] = None,
|
|
42
|
+
decomposer: Callable[[cirq.Operation, int], dp.DecomposeResult] = lambda *_: NotImplemented,
|
|
41
43
|
ignore_failures: bool = True,
|
|
42
44
|
tags_to_decompose: Sequence[Hashable] = (),
|
|
43
|
-
) ->
|
|
45
|
+
) -> cirq.Circuit:
|
|
44
46
|
"""Decomposes every operation to `gateset` using `cirq.decompose` and `decomposer`.
|
|
45
47
|
|
|
46
48
|
This transformer attempts to decompose every operation `op` in the given circuit to `gateset`
|
|
@@ -68,7 +70,7 @@ def _decompose_operations_to_target_gateset(
|
|
|
68
70
|
ValueError: If any input operation fails to convert and `ignore_failures` is False.
|
|
69
71
|
"""
|
|
70
72
|
|
|
71
|
-
def map_func(op:
|
|
73
|
+
def map_func(op: cirq.Operation, moment_index: int):
|
|
72
74
|
if (
|
|
73
75
|
context
|
|
74
76
|
and context.deep
|
|
@@ -97,13 +99,13 @@ def _decompose_operations_to_target_gateset(
|
|
|
97
99
|
|
|
98
100
|
@transformer_api.transformer
|
|
99
101
|
def optimize_for_target_gateset(
|
|
100
|
-
circuit:
|
|
102
|
+
circuit: cirq.AbstractCircuit,
|
|
101
103
|
*,
|
|
102
|
-
context: Optional[
|
|
103
|
-
gateset: Optional[
|
|
104
|
+
context: Optional[cirq.TransformerContext] = None,
|
|
105
|
+
gateset: Optional[cirq.CompilationTargetGateset] = None,
|
|
104
106
|
ignore_failures: bool = True,
|
|
105
107
|
max_num_passes: Union[int, None] = 1,
|
|
106
|
-
) ->
|
|
108
|
+
) -> cirq.Circuit:
|
|
107
109
|
"""Transforms the given circuit into an equivalent circuit using gates accepted by `gateset`.
|
|
108
110
|
|
|
109
111
|
Repeat max_num_passes times or when `max_num_passes=None` until no further changes can be done
|
|
@@ -12,14 +12,18 @@
|
|
|
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 TYPE_CHECKING, Union
|
|
16
18
|
|
|
17
19
|
import pytest
|
|
18
20
|
|
|
19
21
|
import cirq
|
|
20
|
-
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
21
22
|
from cirq.transformers.optimize_for_target_gateset import _decompose_operations_to_target_gateset
|
|
22
23
|
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
26
|
+
|
|
23
27
|
|
|
24
28
|
def test_decompose_operations_raises_on_stuck():
|
|
25
29
|
c_orig = cirq.Circuit(cirq.X(cirq.NamedQubit("q")).with_tags("ignore"))
|
|
@@ -121,7 +125,7 @@ class MatrixGateTargetGateset(cirq.CompilationTargetGateset):
|
|
|
121
125
|
def num_qubits(self) -> int:
|
|
122
126
|
return 2
|
|
123
127
|
|
|
124
|
-
def decompose_to_target_gateset(self, op:
|
|
128
|
+
def decompose_to_target_gateset(self, op: cirq.Operation, _) -> DecomposeResult:
|
|
125
129
|
if cirq.num_qubits(op) != 2 or not cirq.has_unitary(op):
|
|
126
130
|
return NotImplemented
|
|
127
131
|
return cirq.MatrixGate(cirq.unitary(op), name="M").on(*op.qubits)
|