cirq-core 1.7.0.dev20250924214519__py3-none-any.whl → 1.7.0.dev20250925163735__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, 11, 0): # pragma: no cover
28
28
  'of Cirq (e.g. "python -m pip install cirq==1.5.0")'
29
29
  )
30
30
 
31
- __version__ = "1.7.0.dev20250924214519"
31
+ __version__ = "1.7.0.dev20250925163735"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version() -> None:
6
- assert cirq.__version__ == "1.7.0.dev20250924214519"
6
+ assert cirq.__version__ == "1.7.0.dev20250925163735"
@@ -22,16 +22,17 @@ from typing import cast, Sequence, TYPE_CHECKING
22
22
 
23
23
  import attrs
24
24
  import numpy as np
25
+ import sympy
25
26
 
26
27
  import cirq.contrib.shuffle_circuits.shuffle_circuits_with_readout_benchmarking as sc_readout
27
28
  from cirq import circuits, ops, study, work
28
29
  from cirq.experiments.readout_confusion_matrix import TensoredConfusionMatrices
30
+ from cirq.study import ResultDict
29
31
 
30
32
  if TYPE_CHECKING:
31
33
  from cirq.experiments.single_qubit_readout_calibration import (
32
34
  SingleQubitReadoutCalibrationResult,
33
35
  )
34
- from cirq.study import ResultDict
35
36
 
36
37
 
37
38
  @attrs.frozen
