cirq-core 1.5.0.dev20241219205221__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 CHANGED
@@ -28,4 +28,4 @@ if sys.version_info < (3, 10, 0): # pragma: no cover
28
28
  'of cirq (e.g. "python -m pip install cirq==1.1.*")'
29
29
  )
30
30
 
31
- __version__ = "1.5.0.dev20241219205221"
31
+ __version__ = "1.5.0.dev20241221000556"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version():
6
- assert cirq.__version__ == "1.5.0.dev20241219205221"
6
+ assert cirq.__version__ == "1.5.0.dev20241221000556"
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """Provides a method to do z-phase calibration for excitation-preserving gates."""
16
- from typing import Union, Optional, Sequence, Tuple, Dict, TYPE_CHECKING, Any
16
+ from typing import Union, Optional, Sequence, Tuple, Dict, TYPE_CHECKING, Any, List
17
17
  import multiprocessing
18
18
  import multiprocessing.pool
19
19
 
@@ -22,7 +22,8 @@ import numpy as np
22
22
 
23
23
  from cirq.experiments import xeb_fitting
24
24
  from cirq.experiments.two_qubit_xeb import parallel_xeb_workflow
25
- from cirq import ops
25
+ from cirq.transformers import transformer_api
26
+ from cirq import ops, circuits, protocols
26
27
 
27
28
  if TYPE_CHECKING:
28
29
  import cirq
