cirq-core 1.7.0.dev20251027223253__py3-none-any.whl → 1.7.0.dev20251028035559__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/dynamical_decoupling.py +185 -112
- cirq/transformers/dynamical_decoupling_test.py +174 -180
- cirq/value/digits.py +7 -1
- {cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/METADATA +1 -1
- {cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/RECORD +10 -10
- {cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/WHEEL +0 -0
- {cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
|
@@ -16,11 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
+
from enum import Enum
|
|
19
20
|
from functools import reduce
|
|
20
21
|
from itertools import cycle
|
|
21
22
|
from typing import TYPE_CHECKING
|
|
22
23
|
|
|
23
24
|
import numpy as np
|
|
25
|
+
from attrs import frozen
|
|
24
26
|
|
|
25
27
|
from cirq import ops, protocols
|
|
26
28
|
from cirq.circuits import Circuit, FrozenCircuit, Moment
|
|
@@ -133,10 +135,6 @@ def _calc_busy_moment_range_of_each_qubit(circuit: FrozenCircuit) -> dict[ops.Qi
|
|
|
133
135
|
return busy_moment_range_by_qubit
|
|
134
136
|
|
|
135
137
|
|
|
136
|
-
def _is_insertable_moment(moment: Moment, single_qubit_gate_moments_only: bool) -> bool:
|
|
137
|
-
return not single_qubit_gate_moments_only or _is_single_qubit_gate_moment(moment)
|
|
138
|
-
|
|
139
|
-
|
|
140
138
|
def _merge_single_qubit_ops_to_phxz(
|
|
141
139
|
q: ops.Qid, operations: tuple[ops.Operation, ...]
|
|
142
140
|
) -> ops.Operation:
|
|
@@ -149,34 +147,162 @@ def _merge_single_qubit_ops_to_phxz(
|
|
|
149
147
|
return gate.on(q)
|
|
150
148
|
|
|
151
149
|
|
|
152
|
-
def
|
|
153
|
-
|
|
154
|
-
|
|
150
|
+
def _backward_set_stopping_slots(
|
|
151
|
+
q: ops.Qid,
|
|
152
|
+
from_mid: int,
|
|
153
|
+
mergable: dict[ops.Qid, dict[int, bool]],
|
|
154
|
+
need_to_stop: dict[ops.Qid, dict[int, bool]],
|
|
155
|
+
gate_types: dict[ops.Qid, dict[int, _CellType]],
|
|
156
|
+
circuit: FrozenCircuit,
|
|
157
|
+
):
|
|
158
|
+
"""Sets stopping slots for dynamical decoupling insertion.
|
|
159
|
+
|
|
160
|
+
This function traverses backward from a given moment `from_mid` for a specific qubit `q`.
|
|
161
|
+
It identifies moments where a dynamical decoupling sequence needs to be "stopped".
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
q: The qubit for which to set stopping slots.
|
|
165
|
+
from_mid: The moment ID to start the backward traversal from.
|
|
166
|
+
mergable: A dictionary indicating if a single-qubit Clifford gate at (qubit, moment_id)
|
|
167
|
+
can be merged with a Pauli gate.
|
|
168
|
+
need_to_stop: A dictionary to mark moments where a DD sequence must be stopped.
|
|
169
|
+
gate_types: A dictionary indicating the type of gate at each (qubit, moment_id).
|
|
170
|
+
circuit: The original frozen circuit.
|
|
155
171
|
"""
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
172
|
+
affected_qubits: set[ops.Qid] = {q}
|
|
173
|
+
for back_mid in range(from_mid, -1, -1):
|
|
174
|
+
for back_q in set(affected_qubits):
|
|
175
|
+
if gate_types[back_q][back_mid] == _CellType.WALL:
|
|
176
|
+
affected_qubits.remove(back_q)
|
|
177
|
+
continue
|
|
178
|
+
if mergable[back_q][back_mid]:
|
|
179
|
+
need_to_stop[back_q][back_mid] = True
|
|
180
|
+
affected_qubits.remove(back_q)
|
|
181
|
+
continue
|
|
182
|
+
op_at_q = circuit[back_mid].operation_at(back_q) or ops.I(q)
|
|
183
|
+
affected_qubits.update(op_at_q.qubits)
|
|
184
|
+
if not affected_qubits:
|
|
185
|
+
break
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class _CellType(Enum):
|
|
189
|
+
UNKNOWN = '?'
|
|
190
|
+
# Non-insertable gates that cannot be pulled through
|
|
191
|
+
WALL = 'w'
|
|
192
|
+
# Clifford gates where Pauli Gates can be pulled through
|
|
193
|
+
DOOR = 'd'
|
|
194
|
+
# An empty gate can be used to insert Pauli gates from the dd sequence
|
|
195
|
+
INSERTABLE = 'i'
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@frozen
|
|
199
|
+
class _Grid:
|
|
200
|
+
"""A grid representation of the circuit where each gate position is labeled for
|
|
201
|
+
dynamical decoupling.
|
|
202
|
+
|
|
203
|
+
With this representation, a DD sequence can be automatically navigated in a
|
|
204
|
+
forward-only process. This avoids issues where a partially inserted DD
|
|
205
|
+
sequence encounters a "wall" and a new moment must be inserted because the
|
|
206
|
+
remaining DD sequence cannot be absorbed by nearby gates.
|
|
207
|
+
|
|
208
|
+
This labeled representation pre-calculates where DD pulses can be inserted
|
|
209
|
+
and where leftover DD sequences must be merged, avoiding the need for
|
|
210
|
+
backtracking.
|
|
211
|
+
|
|
212
|
+
An example labeled circuit is shown below:
|
|
213
|
+
| 0 | 1 | 2 | 3 | 4 |
|
|
214
|
+
-----+-----+-----+-----+-----+-----+
|
|
215
|
+
q(0) | d | i | i,s | d | w |
|
|
216
|
+
q(1) | d | i | d,s | w | w |
|
|
217
|
+
q(2) | d | d | d,s | w | w |
|
|
218
|
+
where `w`=WALL, `d`=DOOR, `i`=INSERTABLE. `s` represents a stop gate,
|
|
219
|
+
meaning that any unfinished DD sequences must be merged at this gate.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
gate_types: dict[ops.Qid, dict[int, _CellType]]
|
|
223
|
+
need_to_stop: dict[ops.Qid, dict[int, bool]]
|
|
224
|
+
circuit: FrozenCircuit
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def from_circuit(
|
|
228
|
+
cls, circuit: cirq.FrozenCircuit, single_qubit_gate_moments_only: bool
|
|
229
|
+
) -> _Grid:
|
|
230
|
+
gate_types: dict[ops.Qid, dict[int, _CellType]] = {
|
|
231
|
+
q: {mid: _CellType.UNKNOWN for mid in range(len(circuit))} for q in circuit.all_qubits()
|
|
232
|
+
}
|
|
233
|
+
mergable: dict[ops.Qid, dict[int, bool]] = {
|
|
234
|
+
q: {mid: False for mid in range(len(circuit))} for q in circuit.all_qubits()
|
|
235
|
+
}
|
|
236
|
+
busy_moment_range_by_qubit = _calc_busy_moment_range_of_each_qubit(circuit)
|
|
237
|
+
|
|
238
|
+
# Set gate types for each (q, mid)
|
|
239
|
+
for mid, moment in enumerate(circuit):
|
|
240
|
+
is_insertable_moment = (
|
|
241
|
+
not single_qubit_gate_moments_only or _is_single_qubit_gate_moment(moment)
|
|
242
|
+
)
|
|
243
|
+
for q in circuit.all_qubits():
|
|
244
|
+
if mid < busy_moment_range_by_qubit[q][0] or mid > busy_moment_range_by_qubit[q][1]:
|
|
245
|
+
gate_types[q][mid] = _CellType.WALL
|
|
246
|
+
continue
|
|
247
|
+
op_at_q = moment.operation_at(q)
|
|
248
|
+
if op_at_q is None:
|
|
249
|
+
if is_insertable_moment:
|
|
250
|
+
gate_types[q][mid] = _CellType.INSERTABLE
|
|
251
|
+
mergable[q][mid] = True
|
|
252
|
+
else:
|
|
253
|
+
gate_types[q][mid] = _CellType.DOOR
|
|
254
|
+
else:
|
|
255
|
+
if _is_clifford_op(op_at_q):
|
|
256
|
+
gate_types[q][mid] = _CellType.DOOR
|
|
257
|
+
mergable[q][mid] = _is_single_qubit_operation(op_at_q)
|
|
258
|
+
else:
|
|
259
|
+
gate_types[q][mid] = _CellType.WALL
|
|
260
|
+
|
|
261
|
+
need_to_stop: dict[ops.Qid, dict[int, bool]] = {
|
|
262
|
+
q: {mid: False for mid in range(len(circuit))} for q in circuit.all_qubits()
|
|
263
|
+
}
|
|
264
|
+
# Reversely find the last mergeable gate of each qubit, set them as need_to_stop.
|
|
265
|
+
for q in circuit.all_qubits():
|
|
266
|
+
_backward_set_stopping_slots(
|
|
267
|
+
q, len(circuit) - 1, mergable, need_to_stop, gate_types, circuit
|
|
268
|
+
)
|
|
269
|
+
# Reversely check for each wall gate, mark the closest mergeable gate as need_to_stop.
|
|
270
|
+
for mid in range(len(circuit)):
|
|
271
|
+
for q in circuit.all_qubits():
|
|
272
|
+
if gate_types[q][mid] == _CellType.WALL:
|
|
273
|
+
_backward_set_stopping_slots(
|
|
274
|
+
q, mid - 1, mergable, need_to_stop, gate_types, circuit
|
|
275
|
+
)
|
|
276
|
+
return cls(circuit=circuit, gate_types=gate_types, need_to_stop=need_to_stop)
|
|
160
277
|
|
|
278
|
+
def __str__(self) -> str:
|
|
279
|
+
if not self.gate_types:
|
|
280
|
+
return "Grid(empty)"
|
|
161
281
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
for op in moment:
|
|
165
|
-
if (not _is_clifford_op(op) and not _is_single_qubit_operation(op)) or not has_unitary(
|
|
166
|
-
op
|
|
167
|
-
): # multi-qubit clifford op or non-mergable op.
|
|
168
|
-
stop_pulling_through_qubits.update(op.qubits)
|
|
169
|
-
return stop_pulling_through_qubits
|
|
282
|
+
qubits = sorted(list(self.gate_types.keys()))
|
|
283
|
+
num_moments = len(self.gate_types[qubits[0]])
|
|
170
284
|
|
|
285
|
+
max_qubit_len = max(len(str(q)) for q in qubits) if qubits else 0
|
|
171
286
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
287
|
+
header = f"{'':>{max_qubit_len}} |"
|
|
288
|
+
for i in range(num_moments):
|
|
289
|
+
header += f" {i:^3} |"
|
|
290
|
+
|
|
291
|
+
separator = f"{'-' * max_qubit_len}-+"
|
|
292
|
+
separator += '-----+' * num_moments
|
|
293
|
+
|
|
294
|
+
lines = ["Grid Repr:", header, separator]
|
|
295
|
+
|
|
296
|
+
for q in qubits:
|
|
297
|
+
row_str = f"{str(q):>{max_qubit_len}} |"
|
|
298
|
+
for mid in range(num_moments):
|
|
299
|
+
gate_type = self.gate_types[q][mid].value
|
|
300
|
+
stop = self.need_to_stop[q][mid]
|
|
301
|
+
cell = f"{gate_type},s" if stop else f" {gate_type} "
|
|
302
|
+
row_str += f" {cell} |"
|
|
303
|
+
lines.append(row_str)
|
|
304
|
+
|
|
305
|
+
return "\n".join(lines)
|
|
180
306
|
|
|
181
307
|
|
|
182
308
|
@transformer_api.transformer
|
|
@@ -188,7 +314,7 @@ def add_dynamical_decoupling(
|
|
|
188
314
|
single_qubit_gate_moments_only: bool = True,
|
|
189
315
|
) -> cirq.Circuit:
|
|
190
316
|
"""Adds dynamical decoupling gate operations to a given circuit.
|
|
191
|
-
This transformer
|
|
317
|
+
This transformer preserves the structure of the original circuit.
|
|
192
318
|
|
|
193
319
|
Args:
|
|
194
320
|
circuit: Input circuit to transform.
|
|
@@ -202,11 +328,18 @@ def add_dynamical_decoupling(
|
|
|
202
328
|
Returns:
|
|
203
329
|
A copy of the input circuit with dynamical decoupling operations.
|
|
204
330
|
"""
|
|
205
|
-
|
|
331
|
+
|
|
332
|
+
if context is not None and context.deep:
|
|
333
|
+
raise ValueError("Deep transformation is not supported.")
|
|
334
|
+
|
|
206
335
|
orig_circuit = circuit.freeze()
|
|
207
336
|
|
|
208
|
-
|
|
337
|
+
grid = _Grid.from_circuit(orig_circuit, single_qubit_gate_moments_only)
|
|
338
|
+
|
|
339
|
+
if context is not None and context.logger is not None:
|
|
340
|
+
context.logger.log("Preprocessed input circuit grid repr:\n%s", str(grid))
|
|
209
341
|
|
|
342
|
+
base_dd_sequence, pauli_map = _parse_dd_sequence(schema)
|
|
210
343
|
# Stores all the moments of the output circuit chronologically.
|
|
211
344
|
transformed_moments: list[Moment] = []
|
|
212
345
|
# A PauliString stores the result of 'pulling' Pauli gates past each operations
|
|
@@ -215,90 +348,30 @@ def add_dynamical_decoupling(
|
|
|
215
348
|
# Iterator of gate to be used in dd sequence for each qubit.
|
|
216
349
|
dd_iter_by_qubits = {q: cycle(base_dd_sequence) for q in circuit.all_qubits()}
|
|
217
350
|
|
|
218
|
-
def _update_pulled_through(q: ops.Qid, insert_gate: ops.Gate) -> ops.Operation:
|
|
219
|
-
nonlocal pulled_through, pauli_map
|
|
220
|
-
pulled_through *= pauli_map[insert_gate].on(q)
|
|
221
|
-
return insert_gate.on(q)
|
|
222
|
-
|
|
223
|
-
# Insert and pull remaining Pauli ops through the whole circuit.
|
|
224
|
-
# General ideas are
|
|
225
|
-
# * Pull through Clifford gates.
|
|
226
|
-
# * Stop at multi-qubit non-Clifford ops (and other non-mergable ops).
|
|
227
|
-
# * Merge to single-qubit non-Clifford ops.
|
|
228
|
-
# * Insert a new moment if necessary.
|
|
229
|
-
# After pulling through pulled_through at `moment`, we expect a transformation of
|
|
230
|
-
# (pulled_through, moment) -> (updated_moment, updated_pulled_through) or
|
|
231
|
-
# (pulled_through, moment) -> (new_moment, updated_moment, updated_pulled_through)
|
|
232
|
-
# Moments structure changes are split into 3 steps:
|
|
233
|
-
# 1, (..., last_moment, pulled_through1, moment, ...)
|
|
234
|
-
# -> (..., last_moment, new_moment or None, pulled_through2, moment, ...)
|
|
235
|
-
# 2, (..., pulled_through2, moment, ...) -> (..., pulled_through3, updated_moment, ...)
|
|
236
|
-
# 3, (..., pulled_through3, updated_moment, ...)
|
|
237
|
-
# -> (..., updated_moment, pulled_through4, ...)
|
|
238
351
|
for moment_id, moment in enumerate(orig_circuit.moments):
|
|
239
|
-
# Step 1, insert new_moment if necessary.
|
|
240
|
-
# In detail: stop pulling through for multi-qubit non-Clifford ops or gates without
|
|
241
|
-
# unitary representation (e.g., measure gates). If there are remaining pulled through ops,
|
|
242
|
-
# insert into a new moment before current moment.
|
|
243
|
-
stop_pulling_through_qubits: set[ops.Qid] = _get_stop_qubits(moment)
|
|
244
|
-
new_moment_ops: list[ops.Operation] = []
|
|
245
|
-
for q in stop_pulling_through_qubits:
|
|
246
|
-
# Insert the remaining pulled_through
|
|
247
|
-
remaining_pulled_through_gate = pulled_through.get(q)
|
|
248
|
-
if remaining_pulled_through_gate is not None:
|
|
249
|
-
new_moment_ops.append(_update_pulled_through(q, remaining_pulled_through_gate))
|
|
250
|
-
# Reset dd sequence
|
|
251
|
-
dd_iter_by_qubits[q] = cycle(base_dd_sequence)
|
|
252
|
-
# Need to insert a new moment before current moment
|
|
253
|
-
if new_moment_ops:
|
|
254
|
-
# Fill insertable idle moments in the new moment using dd sequence
|
|
255
|
-
for q in orig_circuit.all_qubits() - stop_pulling_through_qubits:
|
|
256
|
-
if busy_moment_range_by_qubit[q][0] < moment_id <= busy_moment_range_by_qubit[q][1]:
|
|
257
|
-
new_moment_ops.append(_update_pulled_through(q, next(dd_iter_by_qubits[q])))
|
|
258
|
-
transformed_moments.append(Moment(new_moment_ops))
|
|
259
|
-
|
|
260
|
-
# Step 2, calc updated_moment with insertions / merges.
|
|
261
352
|
updated_moment_ops: set[cirq.Operation] = set()
|
|
262
353
|
for q in orig_circuit.all_qubits():
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
updated_op = _merge_single_qubit_ops_to_phxz(q, (remaining_op, op_at_q))
|
|
286
|
-
if updated_op is not None:
|
|
287
|
-
updated_moment_ops.add(updated_op)
|
|
288
|
-
|
|
289
|
-
if updated_moment_ops:
|
|
290
|
-
updated_moment = Moment(updated_moment_ops)
|
|
291
|
-
transformed_moments.append(updated_moment)
|
|
292
|
-
|
|
293
|
-
# Step 3, update pulled through.
|
|
294
|
-
# In detail: pulling current `pulled_through` through updated_moment.
|
|
295
|
-
pulled_through = _calc_pulled_through(updated_moment, pulled_through)
|
|
296
|
-
|
|
297
|
-
# Insert a new moment if there are remaining pulled-through operations.
|
|
298
|
-
ending_moment_ops = []
|
|
299
|
-
for affected_q, combined_op_in_pauli in pulled_through.items():
|
|
300
|
-
ending_moment_ops.append(combined_op_in_pauli.on(affected_q))
|
|
301
|
-
if ending_moment_ops:
|
|
302
|
-
transformed_moments.append(Moment(ending_moment_ops))
|
|
354
|
+
new_op_at_q = moment.operation_at(q)
|
|
355
|
+
if grid.gate_types[q][moment_id] == _CellType.INSERTABLE:
|
|
356
|
+
new_gate = next(dd_iter_by_qubits[q])
|
|
357
|
+
new_op_at_q = new_gate.on(q)
|
|
358
|
+
pulled_through *= pauli_map[new_gate].on(q)
|
|
359
|
+
if grid.need_to_stop[q][moment_id]:
|
|
360
|
+
to_be_merged = pulled_through.get(q)
|
|
361
|
+
if to_be_merged is not None:
|
|
362
|
+
new_op_at_q = _merge_single_qubit_ops_to_phxz(
|
|
363
|
+
q, (to_be_merged.on(q), new_op_at_q or ops.I(q))
|
|
364
|
+
)
|
|
365
|
+
pulled_through *= to_be_merged.on(q)
|
|
366
|
+
if new_op_at_q is not None:
|
|
367
|
+
updated_moment_ops.add(new_op_at_q)
|
|
368
|
+
|
|
369
|
+
updated_moment = Moment(updated_moment_ops)
|
|
370
|
+
clifford_ops = [op for op in updated_moment if _is_clifford_op(op)]
|
|
371
|
+
pulled_through = pulled_through.after(clifford_ops)
|
|
372
|
+
transformed_moments.append(updated_moment)
|
|
373
|
+
|
|
374
|
+
if len(pulled_through) > 0:
|
|
375
|
+
raise RuntimeError("Expect empty remaining Paulis after the dd insertion.")
|
|
303
376
|
|
|
304
377
|
return Circuit.from_moments(*transformed_moments)
|
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
from typing import Sequence
|
|
18
|
+
from unittest import mock
|
|
18
19
|
|
|
19
20
|
import numpy as np
|
|
20
21
|
import pytest
|
|
21
22
|
|
|
22
23
|
import cirq
|
|
23
24
|
from cirq import add_dynamical_decoupling, CNOT, CZ, CZPowGate, H, X, Y, Z
|
|
25
|
+
from cirq.transformers.dynamical_decoupling import _CellType, _Grid
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
def assert_sim_eq(circuit1: cirq.AbstractCircuit, circuit2: cirq.AbstractCircuit) -> None:
|
|
@@ -163,10 +165,6 @@ def test_pull_through_h_gate_case1(single_qubit_gate_moments_only: bool) -> None
|
|
|
163
165
|
a: ───H───────H───────@───
|
|
164
166
|
│
|
|
165
167
|
b: ───H───H───H───H───X───
|
|
166
|
-
Output:
|
|
167
|
-
a: ───H───X───H───X───@───Y───
|
|
168
|
-
│
|
|
169
|
-
b: ───H───H───H───H───X───X───
|
|
170
168
|
"""
|
|
171
169
|
a = cirq.NamedQubit('a')
|
|
172
170
|
b = cirq.NamedQubit('b')
|
|
@@ -179,14 +177,11 @@ def test_pull_through_h_gate_case1(single_qubit_gate_moments_only: bool) -> None
|
|
|
179
177
|
cirq.Moment(H(b)),
|
|
180
178
|
cirq.Moment(CNOT(a, b)),
|
|
181
179
|
),
|
|
182
|
-
expected_circuit=
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
cirq.Moment(CNOT(a, b)),
|
|
188
|
-
cirq.Moment(Y(a), X(b)),
|
|
189
|
-
),
|
|
180
|
+
expected_circuit="""
|
|
181
|
+
a: ───H───X───H───PhXZ(a=-0.5,x=0,z=-1)───@───
|
|
182
|
+
│
|
|
183
|
+
b: ───H───H───H───H───────────────────────X───
|
|
184
|
+
""",
|
|
190
185
|
schema="XX_PAIR",
|
|
191
186
|
single_qubit_gate_moments_only=single_qubit_gate_moments_only,
|
|
192
187
|
)
|
|
@@ -199,10 +194,6 @@ def test_pull_through_h_gate_case2(single_qubit_gate_moments_only: bool) -> None
|
|
|
199
194
|
a: ───H───────H───────H───
|
|
200
195
|
|
|
201
196
|
b: ───H───H───H───H───H───
|
|
202
|
-
Output:
|
|
203
|
-
a: ───H───X───H───X───PhXZ(a=0.5,x=0.5,z=1)───
|
|
204
|
-
|
|
205
|
-
b: ───H───H───H───H───H───────────────────────
|
|
206
197
|
"""
|
|
207
198
|
a = cirq.NamedQubit('a')
|
|
208
199
|
b = cirq.NamedQubit('b')
|
|
@@ -215,15 +206,11 @@ def test_pull_through_h_gate_case2(single_qubit_gate_moments_only: bool) -> None
|
|
|
215
206
|
cirq.Moment(H(b)),
|
|
216
207
|
cirq.Moment(H(a), H(b)),
|
|
217
208
|
),
|
|
218
|
-
expected_circuit=
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
cirq.Moment(
|
|
224
|
-
cirq.PhasedXZGate(axis_phase_exponent=0.5, x_exponent=0.5, z_exponent=1).on(a), H(b)
|
|
225
|
-
),
|
|
226
|
-
),
|
|
209
|
+
expected_circuit="""
|
|
210
|
+
a: ───H───X───H───X───PhXZ(a=0.5,x=0.5,z=-1)───
|
|
211
|
+
|
|
212
|
+
b: ───H───H───H───H───H────────────────────────
|
|
213
|
+
""",
|
|
227
214
|
schema="XX_PAIR",
|
|
228
215
|
single_qubit_gate_moments_only=single_qubit_gate_moments_only,
|
|
229
216
|
)
|
|
@@ -444,24 +431,6 @@ def test_scattered_circuit2() -> None:
|
|
|
444
431
|
7: ───────────────@───@───
|
|
445
432
|
│
|
|
446
433
|
8: ───────────────────@───
|
|
447
|
-
Output:
|
|
448
|
-
0: ───────────────────@───
|
|
449
|
-
│
|
|
450
|
-
1: ───────────────@───@───
|
|
451
|
-
│
|
|
452
|
-
2: ───────────@───@───────
|
|
453
|
-
│
|
|
454
|
-
3: ───────@───@───────────
|
|
455
|
-
│
|
|
456
|
-
4: ───@───@───────────────
|
|
457
|
-
│
|
|
458
|
-
5: ───@───X───@───X───────
|
|
459
|
-
│
|
|
460
|
-
6: ───────────@───@───Z───
|
|
461
|
-
│
|
|
462
|
-
7: ───────────────@───@───
|
|
463
|
-
│
|
|
464
|
-
8: ───────────────────@───
|
|
465
434
|
"""
|
|
466
435
|
qubits = cirq.LineQubit.range(9)
|
|
467
436
|
assert_dd(
|
|
@@ -472,13 +441,25 @@ def test_scattered_circuit2() -> None:
|
|
|
472
441
|
cirq.Moment(CZ(*qubits[1:3]), CZ(*qubits[6:8])),
|
|
473
442
|
cirq.Moment(CZ(*qubits[0:2]), CZ(*qubits[7:])),
|
|
474
443
|
),
|
|
475
|
-
expected_circuit=
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
444
|
+
expected_circuit="""
|
|
445
|
+
0: ───────────────────@───
|
|
446
|
+
│
|
|
447
|
+
1: ───────────────@───@───
|
|
448
|
+
│
|
|
449
|
+
2: ───────────@───@───────
|
|
450
|
+
│
|
|
451
|
+
3: ───────@───@───────────
|
|
452
|
+
│
|
|
453
|
+
4: ───@───@───────────────
|
|
454
|
+
│
|
|
455
|
+
5: ───@───I───@───────────
|
|
456
|
+
│
|
|
457
|
+
6: ───────────@───@───────
|
|
458
|
+
│
|
|
459
|
+
7: ───────────────@───@───
|
|
460
|
+
│
|
|
461
|
+
8: ───────────────────@───
|
|
462
|
+
""",
|
|
482
463
|
schema="XX_PAIR",
|
|
483
464
|
single_qubit_gate_moments_only=False,
|
|
484
465
|
)
|
|
@@ -494,14 +475,6 @@ def test_pull_through_chain() -> None:
|
|
|
494
475
|
2: ───────────────×───×───X───
|
|
495
476
|
│
|
|
496
477
|
3: ───────────────────×───X───
|
|
497
|
-
Output:
|
|
498
|
-
0: ───X───X───×───X───X───X───
|
|
499
|
-
│
|
|
500
|
-
1: ───────Y───×───×───X───I───
|
|
501
|
-
│
|
|
502
|
-
2: ───────────────×───×───X───
|
|
503
|
-
│
|
|
504
|
-
3: ───────────────────×───I───
|
|
505
478
|
"""
|
|
506
479
|
qubits = cirq.LineQubit.range(4)
|
|
507
480
|
assert_dd(
|
|
@@ -513,14 +486,15 @@ def test_pull_through_chain() -> None:
|
|
|
513
486
|
cirq.Moment(cirq.SWAP(*qubits[2:4])),
|
|
514
487
|
cirq.Moment([X(qubits[i]) for i in range(4)]),
|
|
515
488
|
),
|
|
516
|
-
expected_circuit=
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
489
|
+
expected_circuit="""
|
|
490
|
+
0: ───X───X───×───X───X───X───
|
|
491
|
+
│
|
|
492
|
+
1: ───────Y───×───×───X───I───
|
|
493
|
+
│
|
|
494
|
+
2: ───────────────×───×───X───
|
|
495
|
+
│
|
|
496
|
+
3: ───────────────────×───I───
|
|
497
|
+
""",
|
|
524
498
|
schema='XX_PAIR',
|
|
525
499
|
single_qubit_gate_moments_only=False,
|
|
526
500
|
)
|
|
@@ -532,10 +506,6 @@ def test_multiple_clifford_pieces_case1() -> None:
|
|
|
532
506
|
a: ───H───────H───────@───────────H───────H───
|
|
533
507
|
│
|
|
534
508
|
b: ───H───H───H───H───@^0.5───H───H───H───H───
|
|
535
|
-
Output:
|
|
536
|
-
a: ───H───X───H───X───Y───@───────X───H───X───PhXZ(a=0.5,x=0.5,z=-1)───
|
|
537
|
-
│
|
|
538
|
-
b: ───H───H───H───H───────@^0.5───H───H───H───H────────────────────────
|
|
539
509
|
"""
|
|
540
510
|
a = cirq.NamedQubit('a')
|
|
541
511
|
b = cirq.NamedQubit('b')
|
|
@@ -552,9 +522,9 @@ def test_multiple_clifford_pieces_case1() -> None:
|
|
|
552
522
|
cirq.Moment(H(a), H(b)),
|
|
553
523
|
),
|
|
554
524
|
expected_circuit="""
|
|
555
|
-
a: ───H───X───H───
|
|
556
|
-
|
|
557
|
-
b: ───H───H───H───H
|
|
525
|
+
a: ───H───X───H───PhXZ(a=-0.5,x=0,z=-1)───@───────X───H───X───PhXZ(a=0.5,x=0.5,z=-1)───
|
|
526
|
+
│
|
|
527
|
+
b: ───H───H───H───H───────────────────────@^0.5───H───H───H───H────────────────────────
|
|
558
528
|
""",
|
|
559
529
|
schema="XX_PAIR",
|
|
560
530
|
)
|
|
@@ -566,10 +536,6 @@ def test_multiple_clifford_pieces_case2() -> None:
|
|
|
566
536
|
a: ───@───PhXZ(a=0.3,x=0.2,z=0)───PhXZ(a=0.3,x=0.2,z=0)───PhXZ(a=0.3,x=0.2,z=0)───@───
|
|
567
537
|
│ │
|
|
568
538
|
b: ───@───────────────────────────────────────────────────────────────────────────@───
|
|
569
|
-
Output:
|
|
570
|
-
a: ───@───PhXZ(a=0.3,x=0.2,z=0)───PhXZ(a=0.3,x=0.2,z=0)───PhXZ(a=0.3,x=0.2,z=0)───@───Z───
|
|
571
|
-
│ │
|
|
572
|
-
b: ───@───X───────────────────────X───────────────────────X───────────────────────@───X───
|
|
573
539
|
"""
|
|
574
540
|
a = cirq.NamedQubit('a')
|
|
575
541
|
b = cirq.NamedQubit('b')
|
|
@@ -583,20 +549,17 @@ def test_multiple_clifford_pieces_case2() -> None:
|
|
|
583
549
|
cirq.Moment(phased_xz_gate.on(a)),
|
|
584
550
|
cirq.Moment(CZ(a, b)),
|
|
585
551
|
),
|
|
586
|
-
expected_circuit=
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
cirq.Moment(CZ(a, b)),
|
|
592
|
-
cirq.Moment(Z(a), X(b)),
|
|
593
|
-
),
|
|
552
|
+
expected_circuit="""
|
|
553
|
+
a: ───@───PhXZ(a=0.3,x=0.2,z=0)───PhXZ(a=0.3,x=0.2,z=0)───PhXZ(a=0.3,x=0.2,z=0)───@───
|
|
554
|
+
│ │
|
|
555
|
+
b: ───@───X───────────────────────X───────────────────────I───────────────────────@───
|
|
556
|
+
""",
|
|
594
557
|
schema='XX_PAIR',
|
|
595
558
|
single_qubit_gate_moments_only=False,
|
|
596
559
|
)
|
|
597
560
|
|
|
598
561
|
|
|
599
|
-
def
|
|
562
|
+
def test_absorb_remaining_dd_sequence() -> None:
|
|
600
563
|
"""Test case diagrams.
|
|
601
564
|
Input:
|
|
602
565
|
a: ───H───────H───@───@───────
|
|
@@ -604,12 +567,6 @@ def test_insert_new_moment() -> None:
|
|
|
604
567
|
b: ───H───H───H───X───@^0.5───
|
|
605
568
|
|
|
606
569
|
c: ───H───────────────H───────
|
|
607
|
-
Output:
|
|
608
|
-
a: ───H───X───H───@───Z───@────────────────────────
|
|
609
|
-
│ │
|
|
610
|
-
b: ───H───H───H───X───────@^0.5────────────────────
|
|
611
|
-
|
|
612
|
-
c: ───H───X───X───────X───PhXZ(a=-0.5,x=0.5,z=0)───
|
|
613
570
|
"""
|
|
614
571
|
a = cirq.NamedQubit('a')
|
|
615
572
|
b = cirq.NamedQubit('b')
|
|
@@ -622,17 +579,13 @@ def test_insert_new_moment() -> None:
|
|
|
622
579
|
cirq.Moment(CNOT(a, b)),
|
|
623
580
|
cirq.Moment(CZPowGate(exponent=0.5).on(a, b), H(c)),
|
|
624
581
|
),
|
|
625
|
-
expected_circuit=
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
CZPowGate(exponent=0.5).on(a, b),
|
|
633
|
-
cirq.PhasedXZGate(axis_phase_exponent=-0.5, x_exponent=0.5, z_exponent=0).on(c),
|
|
634
|
-
),
|
|
635
|
-
),
|
|
582
|
+
expected_circuit="""
|
|
583
|
+
a: ───H───X───PhXZ(a=-0.5,x=0.5,z=0)───@───@───────
|
|
584
|
+
│ │
|
|
585
|
+
b: ───H───H───H────────────────────────X───@^0.5───
|
|
586
|
+
|
|
587
|
+
c: ───H───X───X────────────────────────────H───────
|
|
588
|
+
""",
|
|
636
589
|
schema="XX_PAIR",
|
|
637
590
|
)
|
|
638
591
|
|
|
@@ -659,13 +612,13 @@ def test_with_non_clifford_measurements() -> None:
|
|
|
659
612
|
cirq.Moment([cirq.M(qubits[i]) for i in [0, 1, 2, 3]]),
|
|
660
613
|
),
|
|
661
614
|
expected_circuit="""
|
|
662
|
-
0: ───────────H───@───
|
|
615
|
+
0: ───────────H───@───PhXZ(a=0.5,x=0.5,z=0)───M───
|
|
663
616
|
│
|
|
664
|
-
1: ───H───@───X───@───X
|
|
617
|
+
1: ───H───@───X───@───X───────────────────────M───
|
|
665
618
|
│
|
|
666
|
-
2: ───H───@───H───@───
|
|
619
|
+
2: ───H───@───H───@───I───────────────────────M───
|
|
667
620
|
│
|
|
668
|
-
3: ───────────H───@───H
|
|
621
|
+
3: ───────────H───@───H───────────────────────M───
|
|
669
622
|
""",
|
|
670
623
|
schema="XX_PAIR",
|
|
671
624
|
single_qubit_gate_moments_only=True,
|
|
@@ -688,21 +641,6 @@ def test_cross_clifford_pieces_filling_merge() -> None:
|
|
|
688
641
|
5: ───PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───H───
|
|
689
642
|
│
|
|
690
643
|
6: ───────────────────────────────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)─────────────────────────────@───PhXZ(a=0.2,x=0.2,z=0.1)───H───
|
|
691
|
-
Output:
|
|
692
|
-
|
|
693
|
-
0: ─────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)─────H────────────────────────
|
|
694
|
-
│ │
|
|
695
|
-
1: ─────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)─────H────────────────────────
|
|
696
|
-
|
|
697
|
-
2: ───PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───X───────────────────────────PhXZ(a=0.5,x=0.5,z=-1)───
|
|
698
|
-
│ │ │
|
|
699
|
-
3: ─────────────────────────────┼───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────X─────────────────────────@───Y───────────────────────────PhXZ(a=0.5,x=0.5,z=0)────
|
|
700
|
-
│
|
|
701
|
-
4: ─────────────────────────────┼─────────────────────────────@─────────────────────────X─────────────────────────────Y───────────────────────────PhXZ(a=0.5,x=0.5,z=0)────
|
|
702
|
-
│ │
|
|
703
|
-
5: ───PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=-0.8,x=0.2,z=-0.9)───H────────────────────────
|
|
704
|
-
│
|
|
705
|
-
6: ───────────────────────────────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───X─────────────────────────@───PhXZ(a=0.8,x=0.8,z=0.5)─────H────────────────────────
|
|
706
644
|
""" # noqa: E501
|
|
707
645
|
qubits = cirq.LineQubit.range(7)
|
|
708
646
|
phased_xz_gate = cirq.PhasedXZGate(axis_phase_exponent=0.2, x_exponent=0.2, z_exponent=0.1)
|
|
@@ -721,30 +659,31 @@ def test_cross_clifford_pieces_filling_merge() -> None:
|
|
|
721
659
|
cirq.Moment([H.on(q) for q in qubits]),
|
|
722
660
|
),
|
|
723
661
|
expected_circuit="""
|
|
724
|
-
0: ─────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)
|
|
662
|
+
0: ─────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───H────────────────────────
|
|
725
663
|
│ │
|
|
726
|
-
1: ─────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)
|
|
664
|
+
1: ─────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───H────────────────────────
|
|
727
665
|
|
|
728
|
-
2: ───PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───X
|
|
666
|
+
2: ───PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───X─────────────────────────PhXZ(a=0.5,x=0.5,z=-1)───
|
|
729
667
|
│ │ │
|
|
730
|
-
3: ─────────────────────────────┼───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────X─────────────────────────@───Y
|
|
668
|
+
3: ─────────────────────────────┼───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────X─────────────────────────@───Y─────────────────────────PhXZ(a=0.5,x=0.5,z=0)────
|
|
731
669
|
│
|
|
732
|
-
4: ─────────────────────────────┼─────────────────────────────@─────────────────────────X─────────────────────────────Y
|
|
670
|
+
4: ─────────────────────────────┼─────────────────────────────@─────────────────────────X─────────────────────────────Y─────────────────────────PhXZ(a=0.5,x=0.5,z=0)────
|
|
733
671
|
│ │
|
|
734
|
-
5: ───PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a
|
|
672
|
+
5: ───PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───@─────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───@───PhXZ(a=0.2,x=0.2,z=0.1)───H────────────────────────
|
|
735
673
|
│
|
|
736
|
-
6: ───────────────────────────────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───
|
|
674
|
+
6: ───────────────────────────────────────────────────────────PhXZ(a=0.2,x=0.2,z=0.1)───I─────────────────────────@───PhXZ(a=0.2,x=0.2,z=0.1)───H────────────────────────
|
|
737
675
|
""", # noqa: E501
|
|
738
676
|
)
|
|
739
677
|
|
|
740
678
|
|
|
741
679
|
def test_pull_through_phxz_gate_case1() -> None:
|
|
742
680
|
"""Test case diagrams.
|
|
743
|
-
|
|
681
|
+
|
|
682
|
+
Input:
|
|
744
683
|
a: ───H───────PhXZ(a=0.25,x=-1,z=0)───────@───
|
|
745
684
|
│
|
|
746
685
|
b: ───H───H───H───────────────────────H───X───
|
|
747
|
-
|
|
686
|
+
Output: expected circuit diagram below.
|
|
748
687
|
"""
|
|
749
688
|
a = cirq.NamedQubit('a')
|
|
750
689
|
b = cirq.NamedQubit('b')
|
|
@@ -759,9 +698,9 @@ def test_pull_through_phxz_gate_case1() -> None:
|
|
|
759
698
|
cirq.Moment(CNOT(a, b)),
|
|
760
699
|
),
|
|
761
700
|
expected_circuit="""
|
|
762
|
-
a: ───H───X───PhXZ(a=0.25,x=-1,z=0)───
|
|
763
|
-
|
|
764
|
-
b: ───H───H───H───────────────────────H───
|
|
701
|
+
a: ───H───X───PhXZ(a=0.25,x=-1,z=0)───PhXZ(a=0.5,x=1,z=0)───@───
|
|
702
|
+
│
|
|
703
|
+
b: ───H───H───H───────────────────────H─────────────────────X───
|
|
765
704
|
""",
|
|
766
705
|
schema="XX_PAIR",
|
|
767
706
|
)
|
|
@@ -769,11 +708,12 @@ b: ───H───H───H───────────────
|
|
|
769
708
|
|
|
770
709
|
def test_pull_through_phxz_gate_case2() -> None:
|
|
771
710
|
"""Test case diagrams.
|
|
772
|
-
|
|
711
|
+
|
|
712
|
+
Input:
|
|
773
713
|
a: ───H───────PhXZ(a=0.2,x=-1,z=0)───────@───
|
|
774
714
|
│
|
|
775
715
|
b: ───H───H───H───────────────────────H───X───
|
|
776
|
-
|
|
716
|
+
Output: expected circuit diagram below.
|
|
777
717
|
"""
|
|
778
718
|
a = cirq.NamedQubit('a')
|
|
779
719
|
b = cirq.NamedQubit('b')
|
|
@@ -788,9 +728,9 @@ def test_pull_through_phxz_gate_case2() -> None:
|
|
|
788
728
|
cirq.Moment(CNOT(a, b)),
|
|
789
729
|
),
|
|
790
730
|
expected_circuit="""
|
|
791
|
-
a: ───H───
|
|
792
|
-
|
|
793
|
-
b: ───H───H───H
|
|
731
|
+
a: ───H───I───PhXZ(a=0.2,x=-1,z=0)───I───@───
|
|
732
|
+
│
|
|
733
|
+
b: ───H───H───H──────────────────────H───X───
|
|
794
734
|
""",
|
|
795
735
|
schema="XX_PAIR",
|
|
796
736
|
)
|
|
@@ -819,58 +759,112 @@ def test_merge_before_non_cliffords() -> None:
|
|
|
819
759
|
assert_dd(
|
|
820
760
|
input_circuit=input_circuit,
|
|
821
761
|
expected_circuit="""
|
|
822
|
-
0: ───X───X───X
|
|
762
|
+
0: ───X───X───X──────────────────────────────────────────M───
|
|
823
763
|
|
|
824
|
-
1: ───X───X───PhXZ(a=-1,x=
|
|
825
|
-
|
|
826
|
-
2: ───X───X───S
|
|
764
|
+
1: ───X───X───PhXZ(a=-1.25,x=1,z=0)───FSim(0, 0.0637π)───M───
|
|
765
|
+
│
|
|
766
|
+
2: ───X───X───S───────────────────────FSim(0, 0.0637π)───M───
|
|
827
767
|
""",
|
|
828
768
|
schema="XX_PAIR",
|
|
829
769
|
)
|
|
830
770
|
|
|
831
771
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
[
|
|
835
|
-
(
|
|
836
|
-
True,
|
|
837
|
-
# With single_qubit_gate_moments_only=True, the second DD gate on q2
|
|
838
|
-
# is inserted in a new moment after the CZ gate.
|
|
839
|
-
"""
|
|
840
|
-
0: ───X───X───@───────M───
|
|
841
|
-
│
|
|
842
|
-
1: ───X───X───@───────M───
|
|
772
|
+
def test_runtime_error_if_pulled_through_not_empty_mocked() -> None:
|
|
773
|
+
"""Tests that a RuntimeError is raised if pulled_through is not empty at the end.
|
|
843
774
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
│
|
|
854
|
-
1: ───X───X───@───M───
|
|
775
|
+
This test explicitly mocks the internal state to simulate a scenario where
|
|
776
|
+
the `pulled_through` PauliString is not empty after processing all moments.
|
|
777
|
+
Under normal operation, the `_Grid` and `add_dynamical_decoupling`
|
|
778
|
+
logic should ensure `pulled_through` is always empty at the end, making
|
|
779
|
+
this RuntimeError theoretically unreachable. This test verifies the
|
|
780
|
+
defensive check itself.
|
|
781
|
+
"""
|
|
782
|
+
q0: cirq.Qid = cirq.NamedQubit('q0')
|
|
783
|
+
circuit = cirq.FrozenCircuit(cirq.Moment(cirq.I(q0))) # A minimal circuit
|
|
855
784
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
785
|
+
# Create a mock _Grid instance that would lead to an unabsorbed Pauli.
|
|
786
|
+
# We need an INSERTABLE slot, but no STOP label, and no self-cancellation.
|
|
787
|
+
# To achieve this, we'll mock the `pulled_through.after` method to *not* clear it.
|
|
788
|
+
# This is a deep mock to hit the specific RuntimeError line.
|
|
789
|
+
|
|
790
|
+
# First, create a _Grid that allows insertion but no stopping.
|
|
791
|
+
# This is a hypothetical scenario that `_Grid.from_circuit` should prevent.
|
|
792
|
+
mock_gate_types = {q0: {0: _CellType.INSERTABLE}}
|
|
793
|
+
mock_need_to_stop = {q0: {0: False}} # Crucially, no stop gate
|
|
794
|
+
|
|
795
|
+
mock_labeled_circuit = _Grid(
|
|
796
|
+
gate_types=mock_gate_types, need_to_stop=mock_need_to_stop, circuit=circuit
|
|
797
|
+
)
|
|
798
|
+
|
|
799
|
+
# Mock _Grid.from_circuit to return our custom mock
|
|
800
|
+
with mock.patch(
|
|
801
|
+
'cirq.transformers.dynamical_decoupling._Grid.from_circuit',
|
|
802
|
+
return_value=mock_labeled_circuit,
|
|
803
|
+
):
|
|
804
|
+
# Mock the PauliString.after method to ensure `pulled_through` remains non-empty.
|
|
805
|
+
with mock.patch('cirq.ops.PauliString.after', return_value=cirq.PauliString({q0: cirq.X})):
|
|
806
|
+
with pytest.raises(
|
|
807
|
+
RuntimeError, match="Expect empty remaining Paulis after the dd insertion."
|
|
808
|
+
):
|
|
809
|
+
add_dynamical_decoupling(
|
|
810
|
+
circuit, schema='XX_PAIR', single_qubit_gate_moments_only=True
|
|
811
|
+
)
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
def test_labeled_circuit_str():
|
|
815
|
+
"""Input circuit:
|
|
816
|
+
0: ───X──────────────────────────────────────────────────M───
|
|
817
|
+
|
|
818
|
+
1: ───X───────PhXZ(a=-1,x=0,z=-0.5)───FSim(0, 0.0637π)───M───
|
|
819
|
+
│
|
|
820
|
+
2: ───X───X───S───────────────────────FSim(0, 0.0637π)───M───
|
|
821
|
+
"""
|
|
864
822
|
q0, q1, q2 = cirq.LineQubit.range(3)
|
|
865
823
|
input_circuit = cirq.Circuit(
|
|
866
824
|
cirq.Moment([X(q) for q in [q0, q1, q2]]),
|
|
867
|
-
cirq.Moment(
|
|
868
|
-
cirq.Moment(
|
|
825
|
+
cirq.Moment(X(q2)),
|
|
826
|
+
cirq.Moment(
|
|
827
|
+
cirq.PhasedXZGate(axis_phase_exponent=-1, x_exponent=0, z_exponent=-0.5).on(q1),
|
|
828
|
+
(Z**0.5).on(q2),
|
|
829
|
+
),
|
|
830
|
+
cirq.Moment(cirq.FSimGate(theta=0, phi=0.2).on(q1, q2)),
|
|
869
831
|
cirq.Moment([cirq.M(q) for q in [q0, q1, q2]]),
|
|
870
832
|
)
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
833
|
+
labeled_circuit = _Grid.from_circuit(input_circuit, single_qubit_gate_moments_only=True)
|
|
834
|
+
assert str(labeled_circuit) == (
|
|
835
|
+
"""Grid Repr:
|
|
836
|
+
| 0 | 1 | 2 | 3 | 4 |
|
|
837
|
+
-----+-----+-----+-----+-----+-----+
|
|
838
|
+
q(0) | d | i | i,s | d | w |
|
|
839
|
+
q(1) | d | i | d,s | w | w |
|
|
840
|
+
q(2) | d | d | d,s | w | w |"""
|
|
876
841
|
)
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
def test_labeled_circuit_str_empty():
|
|
845
|
+
"""Tests the __str__ method of _Grid for empty and no-qubit circuits."""
|
|
846
|
+
# Test case for an empty circuit (no moments, no qubits)
|
|
847
|
+
empty_circuit = cirq.Circuit()
|
|
848
|
+
labeled_empty = _Grid.from_circuit(empty_circuit, single_qubit_gate_moments_only=True)
|
|
849
|
+
assert str(labeled_empty) == "Grid(empty)"
|
|
850
|
+
|
|
851
|
+
|
|
852
|
+
def test_add_dynamical_decoupling_with_deep_context_raises_error():
|
|
853
|
+
"""Tests that add_dynamical_decoupling raises an error with deep context."""
|
|
854
|
+
q = cirq.NamedQubit('q')
|
|
855
|
+
circuit = cirq.Circuit(cirq.H(q))
|
|
856
|
+
context = cirq.TransformerContext(deep=True)
|
|
857
|
+
with pytest.raises(ValueError, match="Deep transformation is not supported."):
|
|
858
|
+
add_dynamical_decoupling(circuit, context=context)
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
def test_context_logger():
|
|
862
|
+
q = cirq.NamedQubit('q')
|
|
863
|
+
circuit = cirq.Circuit(cirq.H(q))
|
|
864
|
+
mock_logger = mock.MagicMock(spec=cirq.TransformerLogger)
|
|
865
|
+
context = cirq.TransformerContext(logger=mock_logger)
|
|
866
|
+
|
|
867
|
+
add_dynamical_decoupling(circuit, context=context)
|
|
868
|
+
|
|
869
|
+
mock_logger.log.assert_called_once()
|
|
870
|
+
assert "Preprocessed input circuit grid repr:" in mock_logger.log.call_args[0][0]
|
cirq/value/digits.py
CHANGED
|
@@ -168,6 +168,11 @@ def big_endian_int_to_digits(
|
|
|
168
168
|
>>> cirq.big_endian_int_to_digits(11, base=[2, 3, 4])
|
|
169
169
|
[0, 2, 3]
|
|
170
170
|
"""
|
|
171
|
+
if digit_count and base == 2:
|
|
172
|
+
binary_chars = bin(val).removeprefix('0b')
|
|
173
|
+
zeros_count = digit_count - len(binary_chars)
|
|
174
|
+
if zeros_count >= 0:
|
|
175
|
+
return [0] * zeros_count + [1 if c == "1" else 0 for c in binary_chars]
|
|
171
176
|
if isinstance(base, int):
|
|
172
177
|
if digit_count is None:
|
|
173
178
|
raise ValueError('No digit count. Provide `digit_count` when base is an int.')
|
|
@@ -192,4 +197,5 @@ def big_endian_int_to_digits(
|
|
|
192
197
|
f'left behind {val!r} instead of 0.'
|
|
193
198
|
)
|
|
194
199
|
|
|
195
|
-
|
|
200
|
+
result.reverse()
|
|
201
|
+
return result
|
{cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cirq-core
|
|
3
|
-
Version: 1.7.0.
|
|
3
|
+
Version: 1.7.0.dev20251028035559
|
|
4
4
|
Summary: A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
|
|
5
5
|
Home-page: http://github.com/quantumlib/cirq
|
|
6
6
|
Author: The Cirq Developers
|
{cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/RECORD
RENAMED
|
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=emXpdD5ZvwLRlFAoQB8YatmZyU3b4e9jg6FppMTUhkU,33900
|
|
|
4
4
|
cirq/_doc.py,sha256=28ZskY9ZtZ_4GS1oXPUgklKnJqmAE-rkUfzcsJ0--nA,2941
|
|
5
5
|
cirq/_import.py,sha256=ixBu4EyGl46Ram2cP3p5eZVEFDW5L2DS-VyTjz4N9iw,8429
|
|
6
6
|
cirq/_import_test.py,sha256=oF4izzOVZLc7NZ0aZHFcGv-r01eiFFt_JORx_x7_D4s,1089
|
|
7
|
-
cirq/_version.py,sha256=
|
|
8
|
-
cirq/_version_test.py,sha256=
|
|
7
|
+
cirq/_version.py,sha256=hwKIrLaPuF0ICgE1qbNArfVRn9cZA8_8VnpdaPSokDM,1206
|
|
8
|
+
cirq/_version_test.py,sha256=kvN_UM8XK-zjfJ6SXpp97upPv198bIXsvNPxFrqa4GI,155
|
|
9
9
|
cirq/conftest.py,sha256=wSDKNdIQRDfLnXvOCWD3erheOw8JHRhdfQ53EyTUIXg,1239
|
|
10
10
|
cirq/json_resolver_cache.py,sha256=A5DIgFAY1hUNt9vai_C3-gGBv24116CJMzQxMcXOax4,13726
|
|
11
11
|
cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
|
|
@@ -1078,8 +1078,8 @@ cirq/transformers/drop_empty_moments.py,sha256=uZJG9FpUNyA1Mi0xLDuVuhj_siZhPZ1_s
|
|
|
1078
1078
|
cirq/transformers/drop_empty_moments_test.py,sha256=h6Pji0z0o9KOB7fnSHseWpIAhzvxWurF_flg9XWm_YI,1959
|
|
1079
1079
|
cirq/transformers/drop_negligible_operations.py,sha256=eP2dP_n0BYlr8aZ1wnD8YWsqCtwN0l0O6p45RbXEpfM,2097
|
|
1080
1080
|
cirq/transformers/drop_negligible_operations_test.py,sha256=LrZDDITL5dskTywIahZqZBWnIXAJqNAjOgd4EYfrYTA,3908
|
|
1081
|
-
cirq/transformers/dynamical_decoupling.py,sha256=
|
|
1082
|
-
cirq/transformers/dynamical_decoupling_test.py,sha256=
|
|
1081
|
+
cirq/transformers/dynamical_decoupling.py,sha256=H0sOVKce3-NV-B8onp_S-mWU50EFJ9GJxJqKpQrYoCU,15113
|
|
1082
|
+
cirq/transformers/dynamical_decoupling_test.py,sha256=Dc0zc2civgbJcj8KXFCNDrvCXRPuZfCetIZ9XgHf5Qc,43029
|
|
1083
1083
|
cirq/transformers/eject_phased_paulis.py,sha256=gK1XIslsBPFcppUFacbhvzfhcnK5ZSVcyLN1SM5wTEE,14072
|
|
1084
1084
|
cirq/transformers/eject_phased_paulis_test.py,sha256=CQ5sUmJg9ibgo9RS7265CfOPJ1JgbyGWG9aRRi44dxM,14252
|
|
1085
1085
|
cirq/transformers/eject_z.py,sha256=890RYmv6qi4KgHi0LD1xEt2EQ4V7WzfS8lkqvZHt0r4,5860
|
|
@@ -1195,7 +1195,7 @@ cirq/value/classical_data.py,sha256=SIxyyJyM0BavQxJJVnRN_ktFvv5QFEPPEewsr0muLVk,
|
|
|
1195
1195
|
cirq/value/classical_data_test.py,sha256=q1QMT17E-X9kcaPw1oQqx3Hwnq3hyht24HaK3z7Udpo,5332
|
|
1196
1196
|
cirq/value/condition.py,sha256=lJJcFiqG-r68DhhS01DS6HhQw0pDwbNq71bvH1Famec,11916
|
|
1197
1197
|
cirq/value/condition_test.py,sha256=oEdim5nOYYY8UPU91H2xhb9MH8EC2WbMXTQ_DruHVO0,12949
|
|
1198
|
-
cirq/value/digits.py,sha256
|
|
1198
|
+
cirq/value/digits.py,sha256=5hHOYTM4A7yhz-7RLlv3KTB3VPPfbx-gRp7M_pAVAd4,6330
|
|
1199
1199
|
cirq/value/digits_test.py,sha256=WDeUQTnDqZXh4JjWu_qEkzCFAtd8x1UlN9I2yjdDV3g,3848
|
|
1200
1200
|
cirq/value/duration.py,sha256=4K-eiCoFfzm2SM3K1OhV__YrW1GmzgA7QSkBpxOkTp8,10402
|
|
1201
1201
|
cirq/value/duration_test.py,sha256=xQd5-dE8zZddsZru1P6ClV3PoeJncqLAQr3ivgZIXdQ,8281
|
|
@@ -1246,8 +1246,8 @@ cirq/work/sampler.py,sha256=rxbMWvrhu3gfNSBjZKozw28lLKVvBAS_1EGyPdYe8Xg,19041
|
|
|
1246
1246
|
cirq/work/sampler_test.py,sha256=SsMrRvLDYELyOAWLKISjkdEfrBwLYWRsT6D8WrsLM3Q,13533
|
|
1247
1247
|
cirq/work/zeros_sampler.py,sha256=Fs2JWwq0n9zv7_G5Rm-9vPeHUag7uctcMOHg0JTkZpc,2371
|
|
1248
1248
|
cirq/work/zeros_sampler_test.py,sha256=lQLgQDGBLtfImryys2HzQ2jOSGxHgc7-koVBUhv8qYk,3345
|
|
1249
|
-
cirq_core-1.7.0.
|
|
1250
|
-
cirq_core-1.7.0.
|
|
1251
|
-
cirq_core-1.7.0.
|
|
1252
|
-
cirq_core-1.7.0.
|
|
1253
|
-
cirq_core-1.7.0.
|
|
1249
|
+
cirq_core-1.7.0.dev20251028035559.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
1250
|
+
cirq_core-1.7.0.dev20251028035559.dist-info/METADATA,sha256=V4zXcqoE990QTFmY9VzWqvWLSCTec-DJVfIMWESOK8s,4757
|
|
1251
|
+
cirq_core-1.7.0.dev20251028035559.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
1252
|
+
cirq_core-1.7.0.dev20251028035559.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
|
|
1253
|
+
cirq_core-1.7.0.dev20251028035559.dist-info/RECORD,,
|
{cirq_core-1.7.0.dev20251027223253.dist-info → cirq_core-1.7.0.dev20251028035559.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|