@@ -188,7 +189,7 @@ def _validate_input(
188
189
 
189
190
  # Check pauli_repetitions is bigger than 0
190
191
  if pauli_repetitions <= 0:
191
- raise ValueError("Must provide non-zero pauli_repetitions.")
192
+ raise ValueError("Must provide positive pauli_repetitions.")
192
193
 
193
194
  # Check num_random_bitstrings is bigger than or equal to 0
194
195
  if num_random_bitstrings < 0:
@@ -196,7 +197,7 @@ def _validate_input(
196
197
 
197
198
  # Check readout_repetitions is bigger than 0
198
199
  if readout_repetitions <= 0:
199
- raise ValueError("Must provide non-zero readout_repetitions for readout calibration.")
200
+ raise ValueError("Must provide positive readout_repetitions for readout calibration.")
200
201
 
201
202
 
202
203
  def _normalize_input_paulis(
@@ -240,6 +241,90 @@ def _pauli_strings_to_basis_change_ops(
240
241
  return operations
241
242
 
242
243
 
244
+ def _pauli_strings_to_basis_change_with_sweep(
245
+ pauli_strings: list[ops.PauliString], qid_list: list[ops.Qid]
246
+ ) -> dict[str, float]:
247
+ """Decide single-qubit rotation sweep parameters for basis change.
248
+
249
+ Args:
250
+ pauli_strings: A list of QWC Pauli strings.
251
+ qid_list: A list of qubits to apply the basis change on.
252
+ Returns:
253
+ A dictionary mapping parameter names to their values for basis change.
254
+ """
255
+ params_dict = {}
256
+
257
+ for qid, qubit in enumerate(qid_list):
258
+ params_dict[f"phi{qid}"] = 1.0
259
+ params_dict[f"theta{qid}"] = 0.0
260
+ for pauli_str in pauli_strings:
261
+ pauli_op = pauli_str.get(qubit, default=ops.I)
262
+ if pauli_op == ops.X:
263
+ params_dict[f"phi{qid}"] = 0.0
264
+ params_dict[f"theta{qid}"] = 1 / 2
265
+ break
266
+ elif pauli_op == ops.Y:
267
+ params_dict[f"phi{qid}"] = 1.0
268
+ params_dict[f"theta{qid}"] = 1 / 2
269
+ break
270
+ return params_dict
271
+
272
+
273
+ def _generate_basis_change_circuits(
274
+ normalized_circuits_to_pauli: dict[circuits.FrozenCircuit, list[list[ops.PauliString]]],
275
+ insert_strategy: circuits.InsertStrategy,
276
+ ) -> list[circuits.Circuit]:
277
+ """Generates basis change circuits for each group of Pauli strings."""
278
+ pauli_measurement_circuits = list[circuits.Circuit]()
279
+
280
+ for input_circuit, pauli_string_groups in normalized_circuits_to_pauli.items():
281
+ qid_list = list(sorted(input_circuit.all_qubits()))
282
+ basis_change_circuits = []
283
+ input_circuit_unfrozen = input_circuit.unfreeze()
284
+ for pauli_strings in pauli_string_groups:
285
+ basis_change_circuit = circuits.Circuit(
286
+ input_circuit_unfrozen,
287
+ _pauli_strings_to_basis_change_ops(pauli_strings, qid_list),
288
+ ops.measure(*qid_list, key="result"),
289
+ strategy=insert_strategy,
290
+ )
291
+ basis_change_circuits.append(basis_change_circuit)
292
+ pauli_measurement_circuits.extend(basis_change_circuits)
293
+
294
+ return pauli_measurement_circuits
295
+
296
+
297
+ def _generate_basis_change_circuits_with_sweep(
298
+ normalized_circuits_to_pauli: dict[circuits.FrozenCircuit, list[list[ops.PauliString]]],
299
+ insert_strategy: circuits.InsertStrategy,
300
+ ) -> tuple[list[circuits.Circuit], list[study.Sweepable]]:
301
+ """Generates basis change circuits for each group of Pauli strings with sweep."""
302
+ parameterized_circuits = list[circuits.Circuit]()
303
+ sweep_params = list[study.Sweepable]()
304
+ for input_circuit, pauli_string_groups in normalized_circuits_to_pauli.items():
305
+ qid_list = list(sorted(input_circuit.all_qubits()))
306
+ phi_symbols = sympy.symbols(f"phi:{len(qid_list)}")
307
+ theta_symbols = sympy.symbols(f"theta:{len(qid_list)}")
308
+
309
+ # Create phased gates and measurement operator
310
+ phased_gates = [
311
+ ops.PhasedXPowGate(phase_exponent=(a - 1) / 2, exponent=b)(qubit)
312
+ for a, b, qubit in zip(phi_symbols, theta_symbols, qid_list)
313
+ ]
314
+ measurement_op = ops.M(*qid_list, key="result")
315
+
316
+ parameterized_circuit = circuits.Circuit(
317
+ input_circuit.unfreeze(), phased_gates, measurement_op, strategy=insert_strategy
318
+ )
319
+ sweep_param = []
320
+ for pauli_strings in pauli_string_groups:
321
+ sweep_param.append(_pauli_strings_to_basis_change_with_sweep(pauli_strings, qid_list))
322
+ sweep_params.append(sweep_param)
323
+ parameterized_circuits.append(parameterized_circuit)
324
+
325
+ return parameterized_circuits, sweep_params
326
+
327
+
243
328
  def _build_one_qubit_confusion_matrix(e0: float, e1: float) -> np.ndarray:
244
329
  """Builds a 2x2 confusion matrix for a single qubit.
245
330
 
@@ -288,7 +373,7 @@ def _build_many_one_qubits_empty_confusion_matrix(qubits_length: int) -> list[np
288
373
  def _process_pauli_measurement_results(
289
374
  qubits: Sequence[ops.Qid],
290
375
  pauli_string_groups: list[list[ops.PauliString]],
291
- circuit_results: list[ResultDict] | Sequence[study.Result],
376
+ circuit_results: Sequence[ResultDict] | Sequence[study.Result],
292
377
  calibration_results: dict[tuple[ops.Qid, ...], SingleQubitReadoutCalibrationResult],
293
378
  pauli_repetitions: int,
294
379
  timestamp: float,
@@ -321,7 +406,7 @@ def _process_pauli_measurement_results(
321
406
  pauli_measurement_results: list[PauliStringMeasurementResult] = []
322
407
 
323
408
  for pauli_group_index, circuit_result in enumerate(circuit_results):
324
- measurement_results = circuit_result.measurements["m"]
409
+ measurement_results = circuit_result.measurements["result"]
325
410
  pauli_strs = pauli_string_groups[pauli_group_index]
326
411
  pauli_readout_qubits = _extract_readout_qubits(pauli_strs)
327
412
 
@@ -403,6 +488,8 @@ def measure_pauli_strings(
403
488
  readout_repetitions: int,
404
489
  num_random_bitstrings: int,
405
490
  rng_or_seed: np.random.Generator | int,
491
+ use_sweep: bool = False,
492
+ insert_strategy: circuits.InsertStrategy = circuits.InsertStrategy.INLINE,
406
493
  ) -> list[CircuitToPauliStringsMeasurementResult]:
407
494
  """Measures expectation values of Pauli strings on given circuits with/without
408
495
  readout error mitigation.
@@ -411,10 +498,11 @@ def measure_pauli_strings(
411
498
  For each circuit and its associated list of QWC pauli string group, it:
412
499
  1. Constructs circuits to measure the Pauli string expectation value by
413
500
  adding basis change moments and measurement operations.
414
- 2. Runs shuffled readout benchmarking on these circuits to calibrate readout errors.
501
+ 2. If `num_random_bitstrings` is greater than zero, performing readout
502
+ benchmarking (shuffled or sweep-based) to calibrate readout errors.
415
503
  3. Mitigates readout errors using the calibrated confusion matrices.
416
504
  4. Calculates and returns both error-mitigated and unmitigated expectation values for
417
- each Pauli string.
505
+ each Pauli string.
418
506
 
419
507
  Args:
420
508
  circuits_to_pauli: A dictionary mapping circuits to either:
@@ -432,6 +520,10 @@ def measure_pauli_strings(
432
520
  num_random_bitstrings: The number of random bitstrings to use in readout
433
521
  benchmarking.
434
522
  rng_or_seed: A random number generator or seed for the readout benchmarking.
523
+ use_sweep: If True, uses parameterized circuits and sweeps parameters
524
+ for both Pauli measurements and readout benchmarking. Defaults to False.
525
+ insert_strategy: The strategy for inserting measurement operations into the circuit.
526
+ Defaults to circuits.InsertStrategy.INLINE.
435
527
 
436
528
  Returns:
437
529
  A list of CircuitToPauliStringsMeasurementResult objects, where each object contains:
@@ -460,49 +552,68 @@ def measure_pauli_strings(
460
552
 
461
553
  # Build the basis-change circuits for each Pauli string group
462
554
  pauli_measurement_circuits: list[circuits.Circuit] = []
463
- for input_circuit, pauli_string_groups in normalized_circuits_to_pauli.items():
464
- qid_list = sorted(input_circuit.all_qubits())
465
- basis_change_circuits = []
466
- input_circuit_unfrozen = input_circuit.unfreeze()
467
- for pauli_strings in pauli_string_groups:
468
- basis_change_circuit = (
469
- input_circuit_unfrozen
470
- + _pauli_strings_to_basis_change_ops(pauli_strings, qid_list)
471
- + ops.measure(*qid_list, key="m")
472
- )
473
- basis_change_circuits.append(basis_change_circuit)
474
- pauli_measurement_circuits.extend(basis_change_circuits)
555
+ sweep_params: list[study.Sweepable] = []
556
+ circuits_results: Sequence[ResultDict] | Sequence[Sequence[study.Result]] = []
557
+ calibration_results: dict[tuple[ops.Qid, ...], SingleQubitReadoutCalibrationResult] = {}
558
+
559
+ benchmarking_params = sc_readout.ReadoutBenchmarkingParams(
560
+ circuit_repetitions=pauli_repetitions,
561
+ num_random_bitstrings=num_random_bitstrings,
562
+ readout_repetitions=readout_repetitions,
563
+ )
564
+
565
+ if use_sweep:
566
+ pauli_measurement_circuits, sweep_params = _generate_basis_change_circuits_with_sweep(
567
+ normalized_circuits_to_pauli, insert_strategy
568
+ )
475
569
 
476
- # Run shuffled benchmarking for readout calibration
477
- circuits_results, calibration_results = (
478
- sc_readout.run_shuffled_circuits_with_readout_benchmarking(
570
+ # Run benchmarking using sweep for readout calibration
571
+ circuits_results, calibration_results = sc_readout.run_sweep_with_readout_benchmarking(
479
572
  sampler=sampler,
480
573
  input_circuits=pauli_measurement_circuits,
481
- parameters=sc_readout.ReadoutBenchmarkingParams(
482
- circuit_repetitions=pauli_repetitions,
483
- num_random_bitstrings=num_random_bitstrings,
484
- readout_repetitions=readout_repetitions,
485
- ),
574
+ sweep_params=sweep_params,
575
+ parameters=benchmarking_params,
486
576
  rng_or_seed=rng_or_seed,
487
577
  qubits=[list(qubits) for qubits in qubits_list],
488
578
  )
489
- )
579
+
580
+ else:
581
+ pauli_measurement_circuits = _generate_basis_change_circuits(
582
+ normalized_circuits_to_pauli, insert_strategy
583
+ )
584
+
585
+ # Run shuffled benchmarking for readout calibration
586
+ circuits_results, calibration_results = (
587
+ sc_readout.run_shuffled_circuits_with_readout_benchmarking(
588
+ sampler=sampler,
589
+ input_circuits=pauli_measurement_circuits,
590
+ parameters=benchmarking_params,
591
+ rng_or_seed=rng_or_seed,
592
+ qubits=[list(qubits) for qubits in qubits_list],
593
+ )
594
+ )
490
595
 
491
596
  # Process the results to calculate expectation values
492
597
  results: list[CircuitToPauliStringsMeasurementResult] = []
493
598
  circuit_result_index = 0
494
- for input_circuit, pauli_string_groups in normalized_circuits_to_pauli.items():
495
-
599
+ for i, (input_circuit, pauli_string_groups) in enumerate(normalized_circuits_to_pauli.items()):
496
600
  qubits_in_circuit = tuple(sorted(input_circuit.all_qubits()))
497
601
 
498
602
  disable_readout_mitigation = False if num_random_bitstrings != 0 else True
499
603
 
604
+ circuits_results_for_group: Sequence[ResultDict] | Sequence[study.Result] = []
605
+ if use_sweep:
606
+ circuits_results_for_group = cast(Sequence[Sequence[study.Result]], circuits_results)[i]
607
+ else:
608
+ circuits_results_for_group = cast(Sequence[ResultDict], circuits_results)[
609
+ circuit_result_index : circuit_result_index + len(pauli_string_groups)
610
+ ]
611
+ circuit_result_index += len(pauli_string_groups)
612
+
500
613
  pauli_measurement_results = _process_pauli_measurement_results(
501
614
  list(qubits_in_circuit),
502
615
  pauli_string_groups,
503
- circuits_results[
504
- circuit_result_index : circuit_result_index + len(pauli_string_groups)
505
- ],
616
+ circuits_results_for_group,
506
617
  calibration_results,
507
618
  pauli_repetitions,
508
619
  time.time(),
@@ -514,5 +625,4 @@ def measure_pauli_strings(
514
625
  )
515
626
  )
516
627
 
517
- circuit_result_index += len(pauli_string_groups)
518
628
  return results
@@ -23,10 +23,7 @@ import pytest
23
23
 
24
24
  import cirq
25
25
  from cirq.contrib.paulistring import measure_pauli_strings
26
- from cirq.contrib.paulistring.pauli_string_measurement_with_readout_mitigation import (
27
- _process_pauli_measurement_results,
28
- )
29
- from cirq.experiments.single_qubit_readout_calibration import SingleQubitReadoutCalibrationResult
26
+ from cirq.experiments import SingleQubitReadoutCalibrationResult
30
27
  from cirq.experiments.single_qubit_readout_calibration_test import NoisySingleQubitReadoutSampler
31
28
 
32
29
 
@@ -107,7 +104,8 @@ def _ideal_expectation_based_on_pauli_string(
107
104
  )
108
105
 
109
106
 
110
- def test_pauli_string_measurement_errors_no_noise() -> None:
107
+ @pytest.mark.parametrize("use_sweep", [True, False])
108
+ def test_pauli_string_measurement_errors_no_noise(use_sweep: bool) -> None:
111
109
  """Test that the mitigated expectation is close to the ideal expectation
112
110
  based on the Pauli string"""
113
111
 
@@ -119,55 +117,7 @@ def test_pauli_string_measurement_errors_no_noise() -> None:
119
117
  circuits_to_pauli[circuit] = [_generate_random_pauli_string(qubits) for _ in range(3)]
120
118
 
121
119
  circuits_with_pauli_expectations = measure_pauli_strings(
122
- circuits_to_pauli, sampler, 1000, 1000, 1000, 1000
123
- )
124
-
125
- for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
126
- assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
127
-
128
- expected_val_simulation = sampler.simulate(
129
- circuit_with_pauli_expectations.circuit.unfreeze()
130
- )
131
- final_state_vector = expected_val_simulation.final_state_vector
132
-
133
- for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
134
- # Since there is no noise, the mitigated and unmitigated expectations should be the same
135
- assert np.isclose(
136
- pauli_string_measurement_results.mitigated_expectation,
137
- pauli_string_measurement_results.unmitigated_expectation,
138
- )
139
- assert np.isclose(
140
- pauli_string_measurement_results.mitigated_expectation,
141
- _ideal_expectation_based_on_pauli_string(
142
- pauli_string_measurement_results.pauli_string, final_state_vector
143
- ),
144
- atol=10 * pauli_string_measurement_results.mitigated_stddev,
145
- )
146
- assert isinstance(
147
- pauli_string_measurement_results.calibration_result,
148
- SingleQubitReadoutCalibrationResult,
149
- )
150
- assert pauli_string_measurement_results.calibration_result.zero_state_errors == {
151
- q: 0 for q in pauli_string_measurement_results.pauli_string.qubits
152
- }
153
- assert pauli_string_measurement_results.calibration_result.one_state_errors == {
154
- q: 0 for q in pauli_string_measurement_results.pauli_string.qubits
155
- }
156
-
157
-
158
- def test_pauli_string_measurement_errors_with_coefficient_no_noise() -> None:
159
- """Test that the mitigated expectation is close to the ideal expectation
160
- based on the Pauli string"""
161
-
162
- qubits = cirq.LineQubit.range(5)
163
- circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
164
- sampler = cirq.Simulator()
165
-
166
- circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
167
- circuits_to_pauli[circuit] = [_generate_random_pauli_string(qubits, True) for _ in range(3)]
168
-
169
- circuits_with_pauli_expectations = measure_pauli_strings(
170
- circuits_to_pauli, sampler, 1000, 1000, 1000, 1000
120
+ circuits_to_pauli, sampler, 1000, 1000, 1000, 1000, use_sweep
171
121
  )
172
122
 
173
123
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -203,7 +153,8 @@ def test_pauli_string_measurement_errors_with_coefficient_no_noise() -> None:
203
153
  }
204
154
 
205
155
 
206
- def test_group_pauli_string_measurement_errors_no_noise_with_coefficient() -> None:
156
+ @pytest.mark.parametrize("use_sweep", [True, False])
157
+ def test_group_pauli_string_measurement_errors_no_noise_with_coefficient(use_sweep: bool) -> None:
207
158
  """Test that the mitigated expectation is close to the ideal expectation
208
159
  based on the group of Pauli strings"""
209
160
 
@@ -214,14 +165,14 @@ def test_group_pauli_string_measurement_errors_no_noise_with_coefficient() -> No
214
165
  circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
215
166
  circuits_to_pauli[circuit] = [
216
167
  _generate_qwc_paulis(
217
- _generate_random_pauli_string(qubits, enable_coeff=True, allow_pauli_i=False), 100, True
168
+ _generate_random_pauli_string(qubits, enable_coeff=True, allow_pauli_i=False), 10, True
218
169
  )
219
170
  for _ in range(3)
220
171
  ]
221
172
  circuits_to_pauli[circuit].append([cirq.PauliString({q: cirq.X for q in qubits})])
222
173
 
223
174
  circuits_with_pauli_expectations = measure_pauli_strings(
224
- circuits_to_pauli, sampler, 1000, 1000, 1000, 1000
175
+ circuits_to_pauli, sampler, 1000, 1000, 1000, 500, use_sweep
225
176
  )
226
177
 
227
178
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -257,19 +208,20 @@ def test_group_pauli_string_measurement_errors_no_noise_with_coefficient() -> No
257
208
  }
258
209
 
259
210
 
260
- def test_pauli_string_measurement_errors_with_noise() -> None:
211
+ @pytest.mark.parametrize("use_sweep", [True, False])
212
+ def test_pauli_string_measurement_errors_with_noise(use_sweep: bool) -> None:
261
213
  """Test that the mitigated expectation is close to the ideal expectation
262
214
  based on the Pauli string"""
263
215
  qubits = cirq.LineQubit.range(7)
264
216
  circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
265
- sampler = NoisySingleQubitReadoutSampler(p0=0.001, p1=0.005, seed=1234)
217
+ sampler = NoisySingleQubitReadoutSampler(p0=0.01, p1=0.005, seed=1234)
266
218
  simulator = cirq.Simulator()
267
219
 
268
220
  circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
269
221
  circuits_to_pauli[circuit] = [_generate_random_pauli_string(qubits) for _ in range(3)]
270
222
 
271
223
  circuits_with_pauli_expectations = measure_pauli_strings(
272
- circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng()
224
+ circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng(), use_sweep
273
225
  )
274
226
 
275
227
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -297,19 +249,20 @@ def test_pauli_string_measurement_errors_with_noise() -> None:
297
249
  for (
298
250
  error
299
251
  ) in pauli_string_measurement_results.calibration_result.zero_state_errors.values():
300
- assert 0.0008 < error < 0.0012
252
+ assert 0.008 < error < 0.012
301
253
  for (
302
254
  error
303
255
  ) in pauli_string_measurement_results.calibration_result.one_state_errors.values():
304
256
  assert 0.0045 < error < 0.0055
305
257
 
306
258
 
307
- def test_group_pauli_string_measurement_errors_with_noise() -> None:
259
+ @pytest.mark.parametrize("use_sweep", [True, False])
260
+ def test_group_pauli_string_measurement_errors_with_noise(use_sweep: bool) -> None:
308
261
  """Test that the mitigated expectation is close to the ideal expectation
309
262
  based on the group Pauli strings"""
310
263
  qubits = cirq.LineQubit.range(7)
311
264
  circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
312
- sampler = NoisySingleQubitReadoutSampler(p0=0.001, p1=0.005, seed=1234)
265
+ sampler = NoisySingleQubitReadoutSampler(p0=0.01, p1=0.005, seed=1234)
313
266
  simulator = cirq.Simulator()
314
267
 
315
268
  circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
@@ -320,7 +273,7 @@ def test_group_pauli_string_measurement_errors_with_noise() -> None:
320
273
  ]
321
274
 
322
275
  circuits_with_pauli_expectations = measure_pauli_strings(
323
- circuits_to_pauli, sampler, 800, 1000, 800, np.random.default_rng()
276
+ circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng(), use_sweep
324
277
  )
325
278
 
326
279
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -348,14 +301,15 @@ def test_group_pauli_string_measurement_errors_with_noise() -> None:
348
301
  for (
349
302
  error
350
303
  ) in pauli_string_measurement_results.calibration_result.zero_state_errors.values():
351
- assert 0.0008 < error < 0.0012
304
+ assert 0.008 < error < 0.012
352
305
  for (
353
306
  error
354
307
  ) in pauli_string_measurement_results.calibration_result.one_state_errors.values():
355
308
  assert 0.0045 < error < 0.0055
356
309
 
357
310
 
358
- def test_many_circuits_input_measurement_with_noise() -> None:
311
+ @pytest.mark.parametrize("use_sweep", [True, False])
312
+ def test_many_circuits_input_measurement_with_noise(use_sweep: bool) -> None:
359
313
  """Test that the mitigated expectation is close to the ideal expectation
360
314
  based on the Pauli string for multiple circuits"""
361
315
  qubits_1 = cirq.LineQubit.range(3)
@@ -381,7 +335,7 @@ def test_many_circuits_input_measurement_with_noise() -> None:
381
335
  simulator = cirq.Simulator()
382
336
 
383
337
  circuits_with_pauli_expectations = measure_pauli_strings(
384
- circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng()
338
+ circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng(), use_sweep
385
339
  )
386
340
 
387
341
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -414,41 +368,12 @@ def test_many_circuits_input_measurement_with_noise() -> None:
414
368
  assert 0.0045 < error < 0.0055
415
369
 
416
370
 
417
- def test_allow_measurement_without_readout_mitigation() -> None:
371
+ @pytest.mark.parametrize("use_sweep", [True, False])
372
+ def test_allow_group_pauli_measurement_without_readout_mitigation(use_sweep: bool) -> None:
418
373
  """Test that the function allows to measure without error mitigation"""
419
374
  qubits = cirq.LineQubit.range(7)
420
375
  circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
421
- sampler = NoisySingleQubitReadoutSampler(p0=0.001, p1=0.005, seed=1234)
422
-
423
- circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
424
- circuits_to_pauli[circuit] = [
425
- _generate_random_pauli_string(qubits, True),
426
- _generate_random_pauli_string(qubits),
427
- _generate_random_pauli_string(qubits),
428
- ]
429
-
430
- circuits_with_pauli_expectations = measure_pauli_strings(
431
- circuits_to_pauli, sampler, 1000, 1000, 0, np.random.default_rng()
432
- )
433
-
434
- for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
435
- assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
436
-
437
- for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
438
- # Since there's no mitigation, the mitigated and unmitigated expectations
439
- # should be the same
440
- assert np.isclose(
441
- pauli_string_measurement_results.mitigated_expectation,
442
- pauli_string_measurement_results.unmitigated_expectation,
443
- )
444
- assert pauli_string_measurement_results.calibration_result is None
445
-
446
-
447
- def test_allow_group_pauli_measurement_without_readout_mitigation() -> None:
448
- """Test that the function allows to measure without error mitigation"""
449
- qubits = cirq.LineQubit.range(7)
450
- circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
451
- sampler = NoisySingleQubitReadoutSampler(p0=0.001, p1=0.005, seed=1234)
376
+ sampler = NoisySingleQubitReadoutSampler(p0=0.01, p1=0.005, seed=1234)
452
377
 
453
378
  circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
454
379
  circuits_to_pauli[circuit] = [
@@ -458,7 +383,7 @@ def test_allow_group_pauli_measurement_without_readout_mitigation() -> None:
458
383
  ]
459
384
 
460
385
  circuits_with_pauli_expectations = measure_pauli_strings(
461
- circuits_to_pauli, sampler, 100, 100, 0, np.random.default_rng()
386
+ circuits_to_pauli, sampler, 1000, 1000, 0, np.random.default_rng(), use_sweep
462
387
  )
463
388
 
464
389
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -474,7 +399,13 @@ def test_allow_group_pauli_measurement_without_readout_mitigation() -> None:
474
399
  assert pauli_string_measurement_results.calibration_result is None
475
400
 
476
401
 
477
- def test_many_circuits_with_coefficient() -> None:
402
+ @pytest.mark.parametrize("use_sweep", [True, False])
403
+ @pytest.mark.parametrize(
404
+ "insert_strategy", [cirq.InsertStrategy.INLINE, cirq.InsertStrategy.EARLIEST]
405
+ )
406
+ def test_many_circuits_with_coefficient(
407
+ use_sweep: bool, insert_strategy: cirq.InsertStrategy
408
+ ) -> None:
478
409
  """Test that the mitigated expectation is close to the ideal expectation
479
410
  based on the Pauli string for multiple circuits"""
480
411
  qubits_1 = cirq.LineQubit.range(3)
@@ -500,7 +431,14 @@ def test_many_circuits_with_coefficient() -> None:
500
431
  simulator = cirq.Simulator()
501
432
 
502
433
  circuits_with_pauli_expectations = measure_pauli_strings(
503
- circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng()
434
+ circuits_to_pauli,
435
+ sampler,
436
+ 1000,
437
+ 1000,
438
+ 1000,
439
+ np.random.default_rng(),
440
+ use_sweep,
441
+ insert_strategy,
504
442
  )
505
443
 
506
444
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -533,7 +471,8 @@ def test_many_circuits_with_coefficient() -> None:
533
471
  assert 0.0045 < error < 0.0055
534
472
 
535
473
 
536
- def test_many_group_pauli_in_circuits_with_coefficient() -> None:
474
+ @pytest.mark.parametrize("use_sweep", [True, False])
475
+ def test_many_group_pauli_in_circuits_with_coefficient(use_sweep: bool) -> None:
537
476
  """Test that the mitigated expectation is close to the ideal expectation
538
477
  based on the Pauli string for multiple circuits"""
539
478
  qubits_1 = cirq.LineQubit.range(3)
@@ -571,7 +510,7 @@ def test_many_group_pauli_in_circuits_with_coefficient() -> None:
571
510
  simulator = cirq.Simulator()
572
511
 
573
512
  circuits_with_pauli_expectations = measure_pauli_strings(
574
- circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng()
513
+ circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng(), use_sweep
575
514
  )
576
515
 
577
516
  for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
@@ -734,7 +673,7 @@ def test_zero_pauli_repetitions() -> None:
734
673
 
735
674
  circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
736
675
  circuits_to_pauli[circuit] = [cirq.PauliString({q: cirq.X for q in qubits})]
737
- with pytest.raises(ValueError, match="Must provide non-zero pauli_repetitions."):
676
+ with pytest.raises(ValueError, match="Must provide positive pauli_repetitions."):
738
677
  measure_pauli_strings(
739
678
  circuits_to_pauli, cirq.Simulator(), 0, 1000, 1000, np.random.default_rng()
740
679
  )
@@ -763,7 +702,7 @@ def test_zero_readout_repetitions() -> None:
763
702
  circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
764
703
  circuits_to_pauli[circuit] = [cirq.PauliString({q: cirq.X for q in qubits})]
765
704
  with pytest.raises(
766
- ValueError, match="Must provide non-zero readout_repetitions for readout" + " calibration."
705
+ ValueError, match="Must provide positive readout_repetitions for readout" + " calibration."
767
706
  ):
768
707
  measure_pauli_strings(
769
708
  circuits_to_pauli, cirq.Simulator(), 1000, 0, 1000, np.random.default_rng()
@@ -798,7 +737,7 @@ def test_pauli_type_mismatch() -> None:
798
737
  " ops.PauliStrings. Got <class 'int'> instead.",
799
738
  ):
800
739
  measure_pauli_strings(
801
- circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, "test" # type: ignore[arg-type]
740
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, 1 # type: ignore[arg-type]
802
741
  )
803
742
 
804
743
 
@@ -869,34 +808,3 @@ def test_group_paulis_type_mismatch() -> None:
869
808
  measure_pauli_strings(
870
809
  circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, np.random.default_rng()
871
810
  )
872
-
873
-
874
- def test_process_pauli_measurement_results_raises_error_on_missing_calibration() -> None:
875
- """Test that the function raises an error if the calibration result is missing."""
876
- qubits: Sequence[cirq.Qid] = cirq.LineQubit.range(5)
877
-
878
- measurement_op = cirq.measure(*qubits, key='m')
879
- test_circuits: list[cirq.Circuit] = [_create_ghz(5, qubits) + measurement_op for _ in range(3)]
880
-
881
- pauli_strings = [_generate_random_pauli_string(qubits, True) for _ in range(3)]
882
- sampler = cirq.Simulator()
883
-
884
- circuit_results = sampler.run_batch(test_circuits, repetitions=1000)
885
-
886
- pauli_strings_qubits = sorted(
887
- set(itertools.chain.from_iterable(ps.qubits for ps in pauli_strings))
888
- )
889
- empty_calibration_result_dict = {tuple(pauli_strings_qubits): None}
890
-
891
- with pytest.raises(
892
- ValueError,
893
- match="Readout mitigation is enabled, but no calibration result was found for qubits",
894
- ):
895
- _process_pauli_measurement_results(
896
- qubits,
897
- [pauli_strings],
898
- circuit_results[0],
899
- empty_calibration_result_dict, # type: ignore[arg-type]
900
- 1000,
901
- 1.0,
902
- )
@@ -105,7 +105,7 @@ def _generate_readout_calibration_circuits(
105
105
  readout_calibration_circuits.append(
106
106
  circuits.Circuit(
107
107
  [bit_to_gate[bit](qubit) for bit, qubit in zip(bitstr, qubits)]
108
- + [ops.M(qubits, key="m")]
108
+ + [ops.M(qubits, key="result")]
109
109
  )
110
110
  )
111
111
  return readout_calibration_circuits, random_bitstrings
@@ -137,11 +137,12 @@ def _generate_parameterized_readout_calibration_circuit_with_sweep(
137
137
 
138
138
  exp_symbols = [sympy.Symbol(f'exp_{qubit}') for qubit in qubits]
139
139
  parameterized_readout_calibration_circuit = circuits.Circuit(
140
- [ops.X(qubit) ** exp for exp, qubit in zip(exp_symbols, qubits)], ops.M(*qubits, key="m")
140
+ [ops.X(qubit) ** exp for exp, qubit in zip(exp_symbols, qubits)],
141
+ ops.M(*qubits, key="result"),
141
142
  )
142
143
  sweep_params = []
143
144
  for bitstr in random_bitstrings:
144
- sweep_params.append({exp: bit for exp, bit in zip(exp_symbols, bitstr)})
145
+ sweep_params.append({str(exp): bit for exp, bit in zip(exp_symbols, bitstr)})
145
146
 
146
147
  return parameterized_readout_calibration_circuit, sweep_params, random_bitstrings
147
148
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cirq-core
3
- Version: 1.7.0.dev20250924214519
3
+ Version: 1.7.0.dev20250925163735
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=emXpdD5ZvwLRlFAoQB8YatmZyU3b4e9jg6FppMTUhkU,33900
4
4
  cirq/_doc.py,sha256=BrnoABo1hk5RgB3Cgww4zLHUfiyFny0F1V-tOMCbdaU,2909
5
5
  cirq/_import.py,sha256=ixBu4EyGl46Ram2cP3p5eZVEFDW5L2DS-VyTjz4N9iw,8429
6
6
  cirq/_import_test.py,sha256=oF4izzOVZLc7NZ0aZHFcGv-r01eiFFt_JORx_x7_D4s,1089
7
- cirq/_version.py,sha256=ERZTzRp-ADeOL-jMvFKbib0T4dxXDqI8dcJxQl4D8Lg,1206
8
- cirq/_version_test.py,sha256=8fOhycOENquGXNRwepvoQpbdfrhAroYjOSOQ8jDlEmY,155
7
+ cirq/_version.py,sha256=TvZSYtLeQ-fI3R4DZRX9aDk4sLshNuix_A-HMdXndgU,1206
8
+ cirq/_version_test.py,sha256=UBj3sF7PIbexh4kSxVnq9loc0cmIi8G8jtiNO6xOyYg,155
9
9
  cirq/conftest.py,sha256=wSDKNdIQRDfLnXvOCWD3erheOw8JHRhdfQ53EyTUIXg,1239
10
10
  cirq/json_resolver_cache.py,sha256=A5DIgFAY1hUNt9vai_C3-gGBv24116CJMzQxMcXOax4,13726
11
11
  cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
@@ -108,8 +108,8 @@ cirq/contrib/paulistring/optimize.py,sha256=F02c_9nuc8a41XNsA9bzTGaW2kR3hZw-MdaQ
108
108
  cirq/contrib/paulistring/optimize_test.py,sha256=FsmwyYFIGyyiO115oYgmCfaSV3De55Azd0_rzsi_xnU,3618
109
109
  cirq/contrib/paulistring/pauli_string_dag.py,sha256=28bUVNsIS9WYKdyYCNIVrkRwqQOKlkpmCacWow6N6D0,1142
110
110
  cirq/contrib/paulistring/pauli_string_dag_test.py,sha256=nH_1h5LQobV9rb5gitLmrvpIwWwrcRmNdUGDAhFMZtI,1168
111
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py,sha256=xrG4KNJaJjjhCG_0KvnOFdAOTbNRGJhYwyhCSBjWkWw,21288
112
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py,sha256=dMIjWKXxexxIJMn3OXa7dAT4e7PG0BAqTA9f9WspPkk,36839
111
+ cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py,sha256=3_BkJj2eG4rFINi8yrwYm1P3kjDfoRtNd_5GE1H7voI,26112
112
+ cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py,sha256=jGgfEIsDa4DMMcPsbZbEmd_Q16G3C35mvZwfN8lugks,32733
113
113
  cirq/contrib/paulistring/pauli_string_optimize.py,sha256=ejHf7Bo0iUvnNBeZ5IN0bT0SIXF79DSGr1NxoAyVfiQ,2960
114
114
  cirq/contrib/paulistring/pauli_string_optimize_test.py,sha256=_14FS9TAvzRsmnTZxJUsMXPNcenv5mb0eD2gGTxvohE,2955
115
115
  cirq/contrib/paulistring/recombine.py,sha256=phJ-SY4zdqZpIZca0iSsY0lK6NdXd0M0sOOWnUdGn5U,4353
@@ -162,7 +162,7 @@ cirq/contrib/routing/swap_network_test.py,sha256=dQw1LgVCU4bcjEaYBwRNMM2i4TfxkWp
162
162
  cirq/contrib/routing/utils.py,sha256=xvA1khTMBly750GVJm_pCc5uBpAHpayLGZ-Yq4m2qg8,3780
163
163
  cirq/contrib/routing/utils_test.py,sha256=0TuaQdLTui_fFPRXGJfRBj5k5ysCyIQwW7OMfeABmR0,2107
164
164
  cirq/contrib/shuffle_circuits/__init__.py,sha256=yKqR59wvZYmIrolsEEqoO9Dhgd5hALMkAoR9AtjnbUY,1030
165
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py,sha256=xzMS1EysSMRrrlWE37MyYV-NR9b48kINH204ejYPzkA,22730
165
+ cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py,sha256=zHMHmth-S94ZQUnOn_SS7z70qNLpGt9b1YHby8fwXcI,22754
166
166
  cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py,sha256=JM1GZ3aCYQuc8IHrA9CG3PEZeMnV73roBlm9bEoDArw,23924
167
167
  cirq/contrib/svg/__init__.py,sha256=m7d-CNT2j74uNQdmM2xJ1a7HG6v0FZMt8eAwW4rPJpI,148
168
168
  cirq/contrib/svg/svg.py,sha256=WxwlIcCv5SofhiZ16Bej6qHkdZgU4lT1Gw5GMZnFAkE,9398
@@ -1236,8 +1236,8 @@ cirq/work/sampler.py,sha256=rxbMWvrhu3gfNSBjZKozw28lLKVvBAS_1EGyPdYe8Xg,19041
1236
1236
  cirq/work/sampler_test.py,sha256=SsMrRvLDYELyOAWLKISjkdEfrBwLYWRsT6D8WrsLM3Q,13533
1237
1237
  cirq/work/zeros_sampler.py,sha256=Fs2JWwq0n9zv7_G5Rm-9vPeHUag7uctcMOHg0JTkZpc,2371
1238
1238
  cirq/work/zeros_sampler_test.py,sha256=lQLgQDGBLtfImryys2HzQ2jOSGxHgc7-koVBUhv8qYk,3345
1239
- cirq_core-1.7.0.dev20250924214519.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1240
- cirq_core-1.7.0.dev20250924214519.dist-info/METADATA,sha256=TBeYkFCOjt7NjKONo5kxXysIAM9R7lN2YY7TS1emwUs,4758
1241
- cirq_core-1.7.0.dev20250924214519.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1242
- cirq_core-1.7.0.dev20250924214519.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1243
- cirq_core-1.7.0.dev20250924214519.dist-info/RECORD,,
1239
+ cirq_core-1.7.0.dev20250925163735.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1240
+ cirq_core-1.7.0.dev20250925163735.dist-info/METADATA,sha256=3quT-l2WM6jmOzXA4A-8VCBZElJcNkb30K02o0_Y8YY,4758
1241
+ cirq_core-1.7.0.dev20250925163735.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1242
+ cirq_core-1.7.0.dev20250925163735.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1243
+ cirq_core-1.7.0.dev20250925163735.dist-info/RECORD,,