@@ -283,3 +284,84 @@ def plot_z_phase_calibration_result(
283
284
  ax.set_title('-'.join(str(q) for q in pair))
284
285
  ax.legend()
285
286
  return axes
287
+
288
+
289
+ def _z_angles(old: ops.PhasedFSimGate, new: ops.PhasedFSimGate) -> Tuple[float, float, float]:
290
+ """Computes a set of possible 3 z-phases that result in the change in gamma, zeta, and chi."""
291
+ # This procedure is the inverse of PhasedFSimGate.from_fsim_rz
292
+ delta_gamma = new.gamma - old.gamma
293
+ delta_zeta = new.zeta - old.zeta
294
+ delta_chi = new.chi - old.chi
295
+ return (-delta_gamma + delta_chi, -delta_gamma - delta_zeta, delta_zeta - delta_chi)
296
+
297
+
298
+ @transformer_api.transformer
299
+ class CalibrationTransformer:
300
+
301
+ def __init__(
302
+ self,
303
+ target: 'cirq.Gate',
304
+ calibration_map: Dict[Tuple['cirq.Qid', 'cirq.Qid'], 'cirq.PhasedFSimGate'],
305
+ ):
306
+ """Create a CalibrationTransformer.
307
+
308
+ The transformer adds 3 ZPowGates around each calibrated gate to cancel the
309
+ effect of z-phases.
310
+
311
+ Args:
312
+ target: The target gate. Any gate matching this
313
+ will be replaced based on the content of `calibration_map`.
314
+ calibration_map:
315
+ A map mapping qubit pairs to calibrated gates. This is the output of
316
+ calling `calibrate_z_phases`.
317
+ """
318
+ self.target = target
319
+ if isinstance(target, ops.PhasedFSimGate):
320
+ self.target_as_fsim = target
321
+ elif (gate := ops.PhasedFSimGate.from_matrix(protocols.unitary(target))) is not None:
322
+ self.target_as_fsim = gate
323
+ else:
324
+ raise ValueError(f"{target} is not equivalent to a PhasedFSimGate")
325
+ self.calibration_map = calibration_map
326
+
327
+ def __call__(
328
+ self,
329
+ circuit: 'cirq.AbstractCircuit',
330
+ *,
331
+ context: Optional[transformer_api.TransformerContext] = None,
332
+ ) -> 'cirq.Circuit':
333
+ """Adds 3 ZPowGates around each calibrated gate to cancel the effect of Z phases.
334
+
335
+ Args:
336
+ circuit: Circuit to transform.
337
+ context: Optional transformer context (not used).
338
+
339
+ Returns:
340
+ New circuit with the extra ZPowGates.
341
+ """
342
+ new_moments: List[Union[List[cirq.Operation], 'cirq.Moment']] = []
343
+ for moment in circuit:
344
+ before = []
345
+ after = []
346
+ for op in moment:
347
+ if op.gate != self.target:
348
+ # not a target.
349
+ continue
350
+ assert len(op.qubits) == 2
351
+ gate = self.calibration_map.get(op.qubits, None) or self.calibration_map.get(
352
+ op.qubits[::-1], None
353
+ )
354
+ if gate is None:
355
+ # no calibration available.
356
+ continue
357
+ angles = np.array(_z_angles(self.target_as_fsim, gate)) / np.pi
358
+ angles = -angles # Take the negative to cancel the effect.
359
+ before.append(ops.Z(op.qubits[0]) ** angles[0])
360
+ before.append(ops.Z(op.qubits[1]) ** angles[1])
361
+ after.append(ops.Z(op.qubits[0]) ** angles[2])
362
+ if before:
363
+ new_moments.append(before)
364
+ new_moments.append(moment)
365
+ if after:
366
+ new_moments.append(after)
367
+ return circuits.Circuit.from_moments(*new_moments)
@@ -22,6 +22,7 @@ from cirq.experiments.z_phase_calibration import (
22
22
  calibrate_z_phases,
23
23
  z_phase_calibration_workflow,
24
24
  plot_z_phase_calibration_result,
25
+ CalibrationTransformer,
25
26
  )
26
27
  from cirq.experiments.xeb_fitting import XEBPhasedFSimCharacterizationOptions
27
28
 
@@ -205,3 +206,33 @@ def test_plot_z_phase_calibration_result():
205
206
  np.testing.assert_allclose(axes[1].lines[0].get_xdata().astype(float), [1, 2, 3])
206
207
  np.testing.assert_allclose(axes[1].lines[0].get_ydata().astype(float), [0.6, 0.4, 0.1])
207
208
  np.testing.assert_allclose(axes[1].lines[1].get_ydata().astype(float), [0.7, 0.77, 0.8])
209
+
210
+
211
+ @pytest.mark.parametrize('angles', 2 * np.pi * np.random.random((10, 10)))
212
+ def test_transform_circuit(angles):
213
+ theta, phi = angles[:2]
214
+ old_zs = angles[2:6]
215
+ new_zs = angles[6:]
216
+ gate = cirq.PhasedFSimGate.from_fsim_rz(theta, phi, old_zs[:2], old_zs[2:])
217
+ fsim = cirq.PhasedFSimGate.from_fsim_rz(theta, phi, new_zs[:2], new_zs[2:])
218
+ c = cirq.Circuit(gate(cirq.q(0), cirq.q(1)))
219
+ replacement_map = {(cirq.q(1), cirq.q(0)): fsim}
220
+
221
+ new_circuit = CalibrationTransformer(gate, replacement_map)(c)
222
+
223
+ # we replace the old gate with the `fsim` gate the result should be that the overall
224
+ # unitary equals the unitary of the original (ideal) gate.
225
+ circuit_with_replacement_gate = cirq.Circuit(
226
+ op if op.gate != gate else fsim(*op.qubits) for op in new_circuit.all_operations()
227
+ )
228
+ np.testing.assert_allclose(cirq.unitary(circuit_with_replacement_gate), cirq.unitary(c))
229
+
230
+
231
+ def test_transform_circuit_invalid_gate_raises():
232
+ with pytest.raises(ValueError, match="is not equivalent to a PhasedFSimGate"):
233
+ _ = CalibrationTransformer(cirq.XX, {})
234
+
235
+
236
+ def test_transform_circuit_uncalibrated_gates_pass():
237
+ c = cirq.Circuit(cirq.CZ(cirq.q(0), cirq.q(1)), cirq.measure(cirq.q(0)))
238
+ assert c == CalibrationTransformer(cirq.CZ, {})(c)
cirq/ops/fsim_gate.py CHANGED
@@ -347,6 +347,45 @@ class PhasedFSimGate(gate_features.InterchangeableQubitsGate, raw_types.Gate):
347
347
  chi = (b0 - b1 - a0 + a1) / 2.0
348
348
  return PhasedFSimGate(theta, zeta, chi, gamma, phi)
349
349
 
350
+ @staticmethod
351
+ def from_matrix(u: np.ndarray) -> Optional['PhasedFSimGate']:
352
+ """Contruct a PhasedFSimGate from unitary.
353
+
354
+ Args:
355
+ u: A unitary matrix representing a PhasedFSimGate.
356
+
357
+ Returns:
358
+ - Either PhasedFSimGate with the given unitary or None if
359
+ the matrix is not unitary or if doesn't represent a PhasedFSimGate.
360
+ """
361
+
362
+ gamma = np.angle(u[1, 1] * u[2, 2] - u[1, 2] * u[2, 1]) / -2
363
+ phi = -np.angle(u[3, 3]) - 2 * gamma
364
+ phased_cos_theta_2 = u[1, 1] * u[2, 2]
365
+ if phased_cos_theta_2 == 0:
366
+ # The zeta phase is multiplied with cos(theta),
367
+ # so if cos(theta) is zero then any value is possible.
368
+ zeta = 0
369
+ else:
370
+ zeta = np.angle(u[2, 2] / u[1, 1]) / 2
371
+
372
+ phased_sin_theta_2 = u[1, 2] * u[2, 1]
373
+ if phased_sin_theta_2 == 0:
374
+ # The chi phase is multiplied with sin(theta),
375
+ # so if sin(theta) is zero then any value is possible.
376
+ chi = 0
377
+ else:
378
+ chi = np.angle(u[1, 2] / u[2, 1]) / 2
379
+
380
+ theta = np.angle(
381
+ np.exp(1j * (gamma + zeta)) * u[1, 1] - np.exp(1j * (gamma - chi)) * u[1, 2]
382
+ )
383
+
384
+ gate = PhasedFSimGate(theta=theta, phi=phi, chi=chi, zeta=zeta, gamma=gamma)
385
+ if np.allclose(u, protocols.unitary(gate)):
386
+ return gate
387
+ return None
388
+
350
389
  @property
351
390
  def rz_angles_before(self) -> Tuple['cirq.TParamVal', 'cirq.TParamVal']:
352
391
  """Returns 2-tuple of phase angles applied to qubits before FSimGate."""
@@ -797,3 +797,24 @@ def test_phased_fsim_json_dict():
797
797
  assert cirq.PhasedFSimGate(
798
798
  theta=0.12, zeta=0.34, chi=0.56, gamma=0.78, phi=0.9
799
799
  )._json_dict_() == {'theta': 0.12, 'zeta': 0.34, 'chi': 0.56, 'gamma': 0.78, 'phi': 0.9}
800
+
801
+
802
+ @pytest.mark.parametrize(
803
+ 'gate',
804
+ [
805
+ cirq.CZ,
806
+ cirq.SQRT_ISWAP,
807
+ cirq.SQRT_ISWAP_INV,
808
+ cirq.ISWAP,
809
+ cirq.ISWAP_INV,
810
+ cirq.cphase(0.1),
811
+ cirq.CZ**0.2,
812
+ ],
813
+ )
814
+ def test_phase_fsim_from_matrix(gate):
815
+ u = cirq.unitary(gate)
816
+ np.testing.assert_allclose(cirq.unitary(cirq.PhasedFSimGate.from_matrix(u)), u, atol=1e-8)
817
+
818
+
819
+ def test_phase_fsim_from_matrix_not_fsim_returns_none():
820
+ assert cirq.PhasedFSimGate.from_matrix(np.ones((4, 4))) is None
@@ -24,22 +24,134 @@ from cirq import ops
24
24
 
25
25
  CZGaugeSelector = GaugeSelector(
26
26
  gauges=[
27
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.I, pre_q1=ops.I, post_q0=ops.I, post_q1=ops.I),
28
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.I, pre_q1=ops.X, post_q0=ops.Z, post_q1=ops.X),
29
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.I, pre_q1=ops.Y, post_q0=ops.Z, post_q1=ops.Y),
30
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.I, pre_q1=ops.Z, post_q0=ops.I, post_q1=ops.Z),
31
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.X, pre_q1=ops.I, post_q0=ops.X, post_q1=ops.Z),
32
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.X, pre_q1=ops.X, post_q0=ops.Y, post_q1=ops.Y),
33
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.X, pre_q1=ops.Y, post_q0=ops.Y, post_q1=ops.X),
34
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.X, pre_q1=ops.Z, post_q0=ops.X, post_q1=ops.I),
35
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Y, pre_q1=ops.I, post_q0=ops.Y, post_q1=ops.Z),
36
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Y, pre_q1=ops.X, post_q0=ops.X, post_q1=ops.Y),
37
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Y, pre_q1=ops.Y, post_q0=ops.X, post_q1=ops.X),
38
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Y, pre_q1=ops.Z, post_q0=ops.Y, post_q1=ops.I),
39
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Z, pre_q1=ops.I, post_q0=ops.Z, post_q1=ops.I),
40
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Z, pre_q1=ops.X, post_q0=ops.I, post_q1=ops.X),
41
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Z, pre_q1=ops.Y, post_q0=ops.I, post_q1=ops.Y),
42
- ConstantGauge(two_qubit_gate=CZ, pre_q0=ops.Z, pre_q1=ops.Z, post_q0=ops.Z, post_q1=ops.Z),
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
 
