cirq-core 1.6.0.dev20250625151218__py3-none-any.whl → 1.6.0.dev20250625152617__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/quantum_shannon_decomposition.py +131 -36
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +33 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +64 -5
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +18 -0
- {cirq_core-1.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/RECORD +11 -11
- {cirq_core-1.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
|
@@ -21,26 +21,31 @@ https://arxiv.org/abs/quant-ph/0406176
|
|
|
21
21
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
|
-
from typing import Callable, Iterable, TYPE_CHECKING
|
|
24
|
+
from typing import Callable, cast, Iterable, TYPE_CHECKING
|
|
25
25
|
|
|
26
26
|
import numpy as np
|
|
27
|
+
from attr import define
|
|
27
28
|
from scipy.linalg import cossin
|
|
28
29
|
|
|
29
30
|
from cirq import ops
|
|
30
31
|
from cirq.circuits.frozen_circuit import FrozenCircuit
|
|
31
32
|
from cirq.linalg import decompositions, predicates
|
|
32
33
|
from cirq.protocols import unitary_protocol
|
|
33
|
-
from cirq.transformers.analytical_decompositions.three_qubit_decomposition import (
|
|
34
|
-
three_qubit_matrix_to_operations,
|
|
35
|
-
)
|
|
36
34
|
from cirq.transformers.analytical_decompositions.two_qubit_to_cz import (
|
|
37
35
|
two_qubit_matrix_to_cz_operations,
|
|
36
|
+
two_qubit_matrix_to_diagonal_and_cz_operations,
|
|
38
37
|
)
|
|
39
38
|
|
|
40
39
|
if TYPE_CHECKING:
|
|
41
40
|
import cirq
|
|
42
41
|
|
|
43
42
|
|
|
43
|
+
@define
|
|
44
|
+
class _TwoQubitGate:
|
|
45
|
+
location: int
|
|
46
|
+
matrix: np.ndarray
|
|
47
|
+
|
|
48
|
+
|
|
44
49
|
def quantum_shannon_decomposition(
|
|
45
50
|
qubits: list[cirq.Qid], u: np.ndarray, atol: float = 1e-8
|
|
46
51
|
) -> Iterable[cirq.Operation]:
|
|
@@ -67,14 +72,12 @@ def quantum_shannon_decomposition(
|
|
|
67
72
|
1. _single_qubit_decomposition
|
|
68
73
|
OR
|
|
69
74
|
(Recursive Case)
|
|
70
|
-
1.
|
|
71
|
-
2. _multiplexed_cossin
|
|
72
|
-
3. _msb_demuxer
|
|
75
|
+
1. _recursive_decomposition
|
|
73
76
|
|
|
74
77
|
Yields:
|
|
75
78
|
A single 2-qubit or 1-qubit operations from OP TREE
|
|
76
79
|
composed from the set
|
|
77
|
-
{ CNOT, rz, ry, ZPowGate }
|
|
80
|
+
{ CNOT, CZ, rz, ry, ZPowGate }
|
|
78
81
|
|
|
79
82
|
Raises:
|
|
80
83
|
ValueError: If the u matrix is non-unitary
|
|
@@ -98,30 +101,92 @@ def quantum_shannon_decomposition(
|
|
|
98
101
|
yield from _single_qubit_decomposition(qubits[0], u)
|
|
99
102
|
return
|
|
100
103
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
# Collect all operations from the recursive decomposition
|
|
105
|
+
shannon_decomp: list[cirq.Operation | list[cirq.Operation]] = [
|
|
106
|
+
*_recursive_decomposition(qubits, u)
|
|
107
|
+
]
|
|
108
|
+
# Separate all 2-qubit generic gates while keeping track of location
|
|
109
|
+
two_qubit_gates = [
|
|
110
|
+
_TwoQubitGate(location=loc, matrix=unitary_protocol.unitary(o))
|
|
111
|
+
for loc, o in enumerate(cast(list[ops.Operation], shannon_decomp))
|
|
112
|
+
if isinstance(o.gate, ops.MatrixGate)
|
|
113
|
+
]
|
|
114
|
+
# Apply case A.2 from Shende et al.
|
|
115
|
+
q0 = qubits[-2]
|
|
116
|
+
q1 = qubits[-1]
|
|
117
|
+
for idx in range(len(two_qubit_gates) - 1, 0, -1):
|
|
118
|
+
diagonal, operations = two_qubit_matrix_to_diagonal_and_cz_operations(
|
|
119
|
+
q0,
|
|
120
|
+
q1,
|
|
121
|
+
two_qubit_gates[idx].matrix,
|
|
122
|
+
allow_partial_czs=True,
|
|
123
|
+
clean_operations=True,
|
|
124
|
+
atol=atol,
|
|
106
125
|
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
global_phase = _global_phase_difference(
|
|
127
|
+
two_qubit_gates[idx].matrix, [ops.MatrixGate(diagonal)(q0, q1), *operations]
|
|
128
|
+
)
|
|
129
|
+
if not np.isclose(global_phase, 0, atol=atol):
|
|
130
|
+
operations.append(ops.global_phase_operation(np.exp(1j * global_phase)))
|
|
131
|
+
# Replace the generic gate with ops from OP TREE
|
|
132
|
+
shannon_decomp[two_qubit_gates[idx].location] = operations
|
|
133
|
+
# Join the diagonal with the unitary to be decomposed in the next step
|
|
134
|
+
two_qubit_gates[idx - 1].matrix = diagonal @ two_qubit_gates[idx - 1].matrix
|
|
135
|
+
if len(two_qubit_gates) > 0:
|
|
136
|
+
operations = two_qubit_matrix_to_cz_operations(
|
|
137
|
+
q0,
|
|
138
|
+
q1,
|
|
139
|
+
two_qubit_gates[0].matrix,
|
|
140
|
+
allow_partial_czs=True,
|
|
141
|
+
clean_operations=True,
|
|
142
|
+
atol=atol,
|
|
143
|
+
)
|
|
144
|
+
global_phase = _global_phase_difference(two_qubit_gates[0].matrix, operations)
|
|
145
|
+
if not np.isclose(global_phase, 0, atol=atol):
|
|
146
|
+
operations.append(ops.global_phase_operation(np.exp(1j * global_phase)))
|
|
147
|
+
shannon_decomp[two_qubit_gates[0].location] = operations
|
|
148
|
+
# Yield the final operations in order
|
|
149
|
+
yield from cast(Iterable[ops.Operation], ops.flatten_op_tree(shannon_decomp))
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _recursive_decomposition(qubits: list[cirq.Qid], u: np.ndarray) -> Iterable[cirq.Operation]:
|
|
153
|
+
"""Recursive step in the quantum shannon decomposition.
|
|
154
|
+
|
|
155
|
+
Decomposes n-qubit unitary into generic 2-qubit gates, CNOT, CZ and 1-qubit gates.
|
|
156
|
+
All generic 2-qubit gates are applied to the two least significant qubits and
|
|
157
|
+
are not decomposed further here.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
qubits: List of qubits in order of significance
|
|
161
|
+
u: Numpy array for unitary matrix representing gate to be decomposed
|
|
162
|
+
|
|
163
|
+
Calls:
|
|
164
|
+
1. _msb_demuxer
|
|
165
|
+
2. _multiplexed_cossin
|
|
166
|
+
3. _msb_demuxer
|
|
167
|
+
|
|
168
|
+
Yields:
|
|
169
|
+
Generic 2-qubit gates or operations from {ry,rz,CNOT,CZ}.
|
|
114
170
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
Raises:
|
|
172
|
+
ValueError: If the u matrix is not of shape (2^n,2^n)
|
|
173
|
+
ValueError: If the u matrix is not of size at least 4
|
|
174
|
+
"""
|
|
175
|
+
n = u.shape[0]
|
|
176
|
+
if n & (n - 1):
|
|
177
|
+
raise ValueError(
|
|
178
|
+
f"Expected input matrix u to be a (2^n x 2^n) shaped numpy array, \
|
|
179
|
+
but instead got shape {u.shape}"
|
|
118
180
|
)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
181
|
+
|
|
182
|
+
if n <= 2:
|
|
183
|
+
raise ValueError(
|
|
184
|
+
f"Expected input matrix u for recursive step to have size at least 4, \
|
|
185
|
+
but it has size {n}"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if n == 4:
|
|
189
|
+
yield ops.MatrixGate(u).on(*qubits)
|
|
125
190
|
return
|
|
126
191
|
|
|
127
192
|
# Perform a cosine-sine (linalg) decomposition on u
|
|
@@ -137,10 +202,30 @@ def quantum_shannon_decomposition(
|
|
|
137
202
|
# Yield ops from multiplexed Ry part
|
|
138
203
|
yield from _multiplexed_cossin(qubits, theta, ops.ry)
|
|
139
204
|
|
|
205
|
+
# Optimization A.1 in Shende et al. - the last CZ gate in the multiplexed Ry part
|
|
206
|
+
# is merged into the generic multiplexor (u1, u2)
|
|
207
|
+
# This gate is CZ(qubits[1], qubits[0]) = CZ(qubits[0], qubits[1])
|
|
208
|
+
# as CZ is symmetric.
|
|
209
|
+
# For the u1⊕u2 multiplexor operator:
|
|
210
|
+
# as u1 is the operator in case qubits[0] = |0>,
|
|
211
|
+
# and u2 is the operator in case qubits[0] = |1>
|
|
212
|
+
# we can represent the merge by phasing u2 with Z ⊗ I
|
|
213
|
+
cz_diag = np.concatenate((np.ones(n >> 2), np.full(n >> 2, -1)))
|
|
214
|
+
u2 = u2 @ np.diag(cz_diag)
|
|
215
|
+
|
|
140
216
|
# Yield ops from decomposition of multiplexed u1/u2 part
|
|
141
217
|
yield from _msb_demuxer(qubits, u1, u2)
|
|
142
218
|
|
|
143
219
|
|
|
220
|
+
def _global_phase_difference(u: np.ndarray, ops: list[cirq.Operation]) -> float:
|
|
221
|
+
"""Returns the difference in global phase between unitary u and
|
|
222
|
+
a list of operations computing u.
|
|
223
|
+
"""
|
|
224
|
+
i, j = np.unravel_index(np.argmax(np.abs(u)), u.shape)
|
|
225
|
+
new_unitary = unitary_protocol.unitary(FrozenCircuit.from_moments(*ops))
|
|
226
|
+
return np.angle(u[i, j]) - np.angle(new_unitary[i, j])
|
|
227
|
+
|
|
228
|
+
|
|
144
229
|
def _single_qubit_decomposition(qubit: cirq.Qid, u: np.ndarray) -> Iterable[cirq.Operation]:
|
|
145
230
|
"""Decomposes single-qubit gate, and returns list of operations, keeping phase invariant.
|
|
146
231
|
|
|
@@ -202,11 +287,14 @@ def _msb_demuxer(
|
|
|
202
287
|
u2: Lower-right quadrant of total unitary to be decomposed (see diagram)
|
|
203
288
|
|
|
204
289
|
Calls:
|
|
205
|
-
1.
|
|
290
|
+
1. _recursive_decomposition
|
|
206
291
|
2. _multiplexed_cossin
|
|
207
|
-
3.
|
|
292
|
+
3. _recursive_decomposition
|
|
208
293
|
|
|
209
|
-
Yields:
|
|
294
|
+
Yields:
|
|
295
|
+
Generic 2-qubit gates on the two least significant qubits,
|
|
296
|
+
CNOT gates with the target not on the two least significant qubits,
|
|
297
|
+
ry or rz
|
|
210
298
|
"""
|
|
211
299
|
# Perform a diagonalization to find values
|
|
212
300
|
u1 = u1.astype(np.complex128)
|
|
@@ -231,7 +319,7 @@ def _msb_demuxer(
|
|
|
231
319
|
# Last term is given by ( I ⊗ W ), demultiplexed
|
|
232
320
|
# Remove most-significant (demuxed) control-qubit
|
|
233
321
|
# Yield operations for QSD on W
|
|
234
|
-
yield from
|
|
322
|
+
yield from _recursive_decomposition(demux_qubits[1:], W)
|
|
235
323
|
|
|
236
324
|
# Use complex phase of d_i to give theta_i (so d_i* gives -theta_i)
|
|
237
325
|
# Observe that middle part looks like Σ_i( Rz(theta_i)⊗|i><i| )
|
|
@@ -239,7 +327,7 @@ def _msb_demuxer(
|
|
|
239
327
|
yield from _multiplexed_cossin(demux_qubits, -np.angle(d), ops.rz)
|
|
240
328
|
|
|
241
329
|
# Yield operations for QSD on V
|
|
242
|
-
yield from
|
|
330
|
+
yield from _recursive_decomposition(demux_qubits[1:], V)
|
|
243
331
|
|
|
244
332
|
|
|
245
333
|
def _nth_gray(n: int) -> int:
|
|
@@ -263,7 +351,7 @@ def _multiplexed_cossin(
|
|
|
263
351
|
Calls:
|
|
264
352
|
No major calls
|
|
265
353
|
|
|
266
|
-
Yields: Single operation from OP TREE from set 1- and 2-qubit gates: {ry,rz,CNOT}
|
|
354
|
+
Yields: Single operation from OP TREE from set 1- and 2-qubit gates: {ry,rz,CNOT,CZ}
|
|
267
355
|
"""
|
|
268
356
|
# Most significant qubit is main qubit with rotation function applied
|
|
269
357
|
main_qubit = cossin_qubits[0]
|
|
@@ -304,4 +392,11 @@ def _multiplexed_cossin(
|
|
|
304
392
|
yield rot_func(rotation).on(main_qubit)
|
|
305
393
|
|
|
306
394
|
# Add a CNOT from the select qubit to the main qubit
|
|
307
|
-
|
|
395
|
+
# Optimization A.1 in Shende et al. - use CZ instead of CNOT for ry rotations
|
|
396
|
+
if rot_func == ops.ry:
|
|
397
|
+
# Don't emit the last gate, as it will be merged into the generic multiplexor
|
|
398
|
+
# in the cosine-sine decomposition
|
|
399
|
+
if j < len(angles) - 1:
|
|
400
|
+
yield ops.CZ(control_qubits[select_qubit], main_qubit)
|
|
401
|
+
else:
|
|
402
|
+
yield ops.CNOT(control_qubits[select_qubit], main_qubit)
|
|
@@ -20,10 +20,12 @@ from scipy.stats import unitary_group
|
|
|
20
20
|
|
|
21
21
|
import cirq
|
|
22
22
|
from cirq.ops import common_gates
|
|
23
|
+
from cirq.testing import random_two_qubit_circuit_with_czs
|
|
23
24
|
from cirq.transformers.analytical_decompositions.quantum_shannon_decomposition import (
|
|
24
25
|
_msb_demuxer,
|
|
25
26
|
_multiplexed_cossin,
|
|
26
27
|
_nth_gray,
|
|
28
|
+
_recursive_decomposition,
|
|
27
29
|
_single_qubit_decomposition,
|
|
28
30
|
quantum_shannon_decomposition,
|
|
29
31
|
)
|
|
@@ -49,6 +51,14 @@ def test_qsd_n_qubit_errors():
|
|
|
49
51
|
cirq.Circuit(quantum_shannon_decomposition(qubits, np.ones((8, 8))))
|
|
50
52
|
|
|
51
53
|
|
|
54
|
+
def test_recursive_decomposition_n_qubit_errors():
|
|
55
|
+
qubits = [cirq.NamedQubit(f'q{i}') for i in range(3)]
|
|
56
|
+
with pytest.raises(ValueError, match="shaped numpy array"):
|
|
57
|
+
cirq.Circuit(_recursive_decomposition(qubits, np.eye(9)))
|
|
58
|
+
with pytest.raises(ValueError, match="size at least 4"):
|
|
59
|
+
cirq.Circuit(_recursive_decomposition(qubits, np.eye(2)))
|
|
60
|
+
|
|
61
|
+
|
|
52
62
|
def test_random_single_qubit_decomposition():
|
|
53
63
|
U = unitary_group.rvs(2)
|
|
54
64
|
qubit = cirq.NamedQubit('q0')
|
|
@@ -80,10 +90,18 @@ def test_multiplexed_cossin():
|
|
|
80
90
|
multiplexed_ry = np.array(multiplexed_ry)
|
|
81
91
|
qubits = [cirq.NamedQubit(f'q{i}') for i in range(2)]
|
|
82
92
|
circuit = cirq.Circuit(_multiplexed_cossin(qubits, [angle_1, angle_2]))
|
|
93
|
+
# Add back the CZ gate removed by the A.1 optimization
|
|
94
|
+
circuit += cirq.CZ(qubits[1], qubits[0])
|
|
83
95
|
# Test return is equal to inital unitary
|
|
84
96
|
assert cirq.approx_eq(multiplexed_ry, circuit.unitary(), atol=1e-9)
|
|
85
97
|
# Test all operations in gate set
|
|
86
|
-
gates = (
|
|
98
|
+
gates = (
|
|
99
|
+
common_gates.Rz,
|
|
100
|
+
common_gates.Ry,
|
|
101
|
+
common_gates.ZPowGate,
|
|
102
|
+
common_gates.CXPowGate,
|
|
103
|
+
common_gates.CZPowGate,
|
|
104
|
+
)
|
|
87
105
|
assert all(isinstance(op.gate, gates) for op in circuit.all_operations())
|
|
88
106
|
|
|
89
107
|
|
|
@@ -203,3 +221,17 @@ def test_qft5():
|
|
|
203
221
|
)
|
|
204
222
|
new_unitary = cirq.unitary(shannon_circuit)
|
|
205
223
|
np.testing.assert_allclose(new_unitary, desired_unitary, atol=1e-6)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_random_circuit_decomposition():
|
|
227
|
+
qubits = cirq.LineQubit.range(3)
|
|
228
|
+
test_circuit = (
|
|
229
|
+
random_two_qubit_circuit_with_czs(3, qubits[0], qubits[1])
|
|
230
|
+
+ random_two_qubit_circuit_with_czs(3, qubits[1], qubits[2])
|
|
231
|
+
+ random_two_qubit_circuit_with_czs(3, qubits[0], qubits[2])
|
|
232
|
+
)
|
|
233
|
+
circuit = cirq.Circuit(quantum_shannon_decomposition(qubits, test_circuit.unitary()))
|
|
234
|
+
# Test return is equal to initial unitary
|
|
235
|
+
assert cirq.approx_eq(test_circuit.unitary(), circuit.unitary(), atol=1e-9)
|
|
236
|
+
# Test all operations have at most 2 qubits.
|
|
237
|
+
assert all(cirq.num_qubits(op) <= 2 for op in circuit.all_operations())
|
|
@@ -26,7 +26,6 @@ from cirq.linalg.decompositions import extract_right_diag, num_cnots_required
|
|
|
26
26
|
from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
|
27
27
|
from cirq.transformers.eject_phased_paulis import eject_phased_paulis
|
|
28
28
|
from cirq.transformers.eject_z import eject_z
|
|
29
|
-
from cirq.transformers.merge_single_qubit_gates import merge_single_qubit_gates_to_phased_x_and_z
|
|
30
29
|
|
|
31
30
|
if TYPE_CHECKING:
|
|
32
31
|
import cirq
|
|
@@ -81,8 +80,8 @@ def two_qubit_matrix_to_cz_operations(
|
|
|
81
80
|
if clean_operations:
|
|
82
81
|
if not allow_partial_czs:
|
|
83
82
|
# CZ^t is not allowed for any $t$ except $t=1$.
|
|
84
|
-
return _remove_partial_czs_or_fail(cleanup_operations(operations), atol=atol)
|
|
85
|
-
return cleanup_operations(operations)
|
|
83
|
+
return _remove_partial_czs_or_fail(cleanup_operations(operations, atol=atol), atol=atol)
|
|
84
|
+
return cleanup_operations(operations, atol=atol)
|
|
86
85
|
return operations
|
|
87
86
|
|
|
88
87
|
|
|
@@ -182,15 +181,75 @@ def _xx_yy_zz_interaction_via_full_czs(q0: cirq.Qid, q1: cirq.Qid, x: float, y:
|
|
|
182
181
|
yield ops.H(q1)
|
|
183
182
|
|
|
184
183
|
|
|
185
|
-
def cleanup_operations(operations: Sequence[ops.Operation]):
|
|
184
|
+
def cleanup_operations(operations: Sequence[ops.Operation], atol: float = 1e-8):
|
|
185
|
+
operations = _merge_single_qubit_gates(operations, atol=atol)
|
|
186
186
|
circuit = circuits.Circuit(operations)
|
|
187
|
-
circuit = merge_single_qubit_gates_to_phased_x_and_z(circuit)
|
|
188
187
|
circuit = eject_phased_paulis(circuit)
|
|
189
188
|
circuit = eject_z(circuit)
|
|
190
189
|
circuit = circuits.Circuit(circuit.all_operations(), strategy=circuits.InsertStrategy.EARLIEST)
|
|
191
190
|
return list(circuit.all_operations())
|
|
192
191
|
|
|
193
192
|
|
|
193
|
+
def _transform_single_qubit_operations_to_phased_x_and_z(
|
|
194
|
+
operations: Sequence[ops.Operation], atol: float
|
|
195
|
+
) -> Sequence[ops.Operation]:
|
|
196
|
+
"""Transforms operations on the same qubit to a PhasedXPowGate followed by a Z gate.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
operations: sequence of operations on the same qubit
|
|
200
|
+
atol: a limit on the amount of absolute error introduced by the
|
|
201
|
+
transformation.
|
|
202
|
+
Returns:
|
|
203
|
+
A PhasedXPowGate followed by a Z gate. If one the gates is not needed, it will be omitted.
|
|
204
|
+
"""
|
|
205
|
+
u = np.eye(2)
|
|
206
|
+
for op in operations:
|
|
207
|
+
u = protocols.unitary(op) @ u
|
|
208
|
+
return [
|
|
209
|
+
g(op.qubits[0])
|
|
210
|
+
for g in single_qubit_decompositions.single_qubit_matrix_to_phased_x_z(u, atol=atol)
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _merge_single_qubit_gates(
|
|
215
|
+
operations: Sequence[ops.Operation], atol: float
|
|
216
|
+
) -> Sequence[ops.Operation]:
|
|
217
|
+
"""Merge consecutive single qubit gates.
|
|
218
|
+
|
|
219
|
+
Traverses the sequence of operations maintaining a list of consecutive single qubit
|
|
220
|
+
operations for each qubit. When a 2-qubit gate is encountered, it transforms pending
|
|
221
|
+
operations to a PhasedXPowGate followed by a Z gate.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
operations: sequence of operations
|
|
225
|
+
atol: a limit on the amount of absolute error introduced by the
|
|
226
|
+
transformation.
|
|
227
|
+
Returns:
|
|
228
|
+
new sequence of operations after merging gates
|
|
229
|
+
"""
|
|
230
|
+
merged_ops: list[ops.Operation] = []
|
|
231
|
+
pending_ops: dict[tuple[cirq.Qid, ...], list[ops.Operation]] = dict()
|
|
232
|
+
for op in operations:
|
|
233
|
+
if protocols.num_qubits(op) == 2:
|
|
234
|
+
for _, qubit_ops in pending_ops.items():
|
|
235
|
+
merged_ops.extend(
|
|
236
|
+
_transform_single_qubit_operations_to_phased_x_and_z(qubit_ops, atol=atol)
|
|
237
|
+
)
|
|
238
|
+
pending_ops.clear()
|
|
239
|
+
# Add the 2-qubit gate
|
|
240
|
+
merged_ops.append(op)
|
|
241
|
+
elif protocols.num_qubits(op) == 1:
|
|
242
|
+
if op.qubits not in pending_ops:
|
|
243
|
+
pending_ops[op.qubits] = []
|
|
244
|
+
pending_ops[op.qubits].append(op)
|
|
245
|
+
# Merge remaining pending operations
|
|
246
|
+
for _, qubit_ops in pending_ops.items():
|
|
247
|
+
merged_ops.extend(
|
|
248
|
+
_transform_single_qubit_operations_to_phased_x_and_z(qubit_ops, atol=atol)
|
|
249
|
+
)
|
|
250
|
+
return merged_ops
|
|
251
|
+
|
|
252
|
+
|
|
194
253
|
def _kak_decomposition_to_operations(
|
|
195
254
|
q0: cirq.Qid,
|
|
196
255
|
q1: cirq.Qid,
|
|
@@ -261,6 +261,24 @@ def test_decompose_to_diagonal_and_circuit(v) -> None:
|
|
|
261
261
|
cirq.testing.assert_allclose_up_to_global_phase(circuit_unitary, v, atol=2e-6)
|
|
262
262
|
|
|
263
263
|
|
|
264
|
+
@pytest.mark.parametrize(
|
|
265
|
+
"mat, num_czs",
|
|
266
|
+
[
|
|
267
|
+
(cirq.unitary(random_two_qubit_circuit_with_czs(3)), 2),
|
|
268
|
+
(cirq.unitary(random_two_qubit_circuit_with_czs(2)), 2),
|
|
269
|
+
(cirq.unitary(random_two_qubit_circuit_with_czs(1)), 1),
|
|
270
|
+
(cirq.unitary(random_two_qubit_circuit_with_czs(0)), 0),
|
|
271
|
+
],
|
|
272
|
+
)
|
|
273
|
+
def test_decompose_to_diagonal_and_circuit_returns_circuit_with_expected_number_of_czs(
|
|
274
|
+
mat, num_czs
|
|
275
|
+
):
|
|
276
|
+
b, c = cirq.LineQubit.range(2)
|
|
277
|
+
_, ops = two_qubit_matrix_to_diagonal_and_cz_operations(b, c, mat, atol=1e-8)
|
|
278
|
+
circuit = cirq.Circuit(ops)
|
|
279
|
+
assert len(list(circuit.findall_operations_with_gate_type(cirq.CZPowGate))) == num_czs
|
|
280
|
+
|
|
281
|
+
|
|
264
282
|
def test_remove_partial_czs_or_fail() -> None:
|
|
265
283
|
CZ = cirq.CZ(*cirq.LineQubit.range(2))
|
|
266
284
|
assert (
|
{cirq_core-1.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cirq-core
|
|
3
|
-
Version: 1.6.0.
|
|
3
|
+
Version: 1.6.0.dev20250625152617
|
|
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.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/RECORD
RENAMED
|
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=emXpdD5ZvwLRlFAoQB8YatmZyU3b4e9jg6FppMTUhkU,33900
|
|
|
4
4
|
cirq/_doc.py,sha256=BrnoABo1hk5RgB3Cgww4zLHUfiyFny0F1V-tOMCbdaU,2909
|
|
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=WaS6yXNBrQkWyNLtZioFkSEnew96llAnYDIuKKhPb-4,1206
|
|
8
|
+
cirq/_version_test.py,sha256=LhXcrh_kn28Wi96pK1rtGPJU3q_VGDIJsTcF1OWhgYg,155
|
|
9
9
|
cirq/conftest.py,sha256=X7yLFL8GLhg2CjPw0hp5e_dGASfvHx1-QT03aUbhKJw,1168
|
|
10
10
|
cirq/json_resolver_cache.py,sha256=hYyG53VJeV61X0oukK5ndZYega8lkL2FyaL1m0j6h5M,13556
|
|
11
11
|
cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
|
|
@@ -1102,8 +1102,8 @@ cirq/transformers/analytical_decompositions/cphase_to_fsim.py,sha256=jFWTFjCQ76c
|
|
|
1102
1102
|
cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py,sha256=6ZDfSTL7aWSXXfM5DToeX8VxMalWirrCGKKg7QKBGFc,5591
|
|
1103
1103
|
cirq/transformers/analytical_decompositions/pauli_string_decomposition.py,sha256=7GKdVnN5jvpjABudB0zE1kUn0BPZmuvRZcM2yLMUoWs,4540
|
|
1104
1104
|
cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py,sha256=yWHkXXErOxLmnp5t65WUsY9e9iN6L950MZRw5OY3QW0,2172
|
|
1105
|
-
cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py,sha256=
|
|
1106
|
-
cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py,sha256=
|
|
1105
|
+
cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py,sha256=EIrK1PbHRMMhT5wei6rYk8diPEaqEZ0B-9M1chhCfCo,15450
|
|
1106
|
+
cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py,sha256=Bk94HEm9a-cywM_Q2TBF6eUYkSJB1GWwJ5QO1J-rMoA,9006
|
|
1107
1107
|
cirq/transformers/analytical_decompositions/single_qubit_decompositions.py,sha256=6kaQfcXY7je42o-pVprSwgPXCDJXraDXQ9mHyR_BaBk,8428
|
|
1108
1108
|
cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py,sha256=oh96QXddCm1v8CrYA5mEnnx_ENXwZi89W6paVZU273I,12344
|
|
1109
1109
|
cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py,sha256=CRZylmI8nA_aq6vXj0WmMce8PIe8OFCjq4_bqYfkenk,2464
|
|
@@ -1112,8 +1112,8 @@ cirq/transformers/analytical_decompositions/three_qubit_decomposition.py,sha256=
|
|
|
1112
1112
|
cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py,sha256=a21HU4BE82AG2UJU4hUVqymUU7Lw4CLw4-NChX4OpLI,6808
|
|
1113
1113
|
cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py,sha256=2bIpZOHBHxH2mdbJfDpo6nQgpitOI0ZmoH_5l_nA1nU,6167
|
|
1114
1114
|
cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py,sha256=c-vFBZnybd-Ez4rcs13THGGthzEZ0qw9Iw9sAKbE6yc,4494
|
|
1115
|
-
cirq/transformers/analytical_decompositions/two_qubit_to_cz.py,sha256=
|
|
1116
|
-
cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py,sha256=
|
|
1115
|
+
cirq/transformers/analytical_decompositions/two_qubit_to_cz.py,sha256=L2ScuiYW5tbNSc9_DJ4S6Lr_0mpmurVKUzlwLmGdJmw,11513
|
|
1116
|
+
cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py,sha256=PLPQRsBCVwGCgtL7nBY6xdI_CG1zxTdIj7fFGpxjU2U,10704
|
|
1117
1117
|
cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py,sha256=8tYGV41gQBRzJSNUB3bsTMI8vil0TNE4TgqWlEw8BhE,9656
|
|
1118
1118
|
cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py,sha256=bX8ap8VskN-gKxn3F4A8_vhgWO0AErOpP1QVVEtBjmY,7073
|
|
1119
1119
|
cirq/transformers/analytical_decompositions/two_qubit_to_ms.py,sha256=dP9umZJBgNJ8FbDFFZVgMSyO-NjWJqXmoWyQuTo--0g,3751
|
|
@@ -1220,8 +1220,8 @@ cirq/work/sampler.py,sha256=rxbMWvrhu3gfNSBjZKozw28lLKVvBAS_1EGyPdYe8Xg,19041
|
|
|
1220
1220
|
cirq/work/sampler_test.py,sha256=SsMrRvLDYELyOAWLKISjkdEfrBwLYWRsT6D8WrsLM3Q,13533
|
|
1221
1221
|
cirq/work/zeros_sampler.py,sha256=Fs2JWwq0n9zv7_G5Rm-9vPeHUag7uctcMOHg0JTkZpc,2371
|
|
1222
1222
|
cirq/work/zeros_sampler_test.py,sha256=lQLgQDGBLtfImryys2HzQ2jOSGxHgc7-koVBUhv8qYk,3345
|
|
1223
|
-
cirq_core-1.6.0.
|
|
1224
|
-
cirq_core-1.6.0.
|
|
1225
|
-
cirq_core-1.6.0.
|
|
1226
|
-
cirq_core-1.6.0.
|
|
1227
|
-
cirq_core-1.6.0.
|
|
1223
|
+
cirq_core-1.6.0.dev20250625152617.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
1224
|
+
cirq_core-1.6.0.dev20250625152617.dist-info/METADATA,sha256=fnk4EUEjwRjeZxmyGn_W7MpZMYIIs5bO1ox35RYjOZ0,4857
|
|
1225
|
+
cirq_core-1.6.0.dev20250625152617.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
1226
|
+
cirq_core-1.6.0.dev20250625152617.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
|
|
1227
|
+
cirq_core-1.6.0.dev20250625152617.dist-info/RECORD,,
|
{cirq_core-1.6.0.dev20250625151218.dist-info → cirq_core-1.6.0.dev20250625152617.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|