cirq-core 1.5.0.dev20241220195200__py3-none-any.whl → 1.5.0.dev20241221000556__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/gauge_compiling/cz_gauge.py +128 -16
- cirq/transformers/gauge_compiling/cz_gauge_test.py +1 -0
- cirq/transformers/gauge_compiling/gauge_compiling.py +151 -2
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +85 -1
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +37 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +30 -0
- {cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/METADATA +1 -1
- {cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/RECORD +13 -13
- {cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/LICENSE +0 -0
- {cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/WHEEL +0 -0
- {cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
|
@@ -24,22 +24,134 @@ from cirq import ops
|
|
|
24
24
|
|
|
25
25
|
CZGaugeSelector = GaugeSelector(
|
|
26
26
|
gauges=[
|
|
27
|
-
ConstantGauge(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
ConstantGauge(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
27
|
+
ConstantGauge(
|
|
28
|
+
two_qubit_gate=CZ,
|
|
29
|
+
pre_q0=ops.I,
|
|
30
|
+
pre_q1=ops.I,
|
|
31
|
+
post_q0=ops.I,
|
|
32
|
+
post_q1=ops.I,
|
|
33
|
+
support_sweep=True,
|
|
34
|
+
),
|
|
35
|
+
ConstantGauge(
|
|
36
|
+
two_qubit_gate=CZ,
|
|
37
|
+
pre_q0=ops.I,
|
|
38
|
+
pre_q1=ops.X,
|
|
39
|
+
post_q0=ops.Z,
|
|
40
|
+
post_q1=ops.X,
|
|
41
|
+
support_sweep=True,
|
|
42
|
+
),
|
|
43
|
+
ConstantGauge(
|
|
44
|
+
two_qubit_gate=CZ,
|
|
45
|
+
pre_q0=ops.I,
|
|
46
|
+
pre_q1=ops.Y,
|
|
47
|
+
post_q0=ops.Z,
|
|
48
|
+
post_q1=ops.Y,
|
|
49
|
+
support_sweep=True,
|
|
50
|
+
),
|
|
51
|
+
ConstantGauge(
|
|
52
|
+
two_qubit_gate=CZ,
|
|
53
|
+
pre_q0=ops.I,
|
|
54
|
+
pre_q1=ops.Z,
|
|
55
|
+
post_q0=ops.I,
|
|
56
|
+
post_q1=ops.Z,
|
|
57
|
+
support_sweep=True,
|
|
58
|
+
),
|
|
59
|
+
ConstantGauge(
|
|
60
|
+
two_qubit_gate=CZ,
|
|
61
|
+
pre_q0=ops.X,
|
|
62
|
+
pre_q1=ops.I,
|
|
63
|
+
post_q0=ops.X,
|
|
64
|
+
post_q1=ops.Z,
|
|
65
|
+
support_sweep=True,
|
|
66
|
+
),
|
|
67
|
+
ConstantGauge(
|
|
68
|
+
two_qubit_gate=CZ,
|
|
69
|
+
pre_q0=ops.X,
|
|
70
|
+
pre_q1=ops.X,
|
|
71
|
+
post_q0=ops.Y,
|
|
72
|
+
post_q1=ops.Y,
|
|
73
|
+
support_sweep=True,
|
|
74
|
+
),
|
|
75
|
+
ConstantGauge(
|
|
76
|
+
two_qubit_gate=CZ,
|
|
77
|
+
pre_q0=ops.X,
|
|
78
|
+
pre_q1=ops.Y,
|
|
79
|
+
post_q0=ops.Y,
|
|
80
|
+
post_q1=ops.X,
|
|
81
|
+
support_sweep=True,
|
|
82
|
+
),
|
|
83
|
+
ConstantGauge(
|
|
84
|
+
two_qubit_gate=CZ,
|
|
85
|
+
pre_q0=ops.X,
|
|
86
|
+
pre_q1=ops.Z,
|
|
87
|
+
post_q0=ops.X,
|
|
88
|
+
post_q1=ops.I,
|
|
89
|
+
support_sweep=True,
|
|
90
|
+
),
|
|
91
|
+
ConstantGauge(
|
|
92
|
+
two_qubit_gate=CZ,
|
|
93
|
+
pre_q0=ops.Y,
|
|
94
|
+
pre_q1=ops.I,
|
|
95
|
+
post_q0=ops.Y,
|
|
96
|
+
post_q1=ops.Z,
|
|
97
|
+
support_sweep=True,
|
|
98
|
+
),
|
|
99
|
+
ConstantGauge(
|
|
100
|
+
two_qubit_gate=CZ,
|
|
101
|
+
pre_q0=ops.Y,
|
|
102
|
+
pre_q1=ops.X,
|
|
103
|
+
post_q0=ops.X,
|
|
104
|
+
post_q1=ops.Y,
|
|
105
|
+
support_sweep=True,
|
|
106
|
+
),
|
|
107
|
+
ConstantGauge(
|
|
108
|
+
two_qubit_gate=CZ,
|
|
109
|
+
pre_q0=ops.Y,
|
|
110
|
+
pre_q1=ops.Y,
|
|
111
|
+
post_q0=ops.X,
|
|
112
|
+
post_q1=ops.X,
|
|
113
|
+
support_sweep=True,
|
|
114
|
+
),
|
|
115
|
+
ConstantGauge(
|
|
116
|
+
two_qubit_gate=CZ,
|
|
117
|
+
pre_q0=ops.Y,
|
|
118
|
+
pre_q1=ops.Z,
|
|
119
|
+
post_q0=ops.Y,
|
|
120
|
+
post_q1=ops.I,
|
|
121
|
+
support_sweep=True,
|
|
122
|
+
),
|
|
123
|
+
ConstantGauge(
|
|
124
|
+
two_qubit_gate=CZ,
|
|
125
|
+
pre_q0=ops.Z,
|
|
126
|
+
pre_q1=ops.I,
|
|
127
|
+
post_q0=ops.Z,
|
|
128
|
+
post_q1=ops.I,
|
|
129
|
+
support_sweep=True,
|
|
130
|
+
),
|
|
131
|
+
ConstantGauge(
|
|
132
|
+
two_qubit_gate=CZ,
|
|
133
|
+
pre_q0=ops.Z,
|
|
134
|
+
pre_q1=ops.X,
|
|
135
|
+
post_q0=ops.I,
|
|
136
|
+
post_q1=ops.X,
|
|
137
|
+
support_sweep=True,
|
|
138
|
+
),
|
|
139
|
+
ConstantGauge(
|
|
140
|
+
two_qubit_gate=CZ,
|
|
141
|
+
pre_q0=ops.Z,
|
|
142
|
+
pre_q1=ops.Y,
|
|
143
|
+
post_q0=ops.I,
|
|
144
|
+
post_q1=ops.Y,
|
|
145
|
+
support_sweep=True,
|
|
146
|
+
),
|
|
147
|
+
ConstantGauge(
|
|
148
|
+
two_qubit_gate=CZ,
|
|
149
|
+
pre_q0=ops.Z,
|
|
150
|
+
pre_q1=ops.Z,
|
|
151
|
+
post_q0=ops.Z,
|
|
152
|
+
post_q1=ops.Z,
|
|
153
|
+
support_sweep=True,
|
|
154
|
+
),
|
|
43
155
|
]
|
|
44
156
|
)
|
|
45
157
|
|
|
@@ -14,17 +14,24 @@
|
|
|
14
14
|
|
|
15
15
|
"""Creates the abstraction for gauge compiling as a cirq transformer."""
|
|
16
16
|
|
|
17
|
-
from typing import Callable, Tuple, Optional, Sequence, Union, List
|
|
17
|
+
from typing import Callable, Dict, Tuple, Optional, Sequence, Union, List
|
|
18
|
+
from itertools import count
|
|
19
|
+
from dataclasses import dataclass
|
|
18
20
|
import abc
|
|
19
21
|
import itertools
|
|
20
22
|
import functools
|
|
23
|
+
import sympy
|
|
21
24
|
|
|
22
|
-
from dataclasses import dataclass
|
|
23
25
|
from attrs import frozen, field
|
|
24
26
|
import numpy as np
|
|
25
27
|
|
|
26
28
|
from cirq.transformers import transformer_api
|
|
27
29
|
from cirq import ops, circuits
|
|
30
|
+
from cirq.study import sweepable
|
|
31
|
+
from cirq.protocols import unitary_protocol
|
|
32
|
+
from cirq.protocols.has_unitary_protocol import has_unitary
|
|
33
|
+
from cirq.study.sweeps import Points, Zip
|
|
34
|
+
from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
|
28
35
|
|
|
29
36
|
|
|
30
37
|
class Gauge(abc.ABC):
|
|
@@ -72,6 +79,7 @@ class ConstantGauge(Gauge):
|
|
|
72
79
|
default=(), converter=lambda g: (g,) if isinstance(g, ops.Gate) else tuple(g)
|
|
73
80
|
)
|
|
74
81
|
swap_qubits: bool = False
|
|
82
|
+
support_sweep: bool = False
|
|
75
83
|
|
|
76
84
|
def sample(self, gate: ops.Gate, prng: np.random.Generator) -> "ConstantGauge":
|
|
77
85
|
return self
|
|
@@ -201,6 +209,100 @@ class GaugeTransformer:
|
|
|
201
209
|
new_moments.extend(_build_moments(right))
|
|
202
210
|
return circuits.Circuit.from_moments(*new_moments)
|
|
203
211
|
|
|
212
|
+
def as_sweep(
|
|
213
|
+
self,
|
|
214
|
+
circuit: circuits.AbstractCircuit,
|
|
215
|
+
*,
|
|
216
|
+
N: int,
|
|
217
|
+
context: Optional[transformer_api.TransformerContext] = None,
|
|
218
|
+
prng: Optional[np.random.Generator] = None,
|
|
219
|
+
) -> Tuple[circuits.AbstractCircuit, sweepable.Sweepable]:
|
|
220
|
+
"""Generates a parameterized circuit with *N* sets of sweepable parameters.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
circuit: The input circuit to be processed by gauge compiling.
|
|
224
|
+
N: The number of parameter sets to generate.
|
|
225
|
+
context: A `cirq.TransformerContext` storing common configurable options for
|
|
226
|
+
the transformers.
|
|
227
|
+
prng: A pseudo-random number generator to select a gauge within a gauge cluster.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
rng = np.random.default_rng() if prng is None else prng
|
|
231
|
+
if context is None:
|
|
232
|
+
context = transformer_api.TransformerContext(deep=False)
|
|
233
|
+
if context.deep:
|
|
234
|
+
raise ValueError('GaugeTransformer cannot be used with deep=True')
|
|
235
|
+
new_moments: List[List[ops.Operation]] = [] # Store parameterized circuits.
|
|
236
|
+
values_by_params: Dict[str, List[float]] = {} # map from symbol name to N values.
|
|
237
|
+
symbol_count = count()
|
|
238
|
+
# Map from "((pre|post),$qid,$moment_id)" to gate parameters.
|
|
239
|
+
# E.g. {(post,q1,2): {"x_exponent": "x1", "z_exponent": "z1", "axis_phase": "a1"}}
|
|
240
|
+
symbols_by_loc: Dict[Tuple[str, ops.Qid, int], Dict[str, sympy.Symbol]] = {}
|
|
241
|
+
|
|
242
|
+
def single_qubit_next_symbol() -> Dict[str, sympy.Symbol]:
|
|
243
|
+
sid = next(symbol_count)
|
|
244
|
+
return _parameterize(1, sid)
|
|
245
|
+
|
|
246
|
+
# Build parameterized circuit.
|
|
247
|
+
for moment_id, moment in enumerate(circuit):
|
|
248
|
+
center_moment: List[ops.Operation] = []
|
|
249
|
+
left_moment: List[ops.Operation] = []
|
|
250
|
+
right_moment: List[ops.Operation] = []
|
|
251
|
+
for op in moment:
|
|
252
|
+
if isinstance(op, ops.TaggedOperation) and set(op.tags).intersection(
|
|
253
|
+
context.tags_to_ignore
|
|
254
|
+
):
|
|
255
|
+
center_moment.append(op)
|
|
256
|
+
continue
|
|
257
|
+
if op.gate is not None and op in self.target:
|
|
258
|
+
# Build symbols for the gauge, for a 2-qubit gauge, symbols will be built for
|
|
259
|
+
# pre/post q0/q1 and the new 2-qubit gate if the 2-qubit gate is updated in
|
|
260
|
+
# the gauge compiling.
|
|
261
|
+
center_moment.append(op)
|
|
262
|
+
for prefix, q in itertools.product(["pre", "post"], op.qubits):
|
|
263
|
+
xza_by_symbols = single_qubit_next_symbol() # xza in phased xz gate.
|
|
264
|
+
loc = (prefix, q, moment_id)
|
|
265
|
+
symbols_by_loc[loc] = xza_by_symbols
|
|
266
|
+
new_op = ops.PhasedXZGate(**xza_by_symbols).on(q)
|
|
267
|
+
for symbol in xza_by_symbols.values():
|
|
268
|
+
values_by_params.update({str(symbol): []})
|
|
269
|
+
if prefix == "pre":
|
|
270
|
+
left_moment.append(new_op)
|
|
271
|
+
else:
|
|
272
|
+
right_moment.append(new_op)
|
|
273
|
+
else:
|
|
274
|
+
center_moment.append(op)
|
|
275
|
+
new_moments.extend(
|
|
276
|
+
[moment for moment in [left_moment, center_moment, right_moment] if moment]
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Assign values for parameters via randomly chosen GaugeSelector.
|
|
280
|
+
for _ in range(N):
|
|
281
|
+
for moment_id, moment in enumerate(circuit):
|
|
282
|
+
for op in moment:
|
|
283
|
+
if isinstance(op, ops.TaggedOperation) and set(op.tags).intersection(
|
|
284
|
+
context.tags_to_ignore
|
|
285
|
+
):
|
|
286
|
+
continue
|
|
287
|
+
if op.gate is not None and len(op.qubits) == 2 and op in self.target:
|
|
288
|
+
gauge = self.gauge_selector(rng).sample(op.gate, rng)
|
|
289
|
+
if not gauge.support_sweep:
|
|
290
|
+
raise NotImplementedError(
|
|
291
|
+
f"as_sweep isn't supported for {gauge.two_qubit_gate} gauge"
|
|
292
|
+
)
|
|
293
|
+
# Get the params of pre/post q0/q1 gates.
|
|
294
|
+
for pre_or_post, idx in itertools.product(["pre", "post"], [0, 1]):
|
|
295
|
+
symbols = symbols_by_loc[(pre_or_post, op.qubits[idx], moment_id)]
|
|
296
|
+
gates = getattr(gauge, f"{pre_or_post}_q{idx}")
|
|
297
|
+
phxz_params = _gate_sequence_to_phxz_params(gates, symbols)
|
|
298
|
+
for key, value in phxz_params.items():
|
|
299
|
+
values_by_params[key].append(value)
|
|
300
|
+
sweeps: List[Points] = [
|
|
301
|
+
Points(key=key, points=values) for key, values in values_by_params.items()
|
|
302
|
+
]
|
|
303
|
+
|
|
304
|
+
return circuits.Circuit.from_moments(*new_moments), Zip(*sweeps)
|
|
305
|
+
|
|
204
306
|
|
|
205
307
|
def _build_moments(operation_by_qubits: List[List[ops.Operation]]) -> List[List[ops.Operation]]:
|
|
206
308
|
"""Builds moments from a list of operations grouped by qubits.
|
|
@@ -212,3 +314,50 @@ def _build_moments(operation_by_qubits: List[List[ops.Operation]]) -> List[List[
|
|
|
212
314
|
for moment in itertools.zip_longest(*operation_by_qubits):
|
|
213
315
|
moments.append([op for op in moment if op is not None])
|
|
214
316
|
return moments
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def _parameterize(num_qubits: int, symbol_id: int) -> Dict[str, sympy.Symbol]:
|
|
320
|
+
"""Returns symbolized parameters for the gate."""
|
|
321
|
+
|
|
322
|
+
if num_qubits == 1: # Convert single qubit gate to parameterized PhasedXZGate.
|
|
323
|
+
phased_xz_params = {
|
|
324
|
+
"x_exponent": sympy.Symbol(f"x{symbol_id}"),
|
|
325
|
+
"z_exponent": sympy.Symbol(f"z{symbol_id}"),
|
|
326
|
+
"axis_phase_exponent": sympy.Symbol(f"a{symbol_id}"),
|
|
327
|
+
}
|
|
328
|
+
return phased_xz_params
|
|
329
|
+
raise NotImplementedError("parameterization for non single qubit gates is not supported yet")
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def _gate_sequence_to_phxz_params(
|
|
333
|
+
gates: Tuple[ops.Gate, ...], xza_by_symbols: Dict[str, sympy.Symbol]
|
|
334
|
+
) -> Dict[str, float]:
|
|
335
|
+
for gate in gates:
|
|
336
|
+
if not has_unitary(gate) or gate.num_qubits() != 1:
|
|
337
|
+
raise ValueError(
|
|
338
|
+
"Invalid gate sequence to be converted to PhasedXZGate."
|
|
339
|
+
f"Found incompatiable gate {gate} in sequence."
|
|
340
|
+
)
|
|
341
|
+
phxz = (
|
|
342
|
+
single_qubit_decompositions.single_qubit_matrix_to_phxz(
|
|
343
|
+
functools.reduce(
|
|
344
|
+
np.matmul, [unitary_protocol.unitary(gate) for gate in reversed(gates)]
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
or ops.I
|
|
348
|
+
)
|
|
349
|
+
if phxz is ops.I: # Identity gate
|
|
350
|
+
return {
|
|
351
|
+
str(xza_by_symbols["x_exponent"]): 0.0,
|
|
352
|
+
str(xza_by_symbols["z_exponent"]): 0.0,
|
|
353
|
+
str(xza_by_symbols["axis_phase_exponent"]): 0.0,
|
|
354
|
+
}
|
|
355
|
+
# Check the gate type, needs to be a PhasedXZ gate.
|
|
356
|
+
if not isinstance(phxz, ops.PhasedXZGate):
|
|
357
|
+
raise ValueError("Failed to convert the gate sequence to a PhasedXZ gate.")
|
|
358
|
+
if phxz is not None:
|
|
359
|
+
return {
|
|
360
|
+
str(xza_by_symbols["x_exponent"]): phxz.x_exponent,
|
|
361
|
+
str(xza_by_symbols["z_exponent"]): phxz.z_exponent,
|
|
362
|
+
str(xza_by_symbols["axis_phase_exponent"]): phxz.axis_phase_exponent,
|
|
363
|
+
}
|
|
@@ -12,10 +12,17 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import unittest.mock
|
|
15
16
|
import pytest
|
|
16
17
|
import numpy as np
|
|
17
18
|
import cirq
|
|
18
|
-
from cirq.transformers.gauge_compiling import
|
|
19
|
+
from cirq.transformers.gauge_compiling import (
|
|
20
|
+
GaugeTransformer,
|
|
21
|
+
CZGaugeTransformer,
|
|
22
|
+
ConstantGauge,
|
|
23
|
+
GaugeSelector,
|
|
24
|
+
)
|
|
25
|
+
from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
|
19
26
|
|
|
20
27
|
|
|
21
28
|
def test_deep_transformation_not_supported():
|
|
@@ -25,10 +32,19 @@ def test_deep_transformation_not_supported():
|
|
|
25
32
|
cirq.Circuit(), context=cirq.TransformerContext(deep=True)
|
|
26
33
|
)
|
|
27
34
|
|
|
35
|
+
with pytest.raises(ValueError, match="cannot be used with deep=True"):
|
|
36
|
+
_ = GaugeTransformer(target=cirq.CZ, gauge_selector=lambda _: None).as_sweep(
|
|
37
|
+
cirq.Circuit(), context=cirq.TransformerContext(deep=True), N=1
|
|
38
|
+
)
|
|
39
|
+
|
|
28
40
|
|
|
29
41
|
def test_ignore_tags():
|
|
30
42
|
c = cirq.Circuit(cirq.CZ(*cirq.LineQubit.range(2)).with_tags('foo'))
|
|
31
43
|
assert c == CZGaugeTransformer(c, context=cirq.TransformerContext(tags_to_ignore={"foo"}))
|
|
44
|
+
parameterized_circuit, _ = CZGaugeTransformer.as_sweep(
|
|
45
|
+
c, context=cirq.TransformerContext(tags_to_ignore={"foo"}), N=1
|
|
46
|
+
)
|
|
47
|
+
assert c == parameterized_circuit
|
|
32
48
|
|
|
33
49
|
|
|
34
50
|
def test_target_can_be_gateset():
|
|
@@ -39,3 +55,71 @@ def test_target_can_be_gateset():
|
|
|
39
55
|
)
|
|
40
56
|
want = cirq.Circuit(cirq.Y.on_each(qs), cirq.CZ(*qs), cirq.X.on_each(qs))
|
|
41
57
|
assert transformer(c, prng=np.random.default_rng(0)) == want
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_as_sweep_multi_pre_or_multi_post():
|
|
61
|
+
transformer = GaugeTransformer(
|
|
62
|
+
target=cirq.CZ,
|
|
63
|
+
gauge_selector=GaugeSelector(
|
|
64
|
+
gauges=[
|
|
65
|
+
ConstantGauge(
|
|
66
|
+
two_qubit_gate=cirq.CZ,
|
|
67
|
+
support_sweep=True,
|
|
68
|
+
pre_q0=[cirq.X, cirq.X],
|
|
69
|
+
post_q0=[cirq.Z],
|
|
70
|
+
pre_q1=[cirq.Y],
|
|
71
|
+
post_q1=[cirq.Y, cirq.Y, cirq.Y],
|
|
72
|
+
)
|
|
73
|
+
]
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
qs = cirq.LineQubit.range(2)
|
|
77
|
+
input_circuit = cirq.Circuit(cirq.CZ(*qs))
|
|
78
|
+
parameterized_circuit, sweeps = transformer.as_sweep(input_circuit, N=1)
|
|
79
|
+
|
|
80
|
+
for params in sweeps:
|
|
81
|
+
compiled_circuit = cirq.resolve_parameters(parameterized_circuit, params)
|
|
82
|
+
cirq.testing.assert_circuits_have_same_unitary_given_final_permutation(
|
|
83
|
+
input_circuit, compiled_circuit, qubit_map={q: q for q in input_circuit.all_qubits()}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_as_sweep_invalid_gauge_sequence():
|
|
88
|
+
transfomer = GaugeTransformer(
|
|
89
|
+
target=cirq.CZ,
|
|
90
|
+
gauge_selector=GaugeSelector(
|
|
91
|
+
gauges=[
|
|
92
|
+
ConstantGauge(
|
|
93
|
+
two_qubit_gate=cirq.CZ,
|
|
94
|
+
support_sweep=True,
|
|
95
|
+
pre_q0=[cirq.measure],
|
|
96
|
+
post_q0=[cirq.Z],
|
|
97
|
+
pre_q1=[cirq.X],
|
|
98
|
+
post_q1=[cirq.Z],
|
|
99
|
+
)
|
|
100
|
+
]
|
|
101
|
+
),
|
|
102
|
+
)
|
|
103
|
+
qs = cirq.LineQubit.range(2)
|
|
104
|
+
c = cirq.Circuit(cirq.CZ(*qs))
|
|
105
|
+
with pytest.raises(ValueError, match="Invalid gate sequence to be converted to PhasedXZGate."):
|
|
106
|
+
transfomer.as_sweep(c, N=1)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_as_sweep_convert_to_phxz_failed():
|
|
110
|
+
qs = cirq.LineQubit.range(2)
|
|
111
|
+
c = cirq.Circuit(cirq.CZ(*qs))
|
|
112
|
+
|
|
113
|
+
def mock_single_qubit_matrix_to_phxz(*args, **kwargs):
|
|
114
|
+
# Return an non PhasedXZ gate, so we expect errors from as_sweep().
|
|
115
|
+
return cirq.X
|
|
116
|
+
|
|
117
|
+
with unittest.mock.patch.object(
|
|
118
|
+
single_qubit_decompositions,
|
|
119
|
+
"single_qubit_matrix_to_phxz",
|
|
120
|
+
new=mock_single_qubit_matrix_to_phxz,
|
|
121
|
+
):
|
|
122
|
+
with pytest.raises(
|
|
123
|
+
ValueError, match="Failed to convert the gate sequence to a PhasedXZ gate."
|
|
124
|
+
):
|
|
125
|
+
_ = CZGaugeTransformer.as_sweep(c, context=cirq.TransformerContext(), N=1)
|
|
@@ -27,6 +27,7 @@ class GaugeTester:
|
|
|
27
27
|
two_qubit_gate: cirq.Gate
|
|
28
28
|
gauge_transformer: GaugeTransformer
|
|
29
29
|
must_fail: bool = False
|
|
30
|
+
sweep_must_pass: bool = False
|
|
30
31
|
|
|
31
32
|
@pytest.mark.parametrize(
|
|
32
33
|
['generation_seed', 'transformation_seed'],
|
|
@@ -73,6 +74,42 @@ class GaugeTester:
|
|
|
73
74
|
else:
|
|
74
75
|
_check_equivalent_with_error_message(c, nc, gauge)
|
|
75
76
|
|
|
77
|
+
def test_sweep(self):
|
|
78
|
+
qubits = cirq.LineQubit.range(3)
|
|
79
|
+
|
|
80
|
+
if not self.sweep_must_pass:
|
|
81
|
+
with pytest.raises(NotImplementedError):
|
|
82
|
+
self.gauge_transformer.as_sweep(
|
|
83
|
+
cirq.Circuit(cirq.Moment(self.two_qubit_gate(*qubits[:2]))), N=1
|
|
84
|
+
)
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
input_circuit = cirq.Circuit(
|
|
88
|
+
cirq.Moment(cirq.H(qubits[0])),
|
|
89
|
+
cirq.Moment(self.two_qubit_gate(*qubits[:2])),
|
|
90
|
+
cirq.Moment(self.two_qubit_gate(*qubits[1:])),
|
|
91
|
+
cirq.Moment([cirq.H(q) for q in qubits]),
|
|
92
|
+
cirq.Moment([cirq.measure(q) for q in qubits]),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
n_samples = 5
|
|
96
|
+
parameterized_circuit, sweeps = self.gauge_transformer.as_sweep(input_circuit, N=n_samples)
|
|
97
|
+
|
|
98
|
+
# Check the parameterized circuit and N set of parameters.
|
|
99
|
+
assert cirq.is_parameterized(parameterized_circuit)
|
|
100
|
+
simulator = cirq.Simulator()
|
|
101
|
+
results = simulator.run_sweep(parameterized_circuit, sweeps)
|
|
102
|
+
assert len(results) == n_samples
|
|
103
|
+
|
|
104
|
+
# Check compilied circuits have the same unitary as the orig circuit.
|
|
105
|
+
for params in sweeps:
|
|
106
|
+
compiled_circuit = cirq.resolve_parameters(parameterized_circuit, params)
|
|
107
|
+
cirq.testing.assert_circuits_have_same_unitary_given_final_permutation(
|
|
108
|
+
input_circuit[:-1],
|
|
109
|
+
compiled_circuit[:-1],
|
|
110
|
+
qubit_map={q: q for q in input_circuit.all_qubits()},
|
|
111
|
+
)
|
|
112
|
+
|
|
76
113
|
|
|
77
114
|
def _check_equivalent_with_error_message(c: cirq.AbstractCircuit, nc: cirq.AbstractCircuit, gauge):
|
|
78
115
|
try:
|
|
@@ -26,7 +26,15 @@ class ExampleGate(cirq.testing.TwoQubitGate):
|
|
|
26
26
|
return self.unitary
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
class ExampleSweepGate(cirq.testing.TwoQubitGate):
|
|
30
|
+
unitary = cirq.unitary(cirq.CZ)
|
|
31
|
+
|
|
32
|
+
def _unitary_(self) -> np.ndarray:
|
|
33
|
+
return self.unitary
|
|
34
|
+
|
|
35
|
+
|
|
29
36
|
_EXAMPLE_TARGET = ExampleGate()
|
|
37
|
+
_EXAMPLE_SWEEP_TARGET = ExampleSweepGate()
|
|
30
38
|
|
|
31
39
|
_GOOD_TRANSFORMER = GaugeTransformer(
|
|
32
40
|
target=_EXAMPLE_TARGET,
|
|
@@ -40,6 +48,22 @@ _BAD_TRANSFORMER = GaugeTransformer(
|
|
|
40
48
|
),
|
|
41
49
|
)
|
|
42
50
|
|
|
51
|
+
_TRANSFORMER_WITH_SWEEP = GaugeTransformer(
|
|
52
|
+
target=_EXAMPLE_SWEEP_TARGET,
|
|
53
|
+
gauge_selector=GaugeSelector(
|
|
54
|
+
gauges=[
|
|
55
|
+
ConstantGauge(
|
|
56
|
+
two_qubit_gate=_EXAMPLE_SWEEP_TARGET,
|
|
57
|
+
pre_q0=cirq.Z,
|
|
58
|
+
pre_q1=cirq.Z,
|
|
59
|
+
post_q0=cirq.Z,
|
|
60
|
+
post_q1=cirq.Z,
|
|
61
|
+
support_sweep=True,
|
|
62
|
+
)
|
|
63
|
+
]
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
|
|
43
67
|
|
|
44
68
|
class TestValidTransformer(GaugeTester):
|
|
45
69
|
two_qubit_gate = _EXAMPLE_TARGET
|
|
@@ -50,3 +74,9 @@ class TestInvalidTransformer(GaugeTester):
|
|
|
50
74
|
two_qubit_gate = _EXAMPLE_TARGET
|
|
51
75
|
gauge_transformer = _BAD_TRANSFORMER
|
|
52
76
|
must_fail = True
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class TestSweep(GaugeTester):
|
|
80
|
+
two_qubit_gate = _EXAMPLE_SWEEP_TARGET
|
|
81
|
+
gauge_transformer = _TRANSFORMER_WITH_SWEEP
|
|
82
|
+
sweep_must_pass = True
|
{cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cirq-core
|
|
3
|
-
Version: 1.5.0.
|
|
3
|
+
Version: 1.5.0.dev20241221000556
|
|
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.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/RECORD
RENAMED
|
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=Qq3ZcfgD-Nb81cEppQdJqhAyrVqXKtfXZYGXT0p-Wh0,34718
|
|
|
4
4
|
cirq/_doc.py,sha256=yDyWUD_2JDS0gShfGRb-rdqRt9-WeL7DhkqX7np0Nko,2879
|
|
5
5
|
cirq/_import.py,sha256=p9gMHJscbtDDkfHOaulvd3Aer0pwUF5AXpL89XR8dNw,8402
|
|
6
6
|
cirq/_import_test.py,sha256=6K_v0riZJXOXUphHNkGA8MY-JcmGlezFaGmvrNhm3OQ,1015
|
|
7
|
-
cirq/_version.py,sha256=
|
|
8
|
-
cirq/_version_test.py,sha256=
|
|
7
|
+
cirq/_version.py,sha256=OqoCeE--Ab9NG2PKQn-oiComWbF_Pgw1sRYHYc8sEY0,1206
|
|
8
|
+
cirq/_version_test.py,sha256=UMG2gtNTe_70vsxwkOgm2BvpCnF9uav4WLuoPUqXTjY,147
|
|
9
9
|
cirq/conftest.py,sha256=X7yLFL8GLhg2CjPw0hp5e_dGASfvHx1-QT03aUbhKJw,1168
|
|
10
10
|
cirq/json_resolver_cache.py,sha256=03MVo6Y-UYrzt9CKHmwpiBLN2ixL6uSU-OWnKZXfG7k,13302
|
|
11
11
|
cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
|
|
@@ -1092,12 +1092,12 @@ cirq/transformers/analytical_decompositions/two_qubit_to_ms_test.py,sha256=85Mbu
|
|
|
1092
1092
|
cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py,sha256=F_XpM4ApYHxV6hbWnV3C7Ud9L1BnpvBHBXShPh2mP3k,25397
|
|
1093
1093
|
cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py,sha256=eKOzjWkR7xs-CL2oPj__nWXR0LL9oO42wEHibnvWq-o,20618
|
|
1094
1094
|
cirq/transformers/gauge_compiling/__init__.py,sha256=ZF53ZtYRJeKsVJYjKc_QrAqE1pyd8FFmmb6Wo8JdgQs,1385
|
|
1095
|
-
cirq/transformers/gauge_compiling/cz_gauge.py,sha256=
|
|
1096
|
-
cirq/transformers/gauge_compiling/cz_gauge_test.py,sha256=
|
|
1097
|
-
cirq/transformers/gauge_compiling/gauge_compiling.py,sha256=
|
|
1098
|
-
cirq/transformers/gauge_compiling/gauge_compiling_test.py,sha256=
|
|
1099
|
-
cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py,sha256=
|
|
1100
|
-
cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py,sha256=
|
|
1095
|
+
cirq/transformers/gauge_compiling/cz_gauge.py,sha256=pJ41uVaUltigKLIayxr0XMqTYEs0zUDnaWD-tp65pPk,4198
|
|
1096
|
+
cirq/transformers/gauge_compiling/cz_gauge_test.py,sha256=sHEgEEI_z9-Ka5ChN2JmtoYcEHhNYHysOjGJzaaKkoA,881
|
|
1097
|
+
cirq/transformers/gauge_compiling/gauge_compiling.py,sha256=MyzYcgr0vl0pzOq41jkzmrM6COsDg7e2iU_xQcUoQ20,15063
|
|
1098
|
+
cirq/transformers/gauge_compiling/gauge_compiling_test.py,sha256=Nm0Uxqrq1Y5puQep9UpKXK2zg9a3Dx2NSFArIxeawUg,4444
|
|
1099
|
+
cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py,sha256=7RNZ6-xQ1iKjoNWTokgok7xTCeAnrQUzbpdBhdJZEfY,4933
|
|
1100
|
+
cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py,sha256=cWEAP1EWbpHNp7wQPXLyT413raoG3aIg8aFod_aXAtQ,2340
|
|
1101
1101
|
cirq/transformers/gauge_compiling/iswap_gauge.py,sha256=UGJ_061h65Rfgb9LWREjxC8OSt01ZqP9TGnacL8VAuk,3500
|
|
1102
1102
|
cirq/transformers/gauge_compiling/iswap_gauge_test.py,sha256=HEIIwKlX5ixau1e_etSUj5NvYOVTT-Gc3kuHcyKAeJ4,866
|
|
1103
1103
|
cirq/transformers/gauge_compiling/spin_inversion_gauge.py,sha256=gfjSlQdo13GfBPlrkQoHPWWzouiV7yYr7JAaB85NSGY,1086
|
|
@@ -1189,8 +1189,8 @@ cirq/work/sampler.py,sha256=bE5tmVkcR6cZZMLETxDfHehdsYUMbx2RvBeIBetehI4,19187
|
|
|
1189
1189
|
cirq/work/sampler_test.py,sha256=hL2UWx3dz2ukZVNxWftiKVvJcQoLplLZdQm-k1QcA40,13282
|
|
1190
1190
|
cirq/work/zeros_sampler.py,sha256=x1C7cup66a43n-3tm8QjhiqJa07qcJW10FxNp9jJ59Q,2356
|
|
1191
1191
|
cirq/work/zeros_sampler_test.py,sha256=JIkpBBFPJe5Ba4142vzogyWyboG1Q1ZAm0UVGgOoZn8,3279
|
|
1192
|
-
cirq_core-1.5.0.
|
|
1193
|
-
cirq_core-1.5.0.
|
|
1194
|
-
cirq_core-1.5.0.
|
|
1195
|
-
cirq_core-1.5.0.
|
|
1196
|
-
cirq_core-1.5.0.
|
|
1192
|
+
cirq_core-1.5.0.dev20241221000556.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
1193
|
+
cirq_core-1.5.0.dev20241221000556.dist-info/METADATA,sha256=P70dL9Vm3tnlLFwyneVhZiRBS6axK3zAqZcEOrgNckg,1992
|
|
1194
|
+
cirq_core-1.5.0.dev20241221000556.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
1195
|
+
cirq_core-1.5.0.dev20241221000556.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
|
|
1196
|
+
cirq_core-1.5.0.dev20241221000556.dist-info/RECORD,,
|
{cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/LICENSE
RENAMED
|
File without changes
|
{cirq_core-1.5.0.dev20241220195200.dist-info → cirq_core-1.5.0.dev20241221000556.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|