@@ -21,3 +21,4 @@ from cirq.transformers.gauge_compiling.gauge_compiling_test_utils import GaugeTe
21
21
  class TestCZGauge(GaugeTester):
22
22
  two_qubit_gate = cirq.CZ
23
23
  gauge_transformer = CZGaugeTransformer
24
+ sweep_must_pass = True
@@ -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 GaugeTransformer, CZGaugeTransformer
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cirq-core
3
- Version: 1.5.0.dev20241219205221
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
@@ -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=LgYBHy4-TNt8aWBSL-jhQ7q-NeQUCK8I9jbPHuvcE2M,1206
8
- cirq/_version_test.py,sha256=iRVS_dYH5tfWJBzIJnvIXBfnhMrAk9rshfCOdmo5Bz0,147
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
@@ -203,8 +203,8 @@ cirq/experiments/xeb_sampling.py,sha256=6ZOidGi7Kt6p4cMQCjK7qQuIUXVHCYl47B2GnL8M
203
203
  cirq/experiments/xeb_sampling_test.py,sha256=0XkQGvcURsug3IblE_wZrHVDoOQV3WuQilrqCJbDHjI,6784
204
204
  cirq/experiments/xeb_simulation.py,sha256=yML2NAnYTRFG1wsQHvxtNEGEMXuExbWjrE2JYuCqnrk,5076
