cirq-core 1.6.0.dev20250501192724__py3-none-any.whl → 1.6.0.dev20250501231232__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.6.0.dev20250501192724"
31
+ __version__ = "1.6.0.dev20250501231232"
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.6.0.dev20250501192724"
6
+ assert cirq.__version__ == "1.6.0.dev20250501231232"
@@ -12,8 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  """Tools for measuring expectation values of Pauli strings with readout error mitigation."""
15
+ import itertools
15
16
  import time
16
- from typing import Dict, List, Optional, Tuple, Union
17
+ from typing import cast, Dict, FrozenSet, List, Optional, Sequence, Tuple, Union
17
18
 
18
19
  import attrs
19
20
  import numpy as np
@@ -59,8 +60,74 @@ class CircuitToPauliStringsMeasurementResult:
59
60
  results: List[PauliStringMeasurementResult]
60
61
 
61
62
 
63
+ def _commute_or_identity(
64
+ op1: Union[ops.Pauli, ops.IdentityGate], op2: Union[ops.Pauli, ops.IdentityGate]
65
+ ) -> bool:
66
+ if op1 == ops.I or op2 == ops.I:
67
+ return True
68
+ return op1 == op2
69
+
70
+
71
+ def _are_two_pauli_strings_qubit_wise_commuting(
72
+ pauli_str1: ops.PauliString,
73
+ pauli_str2: ops.PauliString,
74
+ all_qubits: Union[list[ops.Qid], FrozenSet[ops.Qid]],
75
+ ) -> bool:
76
+ for qubit in all_qubits:
77
+ op1 = pauli_str1.get(qubit, default=ops.I)
78
+ op2 = pauli_str2.get(qubit, default=ops.I)
79
+
80
+ if not _commute_or_identity(op1, op2):
81
+ return False
82
+ return True
83
+
84
+
85
+ def _validate_group_paulis_qwc(
86
+ pauli_strs: list[ops.PauliString], all_qubits: Union[list[ops.Qid], FrozenSet[ops.Qid]]
87
+ ):
88
+ """Checks if a group of Pauli strings are Qubit-Wise Commuting.
89
+
90
+ Args:
91
+ pauli_strings: A list of cirq.PauliString objects.
92
+ all_qubits: A list of all qubits to consider for the QWC check.
93
+ The check is performed for each qubit in this list.
94
+
95
+ Returns:
96
+ True if the group is QWC, False otherwise.
97
+ """
98
+ if len(pauli_strs) <= 1:
99
+ return True
100
+ for p1, p2 in itertools.combinations(pauli_strs, 2):
101
+ if not _are_two_pauli_strings_qubit_wise_commuting(p1, p2, all_qubits):
102
+ return False
103
+ return True
104
+
105
+
106
+ def _validate_single_pauli_string(pauli_str: ops.PauliString):
107
+ if not isinstance(pauli_str, ops.PauliString):
108
+ raise TypeError(
109
+ f"All elements in the Pauli string lists must be cirq.PauliString "
110
+ f"instances, got {type(pauli_str)}."
111
+ )
112
+
113
+ if all(q == ops.I for q in pauli_str) or not pauli_str:
114
+ raise ValueError(
115
+ "Empty Pauli strings or Pauli strings consisting "
116
+ "only of Pauli I are not allowed. Please provide "
117
+ "valid input Pauli strings."
118
+ )
119
+ if pauli_str.coefficient.imag != 0:
120
+ raise ValueError(
121
+ "Cannot compute expectation value of a non-Hermitian PauliString. "
122
+ "Coefficient must be real."
123
+ )
124
+
125
+
62
126
  def _validate_input(
63
- circuits_to_pauli: Dict[circuits.FrozenCircuit, list[ops.PauliString]],
127
+ circuits_to_pauli: Union[
128
+ Dict[circuits.FrozenCircuit, list[ops.PauliString]],
129
+ Dict[circuits.FrozenCircuit, list[list[ops.PauliString]]],
130
+ ],
64
131
  pauli_repetitions: int,
65
132
  readout_repetitions: int,
66
133
  num_random_bitstrings: int,
@@ -73,25 +140,39 @@ def _validate_input(
73
140
  if not isinstance(circuit, circuits.FrozenCircuit):
74
141
  raise TypeError("All keys in 'circuits_to_pauli' must be FrozenCircuit instances.")
75
142
 
76
- for pauli_strings in circuits_to_pauli.values():
77
- for pauli_str in pauli_strings:
78
- if not isinstance(pauli_str, ops.PauliString):
79
- raise TypeError(
80
- f"All elements in the Pauli string lists must be cirq.PauliString "
81
- f"instances, got {type(pauli_str)}."
82
- )
83
-
84
- if all(q == ops.I for q in pauli_str):
85
- raise ValueError(
86
- "Empty Pauli strings or Pauli strings consisting "
87
- "only of Pauli I are not allowed. Please provide "
88
- "valid input Pauli strings."
89
- )
90
- if pauli_str.coefficient.imag != 0:
91
- raise ValueError(
92
- "Cannot compute expectation value of a non-Hermitian PauliString. "
93
- "Coefficient must be real."
94
- )
143
+ first_value: Union[list[ops.PauliString], list[list[ops.PauliString]]] = next(
144
+ iter(circuits_to_pauli.values()) # type: ignore
145
+ )
146
+ for circuit, pauli_strs_list in circuits_to_pauli.items():
147
+ if isinstance(pauli_strs_list, Sequence) and isinstance(first_value[0], Sequence):
148
+ for pauli_strs in pauli_strs_list:
149
+ if not pauli_strs:
150
+ raise ValueError("Empty group of Pauli strings is not allowed")
151
+ if not (
152
+ isinstance(pauli_strs, Sequence) and isinstance(pauli_strs[0], ops.PauliString)
153
+ ):
154
+ raise TypeError(
155
+ f"Inconsistent type in list for circuit {circuit}. "
156
+ f"Expected all elements to be sequences of ops.PauliString, "
157
+ f"but found {type(pauli_strs)}."
158
+ )
159
+ if not _validate_group_paulis_qwc(pauli_strs, circuit.all_qubits()):
160
+ raise ValueError(
161
+ f"Pauli group containing {pauli_strs} is invalid: "
162
+ f"The group of Pauli strings are not "
163
+ f"Qubit-Wise Commuting with each other."
164
+ )
165
+ for pauli_str in pauli_strs:
166
+ _validate_single_pauli_string(pauli_str)
167
+ elif isinstance(pauli_strs_list, Sequence) and isinstance(first_value[0], ops.PauliString):
168
+ for pauli_str in pauli_strs_list: # type: ignore
169
+ _validate_single_pauli_string(pauli_str)
170
+ else:
171
+ raise TypeError(
172
+ f"Expected all elements to be either a sequence of PauliStrings"
173
+ f" or sequences of ops.PauliStrings. "
174
+ f"Got {type(pauli_strs_list)} instead."
175
+ )
95
176
 
96
177
  # Check rng is a numpy random generator
97
178
  if not isinstance(rng_or_seed, np.random.Generator) and not isinstance(rng_or_seed, int):
@@ -110,32 +191,39 @@ def _validate_input(
110
191
  raise ValueError("Must provide non-zero readout_repetitions for readout calibration.")
111
192
 
112
193
 
113
- def _pauli_string_to_basis_change_ops(
114
- pauli_string: ops.PauliString, qid_list: list[ops.Qid]
115
- ) -> List[ops.Operation]:
116
- """Creates operations to change to the eigenbasis of the given Pauli string.
117
-
118
- This function constructs a list of ops.Operation that performs basis changes
119
- necessary to measure the given pauli_string in the computational basis.
120
-
121
- Args:
122
- pauli_string: The Pauli string to diagonalize.
123
- qid_list: An ordered list of the qubits in the circuit.
124
-
125
- Returns:
126
- A list of Operations that, when applied before measurement in the
127
- computational basis, effectively measures in the eigenbasis of
128
- pauli_strings.
129
- """
194
+ def _normalize_input_paulis(
195
+ circuits_to_pauli: Union[
196
+ Dict[circuits.FrozenCircuit, list[ops.PauliString]],
197
+ Dict[circuits.FrozenCircuit, list[list[ops.PauliString]]],
198
+ ],
199
+ ) -> Dict[circuits.FrozenCircuit, list[list[ops.PauliString]]]:
200
+ first_value = next(iter(circuits_to_pauli.values()))
201
+ if (
202
+ first_value
203
+ and isinstance(first_value, list)
204
+ and isinstance(first_value[0], ops.PauliString)
205
+ ):
206
+ input_dict = cast(Dict[circuits.FrozenCircuit, List[ops.PauliString]], circuits_to_pauli)
207
+ normalized_circuits_to_pauli: Dict[circuits.FrozenCircuit, list[list[ops.PauliString]]] = {}
208
+ for circuit, paulis in input_dict.items():
209
+ normalized_circuits_to_pauli[circuit] = [[ps] for ps in paulis]
210
+ return normalized_circuits_to_pauli
211
+ return cast(Dict[circuits.FrozenCircuit, List[List[ops.PauliString]]], circuits_to_pauli)
212
+
213
+
214
+ def _pauli_strings_to_basis_change_ops(
215
+ pauli_strings: list[ops.PauliString], qid_list: list[ops.Qid]
216
+ ):
130
217
  operations = []
131
- for qubit in qid_list: # Iterate over ALL qubits in the circuit
132
- if qubit in pauli_string:
133
- pauli_op = pauli_string[qubit]
218
+ for qubit in qid_list:
219
+ for pauli_str in pauli_strings:
220
+ pauli_op = pauli_str.get(qubit, default=ops.I)
134
221
  if pauli_op == ops.X:
135
222
  operations.append(ops.ry(-np.pi / 2)(qubit)) # =cirq.H
223
+ break
136
224
  elif pauli_op == ops.Y:
137
225
  operations.append(ops.rx(np.pi / 2)(qubit))
138
- # If pauli_op is Z or I, no operation needed
226
+ break
139
227
  return operations
140
228
 
141
229
 
@@ -185,14 +273,14 @@ def _build_many_one_qubits_empty_confusion_matrix(qubits_length: int) -> list[np
185
273
 
186
274
 
187
275
  def _process_pauli_measurement_results(
188
- qubits: List[ops.Qid],
189
- pauli_strings: List[ops.PauliString],
190
- circuit_results: List[ResultDict],
276
+ qubits: list[ops.Qid],
277
+ pauli_string_groups: list[list[ops.PauliString]],
278
+ circuit_results: list[ResultDict],
191
279
  calibration_results: Dict[Tuple[ops.Qid, ...], SingleQubitReadoutCalibrationResult],
192
280
  pauli_repetitions: int,
193
281
  timestamp: float,
194
282
  disable_readout_mitigation: bool = False,
195
- ) -> List[PauliStringMeasurementResult]:
283
+ ) -> list[PauliStringMeasurementResult]:
196
284
  """Calculates both error-mitigated expectation values and unmitigated expectation values
197
285
  from measurement results.
198
286
 
@@ -203,7 +291,7 @@ def _process_pauli_measurement_results(
203
291
 
204
292
  Args:
205
293
  qubits: Qubits to build confusion matrices for. In a sorted order.
206
- pauli_strings: The list of PauliStrings that are measured.
294
+ pauli_strings: The lists of QWC Pauli string groups that are measured.
207
295
  circuit_results: A list of ResultDict obtained
208
296
  from running the Pauli measurement circuits.
209
297
  confusion_matrices: A list of confusion matrices from calibration results.
@@ -218,62 +306,66 @@ def _process_pauli_measurement_results(
218
306
 
219
307
  pauli_measurement_results: List[PauliStringMeasurementResult] = []
220
308
 
221
- for pauli_index, circuit_result in enumerate(circuit_results):
309
+ for pauli_group_index, circuit_result in enumerate(circuit_results):
222
310
  measurement_results = circuit_result.measurements["m"]
311
+ pauli_strs = pauli_string_groups[pauli_group_index]
223
312
 
224
- pauli_string = pauli_strings[pauli_index]
225
- qubits_sorted = sorted(pauli_string.qubits)
226
- qubit_indices = [qubits.index(q) for q in qubits_sorted]
313
+ for pauli_str in pauli_strs:
314
+ qubits_sorted = sorted(pauli_str.qubits)
315
+ qubit_indices = [qubits.index(q) for q in qubits_sorted]
227
316
 
228
- confusion_matrices = (
229
- _build_many_one_qubits_confusion_matrix(calibration_results[tuple(qubits_sorted)])
230
- if disable_readout_mitigation is False
231
- else _build_many_one_qubits_empty_confusion_matrix(len(qubits_sorted))
232
- )
233
- tensored_cm = TensoredConfusionMatrices(
234
- confusion_matrices,
235
- [[q] for q in qubits_sorted],
236
- repetitions=pauli_repetitions,
237
- timestamp=timestamp,
238
- )
317
+ confusion_matrices = (
318
+ _build_many_one_qubits_confusion_matrix(calibration_results[tuple(qubits_sorted)])
319
+ if disable_readout_mitigation is False
320
+ else _build_many_one_qubits_empty_confusion_matrix(len(qubits_sorted))
321
+ )
322
+ tensored_cm = TensoredConfusionMatrices(
323
+ confusion_matrices,
324
+ [[q] for q in qubits_sorted],
325
+ repetitions=pauli_repetitions,
326
+ timestamp=timestamp,
327
+ )
239
328
 
240
- # Create a mask for the relevant qubits in the measurement results
241
- relevant_bits = measurement_results[:, qubit_indices]
329
+ # Create a mask for the relevant qubits in the measurement results
330
+ relevant_bits = measurement_results[:, qubit_indices]
242
331
 
243
- # Calculate the mitigated expectation.
244
- raw_mitigated_values, raw_d_m = tensored_cm.readout_mitigation_pauli_uncorrelated(
245
- qubits_sorted, relevant_bits
246
- )
247
- mitigated_values_with_coefficient = raw_mitigated_values * pauli_string.coefficient.real
248
- d_m_with_coefficient = raw_d_m * abs(pauli_string.coefficient.real)
249
-
250
- # Calculate the unmitigated expectation.
251
- parity = np.sum(relevant_bits, axis=1) % 2
252
- raw_unmitigated_values = 1 - 2 * np.mean(parity)
253
- raw_d_unmit = 2 * np.sqrt(np.mean(parity) * (1 - np.mean(parity)) / pauli_repetitions)
254
- unmitigated_value_with_coefficient = raw_unmitigated_values * pauli_string.coefficient
255
- d_unmit_with_coefficient = raw_d_unmit * abs(pauli_string.coefficient)
256
-
257
- pauli_measurement_results.append(
258
- PauliStringMeasurementResult(
259
- pauli_string=pauli_strings[pauli_index],
260
- mitigated_expectation=mitigated_values_with_coefficient,
261
- mitigated_stddev=d_m_with_coefficient,
262
- unmitigated_expectation=unmitigated_value_with_coefficient,
263
- unmitigated_stddev=d_unmit_with_coefficient,
264
- calibration_result=(
265
- calibration_results[tuple(qubits_sorted)]
266
- if disable_readout_mitigation is False
267
- else None
268
- ),
332
+ # Calculate the mitigated expectation.
333
+ raw_mitigated_values, raw_d_m = tensored_cm.readout_mitigation_pauli_uncorrelated(
334
+ qubits_sorted, relevant_bits
335
+ )
336
+ mitigated_values_with_coefficient = raw_mitigated_values * pauli_str.coefficient.real
337
+ d_m_with_coefficient = raw_d_m * abs(pauli_str.coefficient.real)
338
+
339
+ # Calculate the unmitigated expectation.
340
+ parity = np.sum(relevant_bits, axis=1) % 2
341
+ raw_unmitigated_values = 1 - 2 * np.mean(parity)
342
+ raw_d_unmit = 2 * np.sqrt(np.mean(parity) * (1 - np.mean(parity)) / pauli_repetitions)
343
+ unmitigated_value_with_coefficient = raw_unmitigated_values * pauli_str.coefficient.real
344
+ d_unmit_with_coefficient = raw_d_unmit * abs(pauli_str.coefficient.real)
345
+
346
+ pauli_measurement_results.append(
347
+ PauliStringMeasurementResult(
348
+ pauli_string=pauli_str,
349
+ mitigated_expectation=mitigated_values_with_coefficient,
350
+ mitigated_stddev=d_m_with_coefficient,
351
+ unmitigated_expectation=unmitigated_value_with_coefficient,
352
+ unmitigated_stddev=d_unmit_with_coefficient,
353
+ calibration_result=(
354
+ calibration_results[tuple(qubits_sorted)]
355
+ if disable_readout_mitigation is False
356
+ else None
357
+ ),
358
+ )
269
359
  )
270
- )
271
360
 
272
361
  return pauli_measurement_results
273
362
 
274
363
 
275
364
  def measure_pauli_strings(
276
- circuits_to_pauli: Dict[circuits.FrozenCircuit, list[ops.PauliString]],
365
+ circuits_to_pauli: Union[
366
+ Dict[circuits.FrozenCircuit, List[ops.PauliString]],
367
+ Dict[circuits.FrozenCircuit, List[List[ops.PauliString]]],
368
+ ],
277
369
  sampler: work.Sampler,
278
370
  pauli_repetitions: int,
279
371
  readout_repetitions: int,
@@ -283,8 +375,8 @@ def measure_pauli_strings(
283
375
  """Measures expectation values of Pauli strings on given circuits with/without
284
376
  readout error mitigation.
285
377
 
286
- This function takes a list of circuits and corresponding List[PauliString] to measure.
287
- For each circuit-List[PauliString] pair, it:
378
+ This function takes a dictionary mapping circuits to lists of QWC Pauli string groups.
379
+ For each circuit and its associated list of QWC pauli string group, it:
288
380
  1. Constructs circuits to measure the Pauli string expectation value by
289
381
  adding basis change moments and measurement operations.
290
382
  2. Runs shuffled readout benchmarking on these circuits to calibrate readout errors.
@@ -293,8 +385,13 @@ def measure_pauli_strings(
293
385
  each Pauli string.
294
386
 
295
387
  Args:
296
- circuits_to_pauli: A dictionary mapping circuits to a list of Pauli strings
297
- to measure.
388
+ circuits_to_pauli: A dictionary mapping circuits to either:
389
+ - A list of QWC groups (List[List[ops.PauliString]]). Each QWC group
390
+ is a list of PauliStrings that are mutually Qubit-Wise Commuting.
391
+ Pauli strings within the same group will be calculated using the
392
+ same measurement results.
393
+ - A list of PauliStrings (List[ops.PauliString]). In this case, each
394
+ PauliString is treated as its own measurement group.
298
395
  sampler: The sampler to use.
299
396
  pauli_repetitions: The number of repetitions for each circuit when measuring
300
397
  Pauli strings.
@@ -319,24 +416,27 @@ def measure_pauli_strings(
319
416
  rng_or_seed,
320
417
  )
321
418
 
419
+ normalized_circuits_to_pauli = _normalize_input_paulis(circuits_to_pauli)
420
+
322
421
  # Extract unique qubit tuples from input pauli strings
323
422
  unique_qubit_tuples = set()
324
- for pauli_strings in circuits_to_pauli.values():
325
- for pauli_string in pauli_strings:
326
- unique_qubit_tuples.add(tuple(sorted(pauli_string.qubits)))
423
+ for pauli_string_groups in normalized_circuits_to_pauli.values():
424
+ for pauli_strings in pauli_string_groups:
425
+ for pauli_string in pauli_strings:
426
+ unique_qubit_tuples.add(tuple(sorted(pauli_string.qubits)))
327
427
  # qubits_list is a list of qubit tuples
328
428
  qubits_list = sorted(unique_qubit_tuples)
329
429
 
330
- # Build the basis-change circuits for each Pauli string
430
+ # Build the basis-change circuits for each Pauli string group
331
431
  pauli_measurement_circuits = list[circuits.Circuit]()
332
- for input_circuit, pauli_strings in circuits_to_pauli.items():
432
+ for input_circuit, pauli_string_groups in normalized_circuits_to_pauli.items():
333
433
  qid_list = list(sorted(input_circuit.all_qubits()))
334
434
  basis_change_circuits = []
335
435
  input_circuit_unfrozen = input_circuit.unfreeze()
336
- for pauli_string in pauli_strings:
436
+ for pauli_strings in pauli_string_groups:
337
437
  basis_change_circuit = (
338
438
  input_circuit_unfrozen
339
- + _pauli_string_to_basis_change_ops(pauli_string, qid_list)
439
+ + _pauli_strings_to_basis_change_ops(pauli_strings, qid_list)
340
440
  + ops.measure(*qid_list, key="m")
341
441
  )
342
442
  basis_change_circuits.append(basis_change_circuit)
@@ -356,14 +456,18 @@ def measure_pauli_strings(
356
456
  # Process the results to calculate expectation values
357
457
  results: List[CircuitToPauliStringsMeasurementResult] = []
358
458
  circuit_result_index = 0
359
- for input_circuit, pauli_strings in circuits_to_pauli.items():
459
+ for input_circuit, pauli_string_groups in normalized_circuits_to_pauli.items():
460
+
360
461
  qubits_in_circuit = tuple(sorted(input_circuit.all_qubits()))
361
462
 
362
463
  disable_readout_mitigation = False if num_random_bitstrings != 0 else True
464
+
363
465
  pauli_measurement_results = _process_pauli_measurement_results(
364
466
  list(qubits_in_circuit),
365
- pauli_strings,
366
- circuits_results[circuit_result_index : circuit_result_index + len(pauli_strings)],
467
+ pauli_string_groups,
468
+ circuits_results[
469
+ circuit_result_index : circuit_result_index + len(pauli_string_groups)
470
+ ],
367
471
  calibration_results,
368
472
  pauli_repetitions,
369
473
  time.time(),
@@ -375,5 +479,5 @@ def measure_pauli_strings(
375
479
  )
376
480
  )
377
481
 
378
- circuit_result_index += len(pauli_strings)
482
+ circuit_result_index += len(pauli_string_groups)
379
483
  return results
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ import itertools
15
16
  import random
16
17
  from typing import Dict, Sequence
17
18
 
@@ -32,9 +33,14 @@ def _create_ghz(number_of_qubits: int, qubits: Sequence[cirq.Qid]) -> cirq.Circu
32
33
  return ghz_circuit
33
34
 
34
35
 
35
- def _generate_random_pauli_string(qubits: Sequence[cirq.Qid], enable_coeff: bool = False):
36
+ def _generate_random_pauli_string(
37
+ qubits: Sequence[cirq.Qid], enable_coeff: bool = False, allow_pauli_i: bool = True
38
+ ):
36
39
  pauli_ops = [cirq.I, cirq.X, cirq.Y, cirq.Z]
37
40
 
41
+ if not allow_pauli_i:
42
+ pauli_ops = [cirq.X, cirq.Y, cirq.Z]
43
+
38
44
  operators = {q: random.choice(pauli_ops) for q in qubits}
39
45
  # Ensure at least one non-identity.
40
46
  operators[random.choice(qubits)] = random.choice(pauli_ops[1:])
@@ -45,6 +51,49 @@ def _generate_random_pauli_string(qubits: Sequence[cirq.Qid], enable_coeff: bool
45
51
  return cirq.PauliString(operators)
46
52
 
47
53
 
54
+ def _generate_qwc_paulis(
55
+ input_pauli: cirq.PauliString, num_output: int, exclude_input_pauli: bool = False
56
+ ) -> list[cirq.PauliString]:
57
+ """Generates PauliStrings that are Qubit-Wise Commuting (QWC)
58
+ with the input_pauli.
59
+
60
+ All operations in input_pauli must not be pauli I.
61
+ """
62
+ allowed_paulis_per_qubit = []
63
+ qubits = input_pauli.qubits
64
+
65
+ for qubit in qubits:
66
+ pauli_op = input_pauli.get(qubit, cirq.I)
67
+
68
+ allowed_pauli_op = []
69
+ if pauli_op == cirq.I:
70
+ allowed_pauli_op = [cirq.I, cirq.X, cirq.Y, cirq.Z] # pragma: no cover
71
+ elif pauli_op == cirq.X:
72
+ allowed_pauli_op = [cirq.I, cirq.X]
73
+ elif pauli_op == cirq.Y:
74
+ allowed_pauli_op = [cirq.I, cirq.Y]
75
+ elif pauli_op == cirq.Z:
76
+ allowed_pauli_op = [cirq.I, cirq.Z]
77
+
78
+ allowed_paulis_per_qubit.append(allowed_pauli_op)
79
+
80
+ qwc_paulis: list[cirq.PauliString] = []
81
+
82
+ for pauli_combination in itertools.product(*allowed_paulis_per_qubit):
83
+ pauli_dict = {}
84
+ for i, qid in enumerate(qubits):
85
+ pauli_dict[qid] = pauli_combination[i]
86
+
87
+ qwc_pauli: cirq.PauliString = cirq.PauliString(pauli_dict)
88
+ if exclude_input_pauli and qwc_pauli == input_pauli:
89
+ continue # pragma: no cover
90
+ if all(q == cirq.I for q in qwc_pauli):
91
+ continue
92
+ qwc_paulis.append(qwc_pauli)
93
+
94
+ return qwc_paulis if num_output > len(qwc_paulis) else random.sample(qwc_paulis, num_output)
95
+
96
+
48
97
  def _ideal_expectation_based_on_pauli_string(
49
98
  pauli_string: cirq.PauliString, final_state_vector: np.ndarray
50
99
  ) -> float:
@@ -149,6 +198,60 @@ def test_pauli_string_measurement_errors_with_coefficient_no_noise() -> None:
149
198
  }
150
199
 
151
200
 
201
+ def test_group_pauli_string_measurement_errors_no_noise_with_coefficient() -> None:
202
+ """Test that the mitigated expectation is close to the ideal expectation
203
+ based on the group of Pauli strings"""
204
+
205
+ qubits = cirq.LineQubit.range(5)
206
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
207
+ sampler = cirq.Simulator()
208
+
209
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
210
+ circuits_to_pauli[circuit] = [
211
+ _generate_qwc_paulis(
212
+ _generate_random_pauli_string(qubits, enable_coeff=True, allow_pauli_i=False), 100, True
213
+ )
214
+ for _ in range(3)
215
+ ]
216
+ circuits_to_pauli[circuit].append([cirq.PauliString({q: cirq.X for q in qubits})])
217
+
218
+ circuits_with_pauli_expectations = measure_pauli_strings(
219
+ circuits_to_pauli, sampler, 100, 100, 100, 100
220
+ )
221
+
222
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
223
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
224
+
225
+ expected_val_simulation = sampler.simulate(
226
+ circuit_with_pauli_expectations.circuit.unfreeze()
227
+ )
228
+ final_state_vector = expected_val_simulation.final_state_vector
229
+
230
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
231
+ # Since there is no noise, the mitigated and unmitigated expectations should be the same
232
+ assert np.isclose(
233
+ pauli_string_measurement_results.mitigated_expectation,
234
+ pauli_string_measurement_results.unmitigated_expectation,
235
+ )
236
+ assert np.isclose(
237
+ pauli_string_measurement_results.mitigated_expectation,
238
+ _ideal_expectation_based_on_pauli_string(
239
+ pauli_string_measurement_results.pauli_string, final_state_vector
240
+ ),
241
+ atol=4 * pauli_string_measurement_results.mitigated_stddev,
242
+ )
243
+ assert isinstance(
244
+ pauli_string_measurement_results.calibration_result,
245
+ SingleQubitReadoutCalibrationResult,
246
+ )
247
+ assert pauli_string_measurement_results.calibration_result.zero_state_errors == {
248
+ q: 0 for q in pauli_string_measurement_results.pauli_string.qubits
249
+ }
250
+ assert pauli_string_measurement_results.calibration_result.one_state_errors == {
251
+ q: 0 for q in pauli_string_measurement_results.pauli_string.qubits
252
+ }
253
+
254
+
152
255
  def test_pauli_string_measurement_errors_with_noise() -> None:
153
256
  """Test that the mitigated expectation is close to the ideal expectation
154
257
  based on the Pauli string"""
@@ -196,6 +299,57 @@ def test_pauli_string_measurement_errors_with_noise() -> None:
196
299
  assert 0.0045 < error < 0.0055
197
300
 
198
301
 
302
+ def test_group_pauli_string_measurement_errors_with_noise() -> None:
303
+ """Test that the mitigated expectation is close to the ideal expectation
304
+ based on the group Pauli strings"""
305
+ qubits = cirq.LineQubit.range(7)
306
+ circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
307
+ sampler = NoisySingleQubitReadoutSampler(p0=0.1, p1=0.005, seed=1234)
308
+ simulator = cirq.Simulator()
309
+
310
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
311
+ circuits_to_pauli[circuit] = [
312
+ _generate_qwc_paulis(
313
+ _generate_random_pauli_string(qubits, enable_coeff=True, allow_pauli_i=False), 5
314
+ )
315
+ ]
316
+
317
+ circuits_with_pauli_expectations = measure_pauli_strings(
318
+ circuits_to_pauli, sampler, 800, 1000, 800, np.random.default_rng()
319
+ )
320
+
321
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
322
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
323
+
324
+ expected_val_simulation = simulator.simulate(
325
+ circuit_with_pauli_expectations.circuit.unfreeze()
326
+ )
327
+ final_state_vector = expected_val_simulation.final_state_vector
328
+
329
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
330
+ assert np.isclose(
331
+ pauli_string_measurement_results.mitigated_expectation,
332
+ _ideal_expectation_based_on_pauli_string(
333
+ pauli_string_measurement_results.pauli_string, final_state_vector
334
+ ),
335
+ atol=4 * pauli_string_measurement_results.mitigated_stddev,
336
+ )
337
+
338
+ assert isinstance(
339
+ pauli_string_measurement_results.calibration_result,
340
+ SingleQubitReadoutCalibrationResult,
341
+ )
342
+
343
+ for (
344
+ error
345
+ ) in pauli_string_measurement_results.calibration_result.zero_state_errors.values():
346
+ assert 0.08 < error < 0.12
347
+ for (
348
+ error
349
+ ) in pauli_string_measurement_results.calibration_result.one_state_errors.values():
350
+ assert 0.0045 < error < 0.0055
351
+
352
+
199
353
  def test_many_circuits_input_measurement_with_noise() -> None:
200
354
  """Test that the mitigated expectation is close to the ideal expectation
201
355
  based on the Pauli string for multiple circuits"""
@@ -285,6 +439,36 @@ def test_allow_measurement_without_readout_mitigation() -> None:
285
439
  assert pauli_string_measurement_results.calibration_result is None
286
440
 
287
441
 
442
+ def test_allow_group_pauli_measurement_without_readout_mitigation() -> None:
443
+ """Test that the function allows to measure without error mitigation"""
444
+ qubits = cirq.LineQubit.range(7)
445
+ circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
446
+ sampler = NoisySingleQubitReadoutSampler(p0=0.1, p1=0.005, seed=1234)
447
+
448
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
449
+ circuits_to_pauli[circuit] = [
450
+ _generate_qwc_paulis(_generate_random_pauli_string(qubits, True), 2, True),
451
+ _generate_qwc_paulis(_generate_random_pauli_string(qubits), 4),
452
+ _generate_qwc_paulis(_generate_random_pauli_string(qubits), 6),
453
+ ]
454
+
455
+ circuits_with_pauli_expectations = measure_pauli_strings(
456
+ circuits_to_pauli, sampler, 100, 100, 0, np.random.default_rng()
457
+ )
458
+
459
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
460
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
461
+
462
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
463
+ # Since there's no mitigation, the mitigated and unmitigated expectations
464
+ # should be the same
465
+ assert np.isclose(
466
+ pauli_string_measurement_results.mitigated_expectation,
467
+ pauli_string_measurement_results.unmitigated_expectation,
468
+ )
469
+ assert pauli_string_measurement_results.calibration_result is None
470
+
471
+
288
472
  def test_many_circuits_with_coefficient() -> None:
289
473
  """Test that the mitigated expectation is close to the ideal expectation
290
474
  based on the Pauli string for multiple circuits"""
@@ -344,6 +528,77 @@ def test_many_circuits_with_coefficient() -> None:
344
528
  assert 0.0045 < error < 0.0055
345
529
 
346
530
 
531
+ def test_many_group_pauli_in_circuits_with_coefficient() -> None:
532
+ """Test that the mitigated expectation is close to the ideal expectation
533
+ based on the Pauli string for multiple circuits"""
534
+ qubits_1 = cirq.LineQubit.range(3)
535
+ qubits_2 = [
536
+ cirq.GridQubit(0, 1),
537
+ cirq.GridQubit(1, 1),
538
+ cirq.GridQubit(1, 0),
539
+ cirq.GridQubit(1, 2),
540
+ cirq.GridQubit(2, 1),
541
+ ]
542
+ qubits_3 = cirq.LineQubit.range(8)
543
+
544
+ circuit_1 = cirq.FrozenCircuit(_create_ghz(3, qubits_1))
545
+ circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
546
+ circuit_3 = cirq.FrozenCircuit(_create_ghz(8, qubits_3))
547
+
548
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
549
+ circuits_to_pauli[circuit_1] = [
550
+ _generate_qwc_paulis(
551
+ _generate_random_pauli_string(qubits_1, enable_coeff=True, allow_pauli_i=False), 4
552
+ )
553
+ ]
554
+ circuits_to_pauli[circuit_2] = [
555
+ _generate_qwc_paulis(
556
+ _generate_random_pauli_string(qubits_2, enable_coeff=True, allow_pauli_i=False), 5
557
+ )
558
+ ]
559
+ circuits_to_pauli[circuit_3] = [
560
+ _generate_qwc_paulis(
561
+ _generate_random_pauli_string(qubits_3, enable_coeff=True, allow_pauli_i=False), 6
562
+ )
563
+ ]
564
+
565
+ sampler = NoisySingleQubitReadoutSampler(p0=0.03, p1=0.005, seed=1234)
566
+ simulator = cirq.Simulator()
567
+
568
+ circuits_with_pauli_expectations = measure_pauli_strings(
569
+ circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng()
570
+ )
571
+
572
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
573
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
574
+
575
+ expected_val_simulation = simulator.simulate(
576
+ circuit_with_pauli_expectations.circuit.unfreeze()
577
+ )
578
+ final_state_vector = expected_val_simulation.final_state_vector
579
+
580
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
581
+ assert np.isclose(
582
+ pauli_string_measurement_results.mitigated_expectation,
583
+ _ideal_expectation_based_on_pauli_string(
584
+ pauli_string_measurement_results.pauli_string, final_state_vector
585
+ ),
586
+ atol=4 * pauli_string_measurement_results.mitigated_stddev,
587
+ )
588
+ assert isinstance(
589
+ pauli_string_measurement_results.calibration_result,
590
+ SingleQubitReadoutCalibrationResult,
591
+ )
592
+ for (
593
+ error
594
+ ) in pauli_string_measurement_results.calibration_result.zero_state_errors.values():
595
+ assert 0.025 < error < 0.035
596
+ for (
597
+ error
598
+ ) in pauli_string_measurement_results.calibration_result.one_state_errors.values():
599
+ assert 0.0045 < error < 0.0055
600
+
601
+
347
602
  def test_coefficient_not_real_number() -> None:
348
603
  """Test that the coefficient of input pauli string is not real.
349
604
  Should return error in this case"""
@@ -416,12 +671,13 @@ def test_invalid_input_pauli_string_type() -> None:
416
671
  circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
417
672
 
418
673
  circuits_to_pauli: Dict[cirq.FrozenCircuit, cirq.FrozenCircuit] = {}
419
- circuits_to_pauli[circuit_1] = circuit_2
674
+ circuits_to_pauli[circuit_1] = [_generate_random_pauli_string(qubits_1)] # type: ignore
675
+ circuits_to_pauli[circuit_2] = [circuit_1, circuit_2] # type: ignore
420
676
 
421
677
  with pytest.raises(
422
678
  TypeError,
423
679
  match="All elements in the Pauli string lists must be cirq.PauliString "
424
- "instances, got <class 'cirq.circuits.moment.Moment'>.",
680
+ "instances, got <class 'cirq.circuits.frozen_circuit.FrozenCircuit'>.",
425
681
  ):
426
682
  measure_pauli_strings(
427
683
  circuits_to_pauli, # type: ignore[arg-type]
@@ -521,3 +777,91 @@ def test_rng_type_mismatch() -> None:
521
777
  measure_pauli_strings(
522
778
  circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, "test" # type: ignore[arg-type]
523
779
  )
780
+
781
+
782
+ def test_pauli_type_mismatch() -> None:
783
+ """Test that the input paulis are not a sequence of PauliStrings."""
784
+ qubits = cirq.LineQubit.range(5)
785
+
786
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
787
+
788
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, int] = {}
789
+ circuits_to_pauli[circuit] = 1
790
+ with pytest.raises(
791
+ TypeError,
792
+ match="Expected all elements to be either a sequence of PauliStrings or sequences of"
793
+ " ops.PauliStrings. Got <class 'int'> instead.",
794
+ ):
795
+ measure_pauli_strings(
796
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, "test" # type: ignore[arg-type]
797
+ )
798
+
799
+
800
+ def test_group_paulis_are_not_qwc() -> None:
801
+ """Test that the group paulis are not qwc."""
802
+ qubits = cirq.LineQubit.range(5)
803
+
804
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
805
+
806
+ pauli_str1: cirq.PauliString = cirq.PauliString({qubits[0]: cirq.X, qubits[1]: cirq.Y})
807
+ pauli_str2: cirq.PauliString = cirq.PauliString({qubits[0]: cirq.Y})
808
+
809
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
810
+ circuits_to_pauli[circuit] = [[pauli_str1, pauli_str2]] # type: ignore
811
+ with pytest.raises(
812
+ ValueError,
813
+ match="The group of Pauli strings are not " "Qubit-Wise Commuting with each other.",
814
+ ):
815
+ measure_pauli_strings(
816
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, np.random.default_rng()
817
+ )
818
+
819
+
820
+ def test_empty_group_paulis_not_allowed() -> None:
821
+ """Test that the group paulis are empty"""
822
+ qubits = cirq.LineQubit.range(5)
823
+
824
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
825
+
826
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
827
+ circuits_to_pauli[circuit] = [[]] # type: ignore
828
+ with pytest.raises(ValueError, match="Empty group of Pauli strings is not allowed"):
829
+ measure_pauli_strings(
830
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, np.random.default_rng()
831
+ )
832
+
833
+
834
+ def test_group_paulis_type_mismatch() -> None:
835
+ """Test that the group paulis type is not correct"""
836
+ qubits_1 = cirq.LineQubit.range(3)
837
+ qubits_2 = [
838
+ cirq.GridQubit(0, 1),
839
+ cirq.GridQubit(1, 1),
840
+ cirq.GridQubit(1, 0),
841
+ cirq.GridQubit(1, 2),
842
+ cirq.GridQubit(2, 1),
843
+ ]
844
+ qubits_3 = cirq.LineQubit.range(8)
845
+
846
+ circuit_1 = cirq.FrozenCircuit(_create_ghz(3, qubits_1))
847
+ circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
848
+ circuit_3 = cirq.FrozenCircuit(_create_ghz(8, qubits_3))
849
+
850
+ circuits_to_pauli: Dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
851
+ circuits_to_pauli[circuit_1] = [
852
+ _generate_qwc_paulis(
853
+ _generate_random_pauli_string(qubits_1, enable_coeff=True, allow_pauli_i=False), 6
854
+ )
855
+ for _ in range(3)
856
+ ]
857
+ circuits_to_pauli[circuit_2] = [_generate_random_pauli_string(qubits_2, True) for _ in range(3)]
858
+ circuits_to_pauli[circuit_3] = [_generate_random_pauli_string(qubits_3, True) for _ in range(3)]
859
+
860
+ with pytest.raises(
861
+ TypeError,
862
+ match="Expected all elements to be sequences of ops.PauliString, "
863
+ "but found <class 'cirq.ops.pauli_string.PauliString'>.",
864
+ ):
865
+ measure_pauli_strings(
866
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, np.random.default_rng()
867
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cirq-core
3
- Version: 1.6.0.dev20250501192724
3
+ Version: 1.6.0.dev20250501231232
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=0m3sYIyxRNv9jvAo6rzJ-cnbpny3KGnAByrbU7bApgQ,34720
4
4
  cirq/_doc.py,sha256=yDyWUD_2JDS0gShfGRb-rdqRt9-WeL7DhkqX7np0Nko,2879
5
5
  cirq/_import.py,sha256=cfocxtT1BJ4HkfZ-VO8YyIhPP-xfqHDkLrzz6eeO5U0,8421
6
6
  cirq/_import_test.py,sha256=6K_v0riZJXOXUphHNkGA8MY-JcmGlezFaGmvrNhm3OQ,1015
7
- cirq/_version.py,sha256=TLk7J9TWh5C-KK9rqIeJeWRMcGs6VROp63QG6R8pFOE,1206
8
- cirq/_version_test.py,sha256=QFgtKxa4_ejhCTh5ghsOfhAI-qagt91wqkpb1sAx9eI,147
7
+ cirq/_version.py,sha256=A1Q3pZC0Q7bB_vgobf71D8jfZOCjjZZzsMV86g5J2K4,1206
8
+ cirq/_version_test.py,sha256=yrAKSgPL3X-cwPELPoppKh2xaGkiMQ82dgKn7ZCGqvU,147
9
9
  cirq/conftest.py,sha256=X7yLFL8GLhg2CjPw0hp5e_dGASfvHx1-QT03aUbhKJw,1168
10
10
  cirq/json_resolver_cache.py,sha256=-4KqEEYb6aps-seafnFTHTp3SZc0D8mr4O-pCKIajn8,13653
11
11
  cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
@@ -96,8 +96,8 @@ cirq/contrib/paulistring/optimize.py,sha256=ArUWzXYpHq9SE7K9FdqsJ5WJg1ZvHs8DP6zH
96
96
  cirq/contrib/paulistring/optimize_test.py,sha256=jdZBpXIialcHQGsp8LIuIpU9M5wBQX9HgnqqiMv5l8U,3559
97
97
  cirq/contrib/paulistring/pauli_string_dag.py,sha256=vg0994h84zHIejSdwfqR-mdwmHOWWOAOOcGuStfKPdk,1106
98
98
  cirq/contrib/paulistring/pauli_string_dag_test.py,sha256=4XQ2IoXx-2g5OUU1SMCLbEvDWoGyDg9FMy3_rTTqfBk,1124
99
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py,sha256=6sX2EBxwtgZ0F3ANaJVvfO_GEedLBSzu_K8wQA2Zq7c,15674
100
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py,sha256=r2maZa_9bhuolXWn2OaSe3DucOFchIMoZrX3gWs1_l8,21435
99
+ cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py,sha256=zn9Iakv-dGlZXkcEzonflGvEAdF-6wO6C_nIPSJ3Qvc,20084
100
+ cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py,sha256=R53mh_wnXuYsSJgnqWH5mSHGTivsYhEMnSemyFF6PYg,35465
101
101
  cirq/contrib/paulistring/pauli_string_optimize.py,sha256=KPFjsf_gzgvN7_hIcNslawcI2RGJKf5F0pDmYTHNAb8,2867
102
102
  cirq/contrib/paulistring/pauli_string_optimize_test.py,sha256=2wSpV7EVwuuK8wI_Pp31V4vCIkq-CEmQz3EjaFWi8fM,2895
103
103
  cirq/contrib/paulistring/recombine.py,sha256=zm5AJL80Xl4hgTe9U1YUEgWfcHZys_YcWNpnv02DcL0,4355
@@ -1209,8 +1209,8 @@ cirq/work/sampler.py,sha256=sW0RhIelGABAKbqTM58shwyyCPgf86JIv9IGdJe__js,19186
1209
1209
  cirq/work/sampler_test.py,sha256=mdk1J-WrvbPUYhY41VhWf9_te4DnXr_XMPcugWwc4-I,13281
1210
1210
  cirq/work/zeros_sampler.py,sha256=8_Ne6dBkDANtTZuql7Eb0Qg_E_P3-_gu-ybFzxTbKAQ,2356
1211
1211
  cirq/work/zeros_sampler_test.py,sha256=JIkpBBFPJe5Ba4142vzogyWyboG1Q1ZAm0UVGgOoZn8,3279
1212
- cirq_core-1.6.0.dev20250501192724.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1213
- cirq_core-1.6.0.dev20250501192724.dist-info/METADATA,sha256=toJorOr1WMshis6jIfx3Sm-bnAVTy0i73ph9yR5vVLM,4908
1214
- cirq_core-1.6.0.dev20250501192724.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
1215
- cirq_core-1.6.0.dev20250501192724.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1216
- cirq_core-1.6.0.dev20250501192724.dist-info/RECORD,,
1212
+ cirq_core-1.6.0.dev20250501231232.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1213
+ cirq_core-1.6.0.dev20250501231232.dist-info/METADATA,sha256=tJLjTAFl6fI7cJe2iMXNyEskoVXcxnu9JGqT4nPcISY,4908
1214
+ cirq_core-1.6.0.dev20250501231232.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
1215
+ cirq_core-1.6.0.dev20250501231232.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1216
+ cirq_core-1.6.0.dev20250501231232.dist-info/RECORD,,