cirq-core 1.5.0.dev20250403170622__py3-none-any.whl → 1.5.0.dev20250404021339__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/circuits/circuit.py +144 -147
- cirq/circuits/circuit_operation.py +37 -34
- cirq/circuits/circuit_operation_test.py +1 -1
- cirq/circuits/circuit_test.py +4 -6
- cirq/circuits/frozen_circuit.py +30 -26
- cirq/circuits/moment.py +37 -37
- cirq/circuits/optimization_pass.py +11 -11
- cirq/circuits/optimization_pass_test.py +6 -8
- cirq/circuits/qasm_output.py +13 -11
- cirq/circuits/text_diagram_drawer.py +9 -7
- cirq/contrib/acquaintance/bipartite.py +7 -5
- cirq/contrib/acquaintance/devices.py +3 -1
- cirq/contrib/acquaintance/executor.py +14 -16
- cirq/contrib/acquaintance/gates.py +19 -21
- cirq/contrib/acquaintance/inspection_utils.py +8 -6
- cirq/contrib/acquaintance/mutation_utils.py +8 -6
- cirq/contrib/acquaintance/optimizers.py +5 -3
- cirq/contrib/acquaintance/permutation.py +19 -19
- cirq/contrib/acquaintance/shift.py +5 -3
- cirq/contrib/acquaintance/shift_swap_network.py +5 -3
- cirq/contrib/acquaintance/strategies/complete.py +4 -2
- cirq/contrib/acquaintance/strategies/cubic.py +4 -2
- cirq/contrib/acquaintance/strategies/quartic_paired.py +8 -6
- cirq/contrib/acquaintance/topological_sort.py +4 -2
- cirq/contrib/bayesian_network/bayesian_network_gate.py +4 -2
- cirq/contrib/circuitdag/circuit_dag.py +18 -16
- cirq/contrib/custom_simulators/custom_state_simulator.py +10 -8
- cirq/contrib/custom_simulators/custom_state_simulator_test.py +9 -7
- cirq/contrib/graph_device/graph_device.py +4 -2
- cirq/contrib/noise_models/noise_models.py +7 -5
- cirq/contrib/paulistring/clifford_target_gateset.py +11 -9
- cirq/contrib/qcircuit/qcircuit_diagram.py +5 -2
- cirq/contrib/quantum_volume/quantum_volume.py +4 -4
- cirq/contrib/quimb/mps_simulator.py +25 -26
- cirq/contrib/routing/greedy.py +5 -3
- cirq/contrib/routing/initialization.py +3 -1
- cirq/contrib/routing/swap_network.py +5 -5
- cirq/contrib/routing/utils.py +4 -2
- cirq/contrib/svg/svg.py +9 -6
- cirq/devices/device.py +11 -9
- cirq/devices/grid_device_metadata.py +14 -11
- cirq/devices/grid_qubit.py +17 -21
- cirq/devices/grid_qubit_test.py +1 -1
- cirq/devices/insertion_noise_model.py +5 -5
- cirq/devices/line_qubit.py +15 -17
- cirq/devices/named_topologies.py +6 -4
- cirq/devices/noise_model.py +27 -31
- {cirq_core-1.5.0.dev20250403170622.dist-info → cirq_core-1.5.0.dev20250404021339.dist-info}/METADATA +1 -1
- {cirq_core-1.5.0.dev20250403170622.dist-info → cirq_core-1.5.0.dev20250404021339.dist-info}/RECORD +54 -54
- {cirq_core-1.5.0.dev20250403170622.dist-info → cirq_core-1.5.0.dev20250404021339.dist-info}/LICENSE +0 -0
- {cirq_core-1.5.0.dev20250403170622.dist-info → cirq_core-1.5.0.dev20250404021339.dist-info}/WHEEL +0 -0
- {cirq_core-1.5.0.dev20250403170622.dist-info → cirq_core-1.5.0.dev20250404021339.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
|
import abc
|
|
16
18
|
from collections import defaultdict
|
|
17
19
|
from typing import DefaultDict, Dict, Iterator, Optional, Sequence, TYPE_CHECKING
|
|
@@ -42,7 +44,7 @@ class ExecutionStrategy(metaclass=abc.ABCMeta):
|
|
|
42
44
|
|
|
43
45
|
@property
|
|
44
46
|
@abc.abstractmethod
|
|
45
|
-
def device(self) ->
|
|
47
|
+
def device(self) -> cirq.Device:
|
|
46
48
|
"""The device for which the executed acquaintance strategy should be
|
|
47
49
|
valid.
|
|
48
50
|
"""
|
|
@@ -54,8 +56,8 @@ class ExecutionStrategy(metaclass=abc.ABCMeta):
|
|
|
54
56
|
|
|
55
57
|
@abc.abstractmethod
|
|
56
58
|
def get_operations(
|
|
57
|
-
self, indices: Sequence[LogicalIndex], qubits: Sequence[
|
|
58
|
-
) ->
|
|
59
|
+
self, indices: Sequence[LogicalIndex], qubits: Sequence[cirq.Qid]
|
|
60
|
+
) -> cirq.OP_TREE:
|
|
59
61
|
"""Gets the logical operations to apply to qubits."""
|
|
60
62
|
|
|
61
63
|
def __call__(self, *args, **kwargs):
|
|
@@ -97,13 +99,13 @@ class StrategyExecutorTransformer:
|
|
|
97
99
|
self._mapping = execution_strategy.initial_mapping.copy()
|
|
98
100
|
|
|
99
101
|
def __call__(
|
|
100
|
-
self, circuit: circuits.AbstractCircuit, context: Optional[
|
|
102
|
+
self, circuit: circuits.AbstractCircuit, context: Optional[cirq.TransformerContext] = None
|
|
101
103
|
) -> circuits.Circuit:
|
|
102
104
|
"""Executes an acquaintance strategy using cirq.map_operations_and_unroll and
|
|
103
105
|
mutates initial mapping.
|
|
104
106
|
|
|
105
107
|
Args:
|
|
106
|
-
circuit:
|
|
108
|
+
circuit: `cirq.Circuit` input circuit to transform.
|
|
107
109
|
context: `cirq.TransformerContext` storing common configurable
|
|
108
110
|
options for transformers.
|
|
109
111
|
|
|
@@ -126,7 +128,7 @@ class StrategyExecutorTransformer:
|
|
|
126
128
|
def mapping(self) -> LogicalMapping:
|
|
127
129
|
return self._mapping
|
|
128
130
|
|
|
129
|
-
def _map_func(self, op:
|
|
131
|
+
def _map_func(self, op: cirq.Operation, index) -> cirq.OP_TREE:
|
|
130
132
|
if isinstance(op.gate, AcquaintanceOpportunityGate):
|
|
131
133
|
logical_indices = tuple(self._mapping[q] for q in op.qubits)
|
|
132
134
|
logical_operations = self.execution_strategy.get_operations(logical_indices, op.qubits)
|
|
@@ -150,17 +152,13 @@ class AcquaintanceOperation(ops.GateOperation):
|
|
|
150
152
|
logical indices on a particular set of physical qubits.
|
|
151
153
|
"""
|
|
152
154
|
|
|
153
|
-
def __init__(
|
|
154
|
-
self, qubits: Sequence['cirq.Qid'], logical_indices: Sequence[LogicalIndex]
|
|
155
|
-
) -> None:
|
|
155
|
+
def __init__(self, qubits: Sequence[cirq.Qid], logical_indices: Sequence[LogicalIndex]) -> None:
|
|
156
156
|
if len(logical_indices) != len(qubits):
|
|
157
157
|
raise ValueError('len(logical_indices) != len(qubits)')
|
|
158
158
|
super().__init__(AcquaintanceOpportunityGate(num_qubits=len(qubits)), qubits)
|
|
159
159
|
self.logical_indices: LogicalIndexSequence = logical_indices
|
|
160
160
|
|
|
161
|
-
def _circuit_diagram_info_(
|
|
162
|
-
self, args: 'cirq.CircuitDiagramInfoArgs'
|
|
163
|
-
) -> 'cirq.CircuitDiagramInfo':
|
|
161
|
+
def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
|
|
164
162
|
wire_symbols = tuple(f'({i})' for i in self.logical_indices)
|
|
165
163
|
return protocols.CircuitDiagramInfo(wire_symbols=wire_symbols)
|
|
166
164
|
|
|
@@ -176,7 +174,7 @@ class GreedyExecutionStrategy(ExecutionStrategy):
|
|
|
176
174
|
self,
|
|
177
175
|
gates: LogicalGates,
|
|
178
176
|
initial_mapping: LogicalMapping,
|
|
179
|
-
device: Optional[
|
|
177
|
+
device: Optional[cirq.Device] = None,
|
|
180
178
|
) -> None:
|
|
181
179
|
"""Inits GreedyExecutionStrategy.
|
|
182
180
|
|
|
@@ -202,12 +200,12 @@ class GreedyExecutionStrategy(ExecutionStrategy):
|
|
|
202
200
|
return self._initial_mapping
|
|
203
201
|
|
|
204
202
|
@property
|
|
205
|
-
def device(self) ->
|
|
203
|
+
def device(self) -> cirq.Device:
|
|
206
204
|
return self._device
|
|
207
205
|
|
|
208
206
|
def get_operations(
|
|
209
|
-
self, indices: Sequence[LogicalIndex], qubits: Sequence[
|
|
210
|
-
) -> Iterator[
|
|
207
|
+
self, indices: Sequence[LogicalIndex], qubits: Sequence[cirq.Qid]
|
|
208
|
+
) -> Iterator[cirq.OP_TREE]:
|
|
211
209
|
index_set = frozenset(indices)
|
|
212
210
|
if index_set in self.index_set_to_gates:
|
|
213
211
|
gates = self.index_set_to_gates.pop(index_set)
|
|
@@ -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 functools
|
|
16
18
|
import itertools
|
|
17
19
|
import math
|
|
@@ -41,13 +43,11 @@ if TYPE_CHECKING:
|
|
|
41
43
|
|
|
42
44
|
|
|
43
45
|
def operations_to_part_lens(
|
|
44
|
-
qubit_order: Sequence[
|
|
46
|
+
qubit_order: Sequence[cirq.Qid], op_tree: cirq.OP_TREE
|
|
45
47
|
) -> Tuple[int, ...]:
|
|
46
48
|
qubit_sort_key = functools.partial(operator.indexOf, qubit_order)
|
|
47
49
|
op_parts = [tuple(sorted(op.qubits, key=qubit_sort_key)) for op in ops.flatten_op_tree(op_tree)]
|
|
48
|
-
singletons: List[Tuple[
|
|
49
|
-
(q,) for q in set(qubit_order).difference(*op_parts)
|
|
50
|
-
]
|
|
50
|
+
singletons: List[Tuple[cirq.Qid, ...]] = [(q,) for q in set(qubit_order).difference(*op_parts)]
|
|
51
51
|
part_sort_key = lambda p: min(qubit_sort_key(q) for q in p)
|
|
52
52
|
parts = tuple(tuple(part) for part in sorted(singletons + op_parts, key=part_sort_key))
|
|
53
53
|
|
|
@@ -71,7 +71,7 @@ class AcquaintanceOpportunityGate(ops.Gate, ops.InterchangeableQubitsGate):
|
|
|
71
71
|
f'num_qubits={self.num_qubits()!r})'
|
|
72
72
|
)
|
|
73
73
|
|
|
74
|
-
def _circuit_diagram_info_(self, args:
|
|
74
|
+
def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Iterable[str]:
|
|
75
75
|
wire_symbol = '█' if args.use_unicode_characters else 'Acq'
|
|
76
76
|
wire_symbols = (wire_symbol,) * self.num_qubits()
|
|
77
77
|
return wire_symbols
|
|
@@ -80,7 +80,7 @@ class AcquaintanceOpportunityGate(ops.Gate, ops.InterchangeableQubitsGate):
|
|
|
80
80
|
return self._num_qubits
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
def acquaint(*qubits) ->
|
|
83
|
+
def acquaint(*qubits) -> cirq.Operation:
|
|
84
84
|
return AcquaintanceOpportunityGate(len(qubits)).on(*qubits)
|
|
85
85
|
|
|
86
86
|
|
|
@@ -96,14 +96,14 @@ Layers = NamedTuple(
|
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
def new_layers(**kwargs: List[
|
|
99
|
+
def new_layers(**kwargs: List[cirq.Operation]) -> Layers:
|
|
100
100
|
return Layers._make(kwargs.get(field, []) for field in Layers._fields)
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
def acquaint_insides(
|
|
104
|
-
swap_gate:
|
|
105
|
-
acquaintance_gate:
|
|
106
|
-
qubits: Sequence[
|
|
104
|
+
swap_gate: cirq.Gate,
|
|
105
|
+
acquaintance_gate: cirq.Operation,
|
|
106
|
+
qubits: Sequence[cirq.Qid],
|
|
107
107
|
before: bool,
|
|
108
108
|
layers: Layers,
|
|
109
109
|
mapping: Dict[ops.Qid, int],
|
|
@@ -153,10 +153,10 @@ def _get_max_reach(size: int, round_up: bool = True) -> int:
|
|
|
153
153
|
|
|
154
154
|
|
|
155
155
|
def acquaint_and_shift(
|
|
156
|
-
parts: Tuple[List[
|
|
156
|
+
parts: Tuple[List[cirq.Qid], List[cirq.Qid]],
|
|
157
157
|
layers: Layers,
|
|
158
158
|
acquaintance_size: Optional[int],
|
|
159
|
-
swap_gate:
|
|
159
|
+
swap_gate: cirq.Gate,
|
|
160
160
|
mapping: Dict[ops.Qid, int],
|
|
161
161
|
):
|
|
162
162
|
"""Acquaints and shifts a pair of lists of qubits. The first part is
|
|
@@ -277,7 +277,7 @@ class SwapNetworkGate(PermutationGate):
|
|
|
277
277
|
self,
|
|
278
278
|
part_lens: Sequence[int],
|
|
279
279
|
acquaintance_size: Optional[int] = 0,
|
|
280
|
-
swap_gate:
|
|
280
|
+
swap_gate: cirq.Gate = ops.SWAP,
|
|
281
281
|
) -> None:
|
|
282
282
|
super().__init__(sum(part_lens), swap_gate)
|
|
283
283
|
if len(part_lens) < 2:
|
|
@@ -285,7 +285,7 @@ class SwapNetworkGate(PermutationGate):
|
|
|
285
285
|
self.part_lens = tuple(part_lens)
|
|
286
286
|
self.acquaintance_size = acquaintance_size
|
|
287
287
|
|
|
288
|
-
def _decompose_(self, qubits: Sequence[
|
|
288
|
+
def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]:
|
|
289
289
|
qubit_to_position = {q: i for i, q in enumerate(qubits)}
|
|
290
290
|
mapping = dict(qubit_to_position)
|
|
291
291
|
parts = []
|
|
@@ -333,9 +333,7 @@ class SwapNetworkGate(PermutationGate):
|
|
|
333
333
|
if final_gate:
|
|
334
334
|
yield final_gate(*qubits)
|
|
335
335
|
|
|
336
|
-
def _circuit_diagram_info_(
|
|
337
|
-
self, args: 'cirq.CircuitDiagramInfoArgs'
|
|
338
|
-
) -> 'cirq.CircuitDiagramInfo':
|
|
336
|
+
def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
|
|
339
337
|
wire_symbol = '×' if args.use_unicode_characters else 'swap'
|
|
340
338
|
wire_symbols = tuple(
|
|
341
339
|
wire_symbol + f'({part_index},{qubit_index})'
|
|
@@ -346,11 +344,11 @@ class SwapNetworkGate(PermutationGate):
|
|
|
346
344
|
|
|
347
345
|
@staticmethod
|
|
348
346
|
def from_operations(
|
|
349
|
-
qubit_order: Sequence[
|
|
350
|
-
operations: Sequence[
|
|
347
|
+
qubit_order: Sequence[cirq.Qid],
|
|
348
|
+
operations: Sequence[cirq.Operation],
|
|
351
349
|
acquaintance_size: Optional[int] = 0,
|
|
352
|
-
swap_gate:
|
|
353
|
-
) ->
|
|
350
|
+
swap_gate: cirq.Gate = ops.SWAP,
|
|
351
|
+
) -> SwapNetworkGate:
|
|
354
352
|
part_sizes = operations_to_part_lens(qubit_order, operations)
|
|
355
353
|
return SwapNetworkGate(part_sizes, acquaintance_size, swap_gate)
|
|
356
354
|
|
|
@@ -12,16 +12,18 @@
|
|
|
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 FrozenSet, Iterator, Sequence, Set, TYPE_CHECKING
|
|
16
18
|
|
|
17
19
|
from cirq import devices
|
|
18
20
|
from cirq.contrib import circuitdag
|
|
19
21
|
from cirq.contrib.acquaintance.executor import AcquaintanceOperation, ExecutionStrategy
|
|
20
22
|
from cirq.contrib.acquaintance.mutation_utils import expose_acquaintance_gates
|
|
21
|
-
from cirq.contrib.acquaintance.permutation import LogicalIndex, LogicalMapping
|
|
22
23
|
|
|
23
24
|
if TYPE_CHECKING:
|
|
24
25
|
import cirq
|
|
26
|
+
from cirq.contrib.acquaintance.permutation import LogicalIndex, LogicalMapping
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
class LogicalAnnotator(ExecutionStrategy):
|
|
@@ -40,16 +42,16 @@ class LogicalAnnotator(ExecutionStrategy):
|
|
|
40
42
|
return self._initial_mapping
|
|
41
43
|
|
|
42
44
|
@property
|
|
43
|
-
def device(self) ->
|
|
45
|
+
def device(self) -> cirq.Device:
|
|
44
46
|
return devices.UNCONSTRAINED_DEVICE
|
|
45
47
|
|
|
46
48
|
def get_operations(
|
|
47
|
-
self, indices: Sequence[LogicalIndex], qubits: Sequence[
|
|
48
|
-
) -> Iterator[
|
|
49
|
+
self, indices: Sequence[LogicalIndex], qubits: Sequence[cirq.Qid]
|
|
50
|
+
) -> Iterator[cirq.OP_TREE]:
|
|
49
51
|
yield AcquaintanceOperation(qubits, indices)
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
def get_acquaintance_dag(strategy:
|
|
54
|
+
def get_acquaintance_dag(strategy: cirq.Circuit, initial_mapping: LogicalMapping):
|
|
53
55
|
strategy = strategy.copy()
|
|
54
56
|
expose_acquaintance_gates(strategy)
|
|
55
57
|
LogicalAnnotator(initial_mapping)(strategy)
|
|
@@ -63,7 +65,7 @@ def get_acquaintance_dag(strategy: 'cirq.Circuit', initial_mapping: LogicalMappi
|
|
|
63
65
|
|
|
64
66
|
|
|
65
67
|
def get_logical_acquaintance_opportunities(
|
|
66
|
-
strategy:
|
|
68
|
+
strategy: cirq.Circuit, initial_mapping: LogicalMapping
|
|
67
69
|
) -> Set[FrozenSet[LogicalIndex]]:
|
|
68
70
|
acquaintance_dag = get_acquaintance_dag(strategy, initial_mapping)
|
|
69
71
|
logical_acquaintance_opportunities = set()
|
|
@@ -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 collections
|
|
16
18
|
from typing import cast, Dict, List, Optional, Sequence, TYPE_CHECKING, Union
|
|
17
19
|
|
|
@@ -26,7 +28,7 @@ if TYPE_CHECKING:
|
|
|
26
28
|
STRATEGY_GATE = Union[AcquaintanceOpportunityGate, PermutationGate]
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
def rectify_acquaintance_strategy(circuit:
|
|
31
|
+
def rectify_acquaintance_strategy(circuit: cirq.Circuit, acquaint_first: bool = True) -> None:
|
|
30
32
|
"""Splits moments so that they contain either only acquaintance or permutation gates.
|
|
31
33
|
|
|
32
34
|
Orders resulting moments so that the first one is of the same type as the previous one.
|
|
@@ -55,10 +57,10 @@ def rectify_acquaintance_strategy(circuit: 'cirq.Circuit', acquaint_first: bool
|
|
|
55
57
|
|
|
56
58
|
|
|
57
59
|
def replace_acquaintance_with_swap_network(
|
|
58
|
-
circuit:
|
|
59
|
-
qubit_order: Sequence[
|
|
60
|
+
circuit: cirq.Circuit,
|
|
61
|
+
qubit_order: Sequence[cirq.Qid],
|
|
60
62
|
acquaintance_size: Optional[int] = 0,
|
|
61
|
-
swap_gate:
|
|
63
|
+
swap_gate: cirq.Gate = ops.SWAP,
|
|
62
64
|
) -> bool:
|
|
63
65
|
"""Replace every rectified moment with acquaintance gates with a generalized swap network.
|
|
64
66
|
|
|
@@ -104,10 +106,10 @@ class ExposeAcquaintanceGates:
|
|
|
104
106
|
not get_acquaintance_size(op) or isinstance(op.gate, AcquaintanceOpportunityGate)
|
|
105
107
|
)
|
|
106
108
|
|
|
107
|
-
def optimize_circuit(self, circuit:
|
|
109
|
+
def optimize_circuit(self, circuit: cirq.Circuit) -> None:
|
|
108
110
|
circuit._moments = [*transformers.expand_composite(circuit, no_decomp=self.no_decomp)]
|
|
109
111
|
|
|
110
|
-
def __call__(self, circuit:
|
|
112
|
+
def __call__(self, circuit: cirq.Circuit) -> None:
|
|
111
113
|
self.optimize_circuit(circuit)
|
|
112
114
|
|
|
113
115
|
|
|
@@ -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 cast, FrozenSet, List, Sequence, Set, TYPE_CHECKING
|
|
16
18
|
|
|
17
19
|
from cirq import circuits
|
|
@@ -24,7 +26,7 @@ if TYPE_CHECKING:
|
|
|
24
26
|
import cirq
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
def remove_redundant_acquaintance_opportunities(strategy:
|
|
29
|
+
def remove_redundant_acquaintance_opportunities(strategy: cirq.Circuit) -> int:
|
|
28
30
|
"""Removes redundant acquaintance opportunities."""
|
|
29
31
|
|
|
30
32
|
qubits = sorted(strategy.all_qubits())
|
|
@@ -34,11 +36,11 @@ def remove_redundant_acquaintance_opportunities(strategy: 'cirq.Circuit') -> int
|
|
|
34
36
|
annotated_strategy = strategy.copy()
|
|
35
37
|
LogicalAnnotator(mapping)(annotated_strategy)
|
|
36
38
|
|
|
37
|
-
new_moments: List[
|
|
39
|
+
new_moments: List[cirq.Moment] = []
|
|
38
40
|
acquaintance_opps: Set[FrozenSet[int]] = set()
|
|
39
41
|
n_removed = 0
|
|
40
42
|
for moment in annotated_strategy:
|
|
41
|
-
new_moment: List[
|
|
43
|
+
new_moment: List[cirq.Operation] = []
|
|
42
44
|
for op in moment:
|
|
43
45
|
if isinstance(op, AcquaintanceOperation):
|
|
44
46
|
opp = frozenset(cast(Sequence[int], op.logical_indices))
|
|
@@ -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 types import NotImplementedType
|
|
17
19
|
from typing import (
|
|
@@ -51,7 +53,7 @@ class PermutationGate(ops.Gate, metaclass=abc.ABCMeta):
|
|
|
51
53
|
qubits (e.g. SWAP or fermionic swap).
|
|
52
54
|
"""
|
|
53
55
|
|
|
54
|
-
def __init__(self, num_qubits: int, swap_gate:
|
|
56
|
+
def __init__(self, num_qubits: int, swap_gate: cirq.Gate = ops.SWAP) -> None:
|
|
55
57
|
self._num_qubits = num_qubits
|
|
56
58
|
self.swap_gate = swap_gate
|
|
57
59
|
|
|
@@ -64,7 +66,7 @@ class PermutationGate(ops.Gate, metaclass=abc.ABCMeta):
|
|
|
64
66
|
the s[i]-th element."""
|
|
65
67
|
|
|
66
68
|
def update_mapping(
|
|
67
|
-
self, mapping: Dict[ops.Qid, LogicalIndex], keys: Sequence[
|
|
69
|
+
self, mapping: Dict[ops.Qid, LogicalIndex], keys: Sequence[cirq.Qid]
|
|
68
70
|
) -> None:
|
|
69
71
|
"""Updates a mapping (in place) from qubits to logical indices.
|
|
70
72
|
|
|
@@ -96,8 +98,8 @@ class PermutationGate(ops.Gate, metaclass=abc.ABCMeta):
|
|
|
96
98
|
raise IndexError('key is out of bounds.')
|
|
97
99
|
|
|
98
100
|
def _circuit_diagram_info_(
|
|
99
|
-
self, args:
|
|
100
|
-
) -> Union[str, Iterable[str],
|
|
101
|
+
self, args: cirq.CircuitDiagramInfoArgs
|
|
102
|
+
) -> Union[str, Iterable[str], cirq.CircuitDiagramInfo]:
|
|
101
103
|
if args.known_qubit_count is None:
|
|
102
104
|
return NotImplemented
|
|
103
105
|
permutation = self.permutation()
|
|
@@ -118,14 +120,12 @@ class MappingDisplayGate(ops.Gate):
|
|
|
118
120
|
def num_qubits(self) -> int:
|
|
119
121
|
return self._num_qubits
|
|
120
122
|
|
|
121
|
-
def _circuit_diagram_info_(
|
|
122
|
-
self, args: 'cirq.CircuitDiagramInfoArgs'
|
|
123
|
-
) -> 'cirq.CircuitDiagramInfo':
|
|
123
|
+
def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
|
|
124
124
|
wire_symbols = tuple('' if i is None else str(i) for i in self.indices)
|
|
125
125
|
return protocols.CircuitDiagramInfo(wire_symbols, connected=False)
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
def display_mapping(circuit:
|
|
128
|
+
def display_mapping(circuit: cirq.Circuit, initial_mapping: LogicalMapping) -> None:
|
|
129
129
|
"""Inserts display gates between moments to indicate the mapping throughout
|
|
130
130
|
the circuit."""
|
|
131
131
|
qubits = sorted(circuit.all_qubits())
|
|
@@ -147,13 +147,13 @@ def display_mapping(circuit: 'cirq.Circuit', initial_mapping: LogicalMapping) ->
|
|
|
147
147
|
class SwapPermutationGate(PermutationGate):
|
|
148
148
|
"""Generic swap gate."""
|
|
149
149
|
|
|
150
|
-
def __init__(self, swap_gate:
|
|
150
|
+
def __init__(self, swap_gate: cirq.Gate = ops.SWAP):
|
|
151
151
|
super().__init__(2, swap_gate)
|
|
152
152
|
|
|
153
153
|
def permutation(self) -> Dict[int, int]:
|
|
154
154
|
return {0: 1, 1: 0}
|
|
155
155
|
|
|
156
|
-
def _decompose_(self, qubits: Sequence[
|
|
156
|
+
def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]:
|
|
157
157
|
yield self.swap_gate(*qubits)
|
|
158
158
|
|
|
159
159
|
def __repr__(self) -> str:
|
|
@@ -186,7 +186,7 @@ class LinearPermutationGate(PermutationGate):
|
|
|
186
186
|
sorting network."""
|
|
187
187
|
|
|
188
188
|
def __init__(
|
|
189
|
-
self, num_qubits: int, permutation: Dict[int, int], swap_gate:
|
|
189
|
+
self, num_qubits: int, permutation: Dict[int, int], swap_gate: cirq.Gate = ops.SWAP
|
|
190
190
|
) -> None:
|
|
191
191
|
"""Initializes a linear permutation gate.
|
|
192
192
|
|
|
@@ -202,7 +202,7 @@ class LinearPermutationGate(PermutationGate):
|
|
|
202
202
|
def permutation(self) -> Dict[int, int]:
|
|
203
203
|
return self._permutation
|
|
204
204
|
|
|
205
|
-
def _decompose_(self, qubits: Sequence[
|
|
205
|
+
def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]:
|
|
206
206
|
swap_gate = SwapPermutationGate(self.swap_gate)
|
|
207
207
|
n_qubits = len(qubits)
|
|
208
208
|
mapping = {i: self._permutation.get(i, i) for i in range(n_qubits)}
|
|
@@ -238,7 +238,7 @@ class LinearPermutationGate(PermutationGate):
|
|
|
238
238
|
return NotImplemented
|
|
239
239
|
|
|
240
240
|
|
|
241
|
-
def update_mapping(mapping: Dict[ops.Qid, LogicalIndex], operations:
|
|
241
|
+
def update_mapping(mapping: Dict[ops.Qid, LogicalIndex], operations: cirq.OP_TREE) -> None:
|
|
242
242
|
"""Updates a mapping (in place) from qubits to logical indices according to
|
|
243
243
|
a set of permutation gates. Any gates other than permutation gates are
|
|
244
244
|
ignored.
|
|
@@ -253,8 +253,8 @@ def update_mapping(mapping: Dict[ops.Qid, LogicalIndex], operations: 'cirq.OP_TR
|
|
|
253
253
|
|
|
254
254
|
|
|
255
255
|
def get_logical_operations(
|
|
256
|
-
operations:
|
|
257
|
-
) -> Iterable[
|
|
256
|
+
operations: cirq.OP_TREE, initial_mapping: Dict[ops.Qid, ops.Qid]
|
|
257
|
+
) -> Iterable[cirq.Operation]:
|
|
258
258
|
"""Gets the logical operations specified by the physical operations and
|
|
259
259
|
initial mapping.
|
|
260
260
|
|
|
@@ -300,10 +300,10 @@ class DecomposePermutationGates:
|
|
|
300
300
|
not all([isinstance(op, ops.GateOperation), isinstance(op.gate, PermutationGate)])
|
|
301
301
|
)
|
|
302
302
|
|
|
303
|
-
def optimize_circuit(self, circuit:
|
|
303
|
+
def optimize_circuit(self, circuit: cirq.Circuit) -> None:
|
|
304
304
|
circuit._moments = [*transformers.expand_composite(circuit, no_decomp=self.no_decomp)]
|
|
305
305
|
|
|
306
|
-
def __call__(self, circuit:
|
|
306
|
+
def __call__(self, circuit: cirq.Circuit) -> None:
|
|
307
307
|
self.optimize_circuit(circuit)
|
|
308
308
|
|
|
309
309
|
|
|
@@ -311,7 +311,7 @@ EXPAND_PERMUTATION_GATES = DecomposePermutationGates(keep_swap_permutations=True
|
|
|
311
311
|
DECOMPOSE_PERMUTATION_GATES = DecomposePermutationGates(keep_swap_permutations=False)
|
|
312
312
|
|
|
313
313
|
|
|
314
|
-
def return_to_initial_mapping(circuit:
|
|
314
|
+
def return_to_initial_mapping(circuit: cirq.Circuit, swap_gate: cirq.Gate = ops.SWAP) -> None:
|
|
315
315
|
qubits = sorted(circuit.all_qubits())
|
|
316
316
|
n_qubits = len(qubits)
|
|
317
317
|
|
|
@@ -323,7 +323,7 @@ def return_to_initial_mapping(circuit: 'cirq.Circuit', swap_gate: 'cirq.Gate' =
|
|
|
323
323
|
circuit.append(returning_permutation_op)
|
|
324
324
|
|
|
325
325
|
|
|
326
|
-
def uses_consistent_swap_gate(circuit:
|
|
326
|
+
def uses_consistent_swap_gate(circuit: cirq.Circuit, swap_gate: cirq.Gate) -> bool:
|
|
327
327
|
for op in circuit.all_operations():
|
|
328
328
|
if isinstance(op, ops.GateOperation) and isinstance(op.gate, PermutationGate):
|
|
329
329
|
if op.gate.swap_gate != swap_gate:
|
|
@@ -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 typing import Any, Dict, Iterator, Sequence, Tuple, TYPE_CHECKING
|
|
17
19
|
|
|
@@ -26,7 +28,7 @@ if TYPE_CHECKING:
|
|
|
26
28
|
class CircularShiftGate(PermutationGate):
|
|
27
29
|
"""Performs a cyclical permutation of the qubits to the left by a specified amount."""
|
|
28
30
|
|
|
29
|
-
def __init__(self, num_qubits: int, shift: int, swap_gate:
|
|
31
|
+
def __init__(self, num_qubits: int, shift: int, swap_gate: cirq.Gate = ops.SWAP) -> None:
|
|
30
32
|
"""Construct a circular shift gate.
|
|
31
33
|
|
|
32
34
|
Args:
|
|
@@ -47,7 +49,7 @@ class CircularShiftGate(PermutationGate):
|
|
|
47
49
|
def _value_equality_values_(self) -> Any:
|
|
48
50
|
return self.shift, self.swap_gate, self.num_qubits()
|
|
49
51
|
|
|
50
|
-
def _decompose_(self, qubits: Sequence[
|
|
52
|
+
def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]:
|
|
51
53
|
n = len(qubits)
|
|
52
54
|
left_shift = self.shift % n
|
|
53
55
|
right_shift = n - left_shift
|
|
@@ -58,7 +60,7 @@ class CircularShiftGate(PermutationGate):
|
|
|
58
60
|
for k in range(i, j, 2):
|
|
59
61
|
yield swap_gate(*qubits[k : k + 2])
|
|
60
62
|
|
|
61
|
-
def _circuit_diagram_info_(self, args:
|
|
63
|
+
def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Tuple[str, ...]:
|
|
62
64
|
if args.known_qubit_count is None:
|
|
63
65
|
return NotImplemented # pragma: no cover
|
|
64
66
|
direction_symbols = ('╲', '╱') if args.use_unicode_characters else ('\\', '/')
|
|
@@ -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 functools
|
|
16
18
|
import itertools
|
|
17
19
|
from typing import Dict, Iterable, Iterator, Optional, Sequence, Tuple, TYPE_CHECKING
|
|
@@ -51,7 +53,7 @@ class ShiftSwapNetworkGate(PermutationGate):
|
|
|
51
53
|
self,
|
|
52
54
|
left_part_lens: Iterable[int],
|
|
53
55
|
right_part_lens: Iterable[int],
|
|
54
|
-
swap_gate:
|
|
56
|
+
swap_gate: cirq.Gate = ops.SWAP,
|
|
55
57
|
) -> None:
|
|
56
58
|
|
|
57
59
|
self.part_lens = {'left': tuple(left_part_lens), 'right': tuple(right_part_lens)}
|
|
@@ -65,7 +67,7 @@ class ShiftSwapNetworkGate(PermutationGate):
|
|
|
65
67
|
def acquaintance_size(self) -> int:
|
|
66
68
|
return sum(max(self.part_lens[side]) for side in ('left', 'right'))
|
|
67
69
|
|
|
68
|
-
def _decompose_(self, qubits: Sequence[
|
|
70
|
+
def _decompose_(self, qubits: Sequence[cirq.Qid]) -> Iterator[cirq.OP_TREE]:
|
|
69
71
|
part_lens = list(itertools.chain(*(self.part_lens[side] for side in ('left', 'right'))))
|
|
70
72
|
|
|
71
73
|
n_qubits = 0
|
|
@@ -110,7 +112,7 @@ class ShiftSwapNetworkGate(PermutationGate):
|
|
|
110
112
|
)
|
|
111
113
|
)
|
|
112
114
|
|
|
113
|
-
def _circuit_diagram_info_(self, args:
|
|
115
|
+
def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> Tuple[str, ...]:
|
|
114
116
|
qubit_count = self.qubit_count()
|
|
115
117
|
assert args.known_qubit_count in (None, qubit_count)
|
|
116
118
|
|
|
@@ -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 Sequence, TYPE_CHECKING
|
|
16
18
|
|
|
17
19
|
from cirq import circuits, ops
|
|
@@ -26,8 +28,8 @@ if TYPE_CHECKING:
|
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
def complete_acquaintance_strategy(
|
|
29
|
-
qubit_order: Sequence[
|
|
30
|
-
) ->
|
|
31
|
+
qubit_order: Sequence[cirq.Qid], acquaintance_size: int = 0, swap_gate: cirq.Gate = ops.SWAP
|
|
32
|
+
) -> cirq.Circuit:
|
|
31
33
|
"""Returns an acquaintance strategy with can handle the given number of qubits.
|
|
32
34
|
|
|
33
35
|
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 itertools
|
|
16
18
|
from typing import Iterable, Sequence, Tuple, TYPE_CHECKING, TypeVar
|
|
17
19
|
|
|
@@ -35,8 +37,8 @@ def skip_and_wrap_around(items: Sequence[TItem]) -> Tuple[TItem, ...]:
|
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
def cubic_acquaintance_strategy(
|
|
38
|
-
qubits: Iterable[
|
|
39
|
-
) ->
|
|
40
|
+
qubits: Iterable[cirq.Qid], swap_gate: cirq.Gate = ops.SWAP
|
|
41
|
+
) -> cirq.Circuit:
|
|
40
42
|
"""Acquaints every triple of qubits.
|
|
41
43
|
|
|
42
44
|
Exploits the fact that in a simple linear swap network every pair of
|
|
@@ -12,9 +12,11 @@
|
|
|
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 cast, Iterable, List, Sequence, Tuple, TYPE_CHECKING
|
|
16
18
|
|
|
17
|
-
from cirq import circuits
|
|
19
|
+
from cirq import circuits
|
|
18
20
|
from cirq.contrib.acquaintance.gates import acquaint, SwapNetworkGate
|
|
19
21
|
from cirq.contrib.acquaintance.mutation_utils import expose_acquaintance_gates
|
|
20
22
|
|
|
@@ -22,7 +24,7 @@ if TYPE_CHECKING:
|
|
|
22
24
|
import cirq
|
|
23
25
|
|
|
24
26
|
|
|
25
|
-
def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence[
|
|
27
|
+
def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence[cirq.Qid]]) -> List[cirq.Qid]:
|
|
26
28
|
"""Takes a sequence of qubit pairs and returns a sequence in which every
|
|
27
29
|
pair is at distance two.
|
|
28
30
|
|
|
@@ -33,7 +35,7 @@ def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence['cirq.Qid']]) -> L
|
|
|
33
35
|
if set(len(qubit_pair) for qubit_pair in qubit_pairs) != set((2,)):
|
|
34
36
|
raise ValueError('set(len(qubit_pair) for qubit_pair in qubit_pairs) != set((2,))')
|
|
35
37
|
n_pairs = len(qubit_pairs)
|
|
36
|
-
qubits: List[
|
|
38
|
+
qubits: List[cirq.Qid] = []
|
|
37
39
|
for i in range(0, 2 * (n_pairs // 2), 2):
|
|
38
40
|
qubits += [
|
|
39
41
|
qubit_pairs[i][0],
|
|
@@ -47,15 +49,15 @@ def qubit_pairs_to_qubit_order(qubit_pairs: Sequence[Sequence['cirq.Qid']]) -> L
|
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
def quartic_paired_acquaintance_strategy(
|
|
50
|
-
qubit_pairs: Iterable[Tuple[
|
|
51
|
-
) -> Tuple[
|
|
52
|
+
qubit_pairs: Iterable[Tuple[cirq.Qid, cirq.Qid]],
|
|
53
|
+
) -> Tuple[cirq.Circuit, Sequence[cirq.Qid]]:
|
|
52
54
|
"""Acquaintance strategy for pairs of pairs.
|
|
53
55
|
|
|
54
56
|
Implements UpCCGSD ansatz from arXiv:1810.02327.
|
|
55
57
|
"""
|
|
56
58
|
|
|
57
59
|
qubit_pairs = tuple(
|
|
58
|
-
cast(Tuple['cirq.Qid',
|
|
60
|
+
cast(Tuple['cirq.Qid', 'cirq.Qid'], tuple(qubit_pair)) for qubit_pair in qubit_pairs
|
|
59
61
|
)
|
|
60
62
|
qubits = qubit_pairs_to_qubit_order(qubit_pairs)
|
|
61
63
|
n_qubits = len(qubits)
|
|
@@ -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 operator
|
|
16
18
|
import random
|
|
17
19
|
from typing import Any, Callable, cast, Iterable, TYPE_CHECKING
|
|
@@ -25,8 +27,8 @@ if TYPE_CHECKING:
|
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def is_topologically_sorted(
|
|
28
|
-
dag:
|
|
29
|
-
operations:
|
|
30
|
+
dag: cirq.contrib.CircuitDag,
|
|
31
|
+
operations: cirq.OP_TREE,
|
|
30
32
|
equals: Callable[[ops.Operation, ops.Operation], bool] = operator.eq,
|
|
31
33
|
) -> bool:
|
|
32
34
|
"""Whether a given order of operations is consistent with the DAG.
|