205
205
  cirq/experiments/xeb_simulation_test.py,sha256=YWFKXPdtBFuZNhQoG06W1EetVhXighc3zyXwhKfGAeo,5652
206
- cirq/experiments/z_phase_calibration.py,sha256=6N83Ky3zkhT5LMKx0TqNe2UAQbb-rp4nzuTG31GFELg,11884
207
- cirq/experiments/z_phase_calibration_test.py,sha256=Hk6FR-mvlkwol1WQvc75gw6oC_adRW-0_JF5y0X598E,7592
206
+ cirq/experiments/z_phase_calibration.py,sha256=2mkpmtY60hQuaB91If6eAL_q_nW88hwJ2Pqdq9R_iTE,15152
207
+ cirq/experiments/z_phase_calibration_test.py,sha256=BJ88waxTxRUsKSoFnkYkvhKxKwBNSmYCuZII6X-R36g,8904
208
208
  cirq/interop/__init__.py,sha256=Xt1xU9UegP_jBNa9xaeOFSgtC0lYb_HNHq4hQQ0J20k,784
209
209
  cirq/interop/quirk/__init__.py,sha256=W11jqaExSgvoUkjM_d0Kik4R8bqETF9Ezo27CDEB3iw,1237
210
210
  cirq/interop/quirk/url_to_circuit.py,sha256=1ToWnFJdJIhCko9q62BEvOoCGxCpOUl8891IdCa52MM,14211
@@ -292,8 +292,8 @@ cirq/ops/eigen_gate.py,sha256=eQ6-MOknop7CrejsTuQ0KZWf4mZnQBi8wEaTQXw4KSQ,18334
292
292
  cirq/ops/eigen_gate_test.py,sha256=-7l6GmAd1EYzHoGREQN1n7J1VOQKbThH2mA88TRODs8,13928
293
293
  cirq/ops/fourier_transform.py,sha256=pynO07OcZSVCeL8L0pNQ9m_y5_wrpTWOMf99BHpjXdU,7579
294
294
  cirq/ops/fourier_transform_test.py,sha256=PIK4bWnCIy2TuX0fgclHeU1CBDT6zRVoQpv1v1jt62c,6220
295
- cirq/ops/fsim_gate.py,sha256=eAQP2XPWW_1nItjzv__75eqhruCbKkFB1Y_eL1ov10c,18725
296
- cirq/ops/fsim_gate_test.py,sha256=owW1VpXntJqxlzhtppnyfaS9gQKFNA6UzCHksgPHaHU,25165
295
+ cirq/ops/fsim_gate.py,sha256=Avzlcb_O201K0_tBmNR5m9fWkpBM7Nby0MfJjNJ9g_8,20136
296
+ cirq/ops/fsim_gate_test.py,sha256=4kFk0ALzTmaskQURHPl6JerNvw8gbZn49nt1_WAjpdY,25671
297
297
  cirq/ops/gate_features.py,sha256=414mSi3kgKSwLOeAG_WEZKn8ZMaLtOowed7os1qSnM4,1049
298
298
  cirq/ops/gate_features_test.py,sha256=mnlqJnSpllcOnTUdvmUs_ssnPRhAIgHhKIAK2Z86Dfg,2347
299
299
  cirq/ops/gate_operation.py,sha256=IGCyqe9YguIlajnQ3EV61Y0vUxOT_SrRxvNEFwKtUak,13720
@@ -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=TNZviXFu4j-lCF87QMGYVdb2RC_ePHLdI6FRCqh9go4,2550
1096
- cirq/transformers/gauge_compiling/cz_gauge_test.py,sha256=_2RMzwuMoqytgsVZEET2m6QsGoZ2_uWgBfSGGvhZEWo,854
1097
- cirq/transformers/gauge_compiling/gauge_compiling.py,sha256=7jUg2MHVX2V8SzH7r27e_BUUA_p5l15-Qv8lLlhGasQ,7948
1098
- cirq/transformers/gauge_compiling/gauge_compiling_test.py,sha256=xVeoaaMuenlp_pxqmZO89kJEeBV0iapK7-JDTUuC7Lg,1565
1099
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py,sha256=6mpF2ftcDtWQEsZNr-m16GkDOn5WBWV08JB4ZS5rf8M,3408
1100
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py,sha256=HQw1xeko9OAD0PCuKcehUiy8mbxeRza4nE-6E8MGVME,1584
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.dev20241219205221.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1193
- cirq_core-1.5.0.dev20241219205221.dist-info/METADATA,sha256=sUEl9aQuRY9clOGfxIhMygmHjCE89UTc7hGDjel2gHM,1992
1194
- cirq_core-1.5.0.dev20241219205221.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
1195
- cirq_core-1.5.0.dev20241219205221.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1196
- cirq_core-1.5.0.dev20241219205221.dist-info/RECORD,,
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,,