cirq-core 1.5.0.dev20240626180854__py3-none-any.whl → 1.5.0.dev20240701205135__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.dev20240626180854"
31
+ __version__ = "1.5.0.dev20240701205135"
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.dev20240626180854"
6
+ assert cirq.__version__ == "1.5.0.dev20240701205135"
@@ -26,12 +26,26 @@ if TYPE_CHECKING:
26
26
  import cirq
27
27
 
28
28
 
29
+ def _mitigate_single_bitstring(z_rinv_all: list[np.ndarray], bitstring: np.ndarray) -> float:
30
+ """Return the mitigated Pauli expectation value for a single observed bitstring.
31
+
32
+ Args:
33
+ z_rinv_all: A list of single-qubit pauli-Z (as a vector) contracted with the single-qubit
34
+ inverse response matrix, for each qubit.
35
+ bitstring: The measured bitstring.
36
+
37
+ Returns:
38
+ The corrected expectation value of ZZZZZ... given the single measured bitstring.
39
+ """
40
+ return np.prod([z_rinv[bit] for z_rinv, bit in zip(z_rinv_all, bitstring)])
41
+
42
+
29
43
  class TensoredConfusionMatrices:
30
44
  """Store and use confusion matrices for readout error mitigation on sets of qubits.
31
45
 
32
46
  The confusion matrix (CM) for one qubit is:
33
47
 
34
- [ Pr(0|0) Pr(1|0) ]
48
+ [ Pr(0|0) Pr(0|1) ]
35
49
  [ Pr(1|0) Pr(1|1) ]
36
50
 
37
51
  where Pr(i | j) = Probability of observing state "i" given state "j" was prepared.
@@ -71,7 +85,7 @@ class TensoredConfusionMatrices:
71
85
  confusion_matrices: Sequence of confusion matrices, computed for qubit patterns present
72
86
  in `measure_qubits`. A single confusion matrix is also accepted.
73
87
  measure_qubits: Sequence of smaller qubit patterns, for which the confusion matrices
74
- were computed. A single qubit pattern is also accepted. Note that the
88
+ were computed. A single qubit pattern is also accepted. Note that
75
89
  each qubit pattern is a sequence of qubits used to label the axes of
76
90
  the corresponding confusion matrix.
77
91
  repetitions: The number of repetitions that were used to estimate the confusion
@@ -298,6 +312,72 @@ class TensoredConfusionMatrices:
298
312
  ) # pragma: no cover
299
313
  return res.x
300
314
 
315
+ def readout_mitigation_pauli_uncorrelated(
316
+ self, qubits: Sequence['cirq.Qid'], measured_bitstrings: np.ndarray
317
+ ) -> tuple[float, float]:
318
+ r"""Uncorrelated readout error mitigation for a multi-qubit Pauli operator.
319
+
320
+ This function scalably performs readout error mitigation on an arbitrary-length Pauli
321
+ operator. It is a reimplementation of https://github.com/eliottrosenberg/correlated_SPAM
322
+ but specialized to the case in which readout is uncorrelated. We require that the confusion
323
+ matrix is a tensor product of single-qubit confusion matrices. We then invert the confusion
324
+ matrix by inverting each of the $C^{(q)}$ Then, in a bit-by-bit fashion, we apply the
325
+ inverses of the single-site confusion matrices to the bits of the measured bitstring,
326
+ contract them with the single-site Pauli operator, and take the product over all of the
327
+ bits. This could be generalized to tensor product spaces that are larger than single qubits,
328
+ but the essential simplification is that each tensor product space is small, so that none of
329
+ the response matrices is exponentially large.
330
+
331
+ This can result in mitigated Pauli operators that are not in the range [-1, 1], but if
332
+ the readout error is indeed uncorrelated and well-characterized, then it should converge
333
+ to being within this range. Results are improved both by a more precise characterization
334
+ of the response matrices (whose statistical uncertainty is not accounted for in the error
335
+ propagation here) and by increasing the number of measured bitstrings.
336
+
337
+ Args:
338
+ qubits: The qubits on which the Pauli operator acts.
339
+ measured_bitstrings: The experimentally measured bitstrings in the eigenbasis of the
340
+ Pauli operator. measured_bitstrings[i,j] is the ith bitstring, qubit j.
341
+
342
+ Returns:
343
+ The error-mitigated expectation value of the Pauli operator and its statistical
344
+ uncertainty (not including the uncertainty in the confusion matrices for now).
345
+
346
+ Raises:
347
+ NotImplementedError: If the confusion matrix is not a tensor product of single-qubit
348
+ confusion matrices for all of `qubits`.
349
+ """
350
+
351
+ # first, get all of the confusion matrices
352
+ cm_all = []
353
+ for qubit in qubits:
354
+ try:
355
+ idx = self.measure_qubits.index((qubit,))
356
+ except: # pragma: no cover
357
+ raise NotImplementedError( # pragma: no cover
358
+ "The response matrix must be a tensor product of single-qu" # pragma: no cover
359
+ + f"bit response matrices, including that of qubit {qubit}." # pragma: no cover
360
+ ) # pragma: no cover
361
+ cm_all.append(self.confusion_matrices[idx])
362
+
363
+ # get the correction matrices, assuming uncorrelated readout:
364
+ cminv_all = [np.linalg.inv(cm) for cm in cm_all]
365
+
366
+ # next, contract them with the single-qubit Pauli operators:
367
+ z = np.array([1, -1])
368
+ z_cminv_all = [z @ cminv for cminv in cminv_all]
369
+
370
+ # finally, mitigate each bitstring:
371
+ z_mit_all_shots = np.array(
372
+ [
373
+ _mitigate_single_bitstring(z_cminv_all, bitstring)
374
+ for bitstring in measured_bitstrings
375
+ ]
376
+ )
377
+
378
+ # return mean and statistical uncertainty:
379
+ return np.mean(z_mit_all_shots), np.std(z_mit_all_shots) / np.sqrt(len(measured_bitstrings))
380
+
301
381
  def __repr__(self) -> str:
302
382
  return (
303
383
  f"cirq.TensoredConfusionMatrices("
@@ -17,6 +17,34 @@ import cirq
17
17
  import pytest
18
18
 
19
19
  from cirq.experiments.single_qubit_readout_calibration_test import NoisySingleQubitReadoutSampler
20
+ from cirq.experiments.readout_confusion_matrix import TensoredConfusionMatrices
21
+
22
+
23
+ def add_readout_error(
24
+ measurements: np.ndarray,
25
+ zero_errors: np.ndarray,
26
+ one_errors: np.ndarray,
27
+ rng: np.random.Generator,
28
+ ) -> np.ndarray:
29
+ """Add readout errors to measured (or simulated) bitstrings.
30
+
31
+ Args:
32
+ measurements: The bitstrings to which we will add readout errors. measurements[i,j] is the
33
+ ith bitstring, qubit j.
34
+ zero_errors: zero_errors[i] is the probability of a 0->1 readout error on qubit i.
35
+ one_errors: one_errors[i] is the probability of a 1->0 readout error on qubit i.
36
+ rng: The pseudorandom number generator to use.
37
+
38
+ Returns:
39
+ New measurements but with readout errors added.
40
+ """
41
+ num_bitstrs, n = measurements.shape
42
+ assert len(zero_errors) == len(one_errors) == n
43
+ # compute the probability that each bit is 1 after adding readout errors:
44
+ p1 = measurements * (1 - one_errors) + (1 - measurements) * zero_errors
45
+ r = rng.random((num_bitstrs, n))
46
+ noisy_measurements = r < p1
47
+ return noisy_measurements.astype(int)
20
48
 
21
49
 
22
50
  def get_expected_cm(num_qubits: int, p0: float, p1: float):
@@ -159,3 +187,78 @@ def test_readout_confusion_matrix_repr_and_equality():
159
187
  eq.add_equality_group(a, a)
160
188
  eq.add_equality_group(b, b)
161
189
  eq.add_equality_group(c, c)
190
+
191
+
192
+ def _sample_ghz(n: int, repetitions: int, rng: np.random.Generator) -> np.ndarray:
193
+ """Sample a GHZ state in the z basis.
194
+ Args:
195
+ n: The number of qubits.
196
+ repetitions: The number of repetitions.
197
+ rng: The pseudorandom number generator to use.
198
+ Returns:
199
+ An array of the measurement outcomes.
200
+ """
201
+ return np.tile(rng.integers(0, 2, size=repetitions), (n, 1)).T
202
+
203
+
204
+ def _add_noise_and_mitigate_ghz(
205
+ n: int,
206
+ repetitions: int,
207
+ zero_errors: np.ndarray,
208
+ one_errors: np.ndarray,
209
+ rng: np.random.Generator | None = None,
210
+ ) -> tuple[float, float, float, float]:
211
+ """Add readout error to GHZ-like bitstrings and measure <ZZZ...> with and
212
+ without readout error mitigation.
213
+ Args:
214
+ n: The number of qubits.
215
+ repetitions: The number of repetitions.
216
+ zero_errors: zero_errors[i] is the probability of a 0->1 readout error on qubit i.
217
+ one_errors: one_errors[i] is the probability of a 1->0 readout error on qubit i.
218
+ rng: The pseudorandom number generator to use.
219
+ Returns:
220
+ A tuple of:
221
+ - The mitigated expectation value of <ZZZ...>
222
+ - The statistical uncertainty of the previous output
223
+ - The unmitigated expectation value of <ZZZ...>
224
+ - The statstical uncertainty of the previous output
225
+ """
226
+ if rng is None:
227
+ rng = np.random.default_rng(0)
228
+ confusion_matrices = [
229
+ np.array([[1 - e0, e1], [e0, 1 - e1]]) for e0, e1 in zip(zero_errors, one_errors)
230
+ ]
231
+ qubits = cirq.LineQubit.range(n)
232
+ tcm = TensoredConfusionMatrices(
233
+ confusion_matrices, [[q] for q in qubits], repetitions=0, timestamp=0.0
234
+ )
235
+
236
+ measurements = _sample_ghz(n, repetitions, rng)
237
+ noisy_measurements = add_readout_error(measurements, zero_errors, one_errors, rng)
238
+ # unmitigated:
239
+ p1 = np.mean(np.sum(noisy_measurements, axis=1) % 2)
240
+ z = 1 - 2 * np.mean(p1)
241
+ dz = 2 * np.sqrt(p1 * (1 - p1) / repetitions)
242
+ # return mitigated and unmitigated:
243
+ return (*tcm.readout_mitigation_pauli_uncorrelated(qubits, noisy_measurements), z, dz)
244
+
245
+
246
+ def test_uncorrelated_readout_mitigation_pauli():
247
+ n_all = np.arange(2, 35)
248
+ z_all_mit = []
249
+ dz_all_mit = []
250
+ z_all_raw = []
251
+ dz_all_raw = []
252
+ repetitions = 10_000
253
+ for n in n_all:
254
+ e0 = np.ones(n) * 0.005
255
+ e1 = np.ones(n) * 0.03
256
+ z_mit, dz_mit, z_raw, dz_raw = _add_noise_and_mitigate_ghz(n, repetitions, e0, e1)
257
+ z_all_mit.append(z_mit)
258
+ dz_all_mit.append(dz_mit)
259
+ z_all_raw.append(z_raw)
260
+ dz_all_raw.append(dz_raw)
261
+
262
+ for n, z, dz in zip(n_all, z_all_mit, dz_all_mit):
263
+ ideal = 1.0 if n % 2 == 0 else 0.0
264
+ assert np.isclose(z, ideal, atol=4 * dz)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cirq-core
3
- Version: 1.5.0.dev20240626180854
3
+ Version: 1.5.0.dev20240701205135
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=ZaiEAjc2JNjfmnTytMQdBinNlS144AIAqwDYEm2146Y,1206
8
- cirq/_version_test.py,sha256=6EWyGOSMXYPHbwBREsU9OtGJnS8qu5wRY1ptdIaYgMc,147
7
+ cirq/_version.py,sha256=_zIQ22vgNE_xJZVUgRlo8jd8osD7HKMrfP55L4B-u4g,1206
8
+ cirq/_version_test.py,sha256=blpx6eLf7bpTF3Ruw7yOsVnbfplWIhhwfMZXaTfvdcA,147
9
9
  cirq/conftest.py,sha256=X7yLFL8GLhg2CjPw0hp5e_dGASfvHx1-QT03aUbhKJw,1168
10
10
  cirq/json_resolver_cache.py,sha256=ytePZtNZgKjOF2NiVpUTuotB-JKZmQNOFIFdvXqsxHw,13271
11
11
  cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
@@ -188,8 +188,8 @@ cirq/experiments/qubit_characterizations.py,sha256=Zi925SVZ0U5HbkyuGD6BspjzPAhsq
188
188
  cirq/experiments/qubit_characterizations_test.py,sha256=b_ONqxyW6s01Ts8T65BEdb4e8Xy24Qp4zTGXWesL0ic,9733
189
189
  cirq/experiments/random_quantum_circuit_generation.py,sha256=R_w7z35plUHEYBY0-F80bPcWJSSSjNQDaP2GbxVBEZg,28143
190
190
  cirq/experiments/random_quantum_circuit_generation_test.py,sha256=1rvgN8-Ajedn_70FyYKVzjvzR6NVpHj6KQgo6tra-Jc,15995
191
- cirq/experiments/readout_confusion_matrix.py,sha256=gsRjGJTDcxRPtY7G63t-nYoJ1BcByC1jl02zHh2B8fQ,17278
192
- cirq/experiments/readout_confusion_matrix_test.py,sha256=R4UoGklVJ2owqeDTRVP4M9gYynzVYgw-Y76VLcoIJtY,6766
191
+ cirq/experiments/readout_confusion_matrix.py,sha256=jIyikXfYWGbVrOjU1pbV2VZL-m03VTFYS18KT1Cf2qk,21404
192
+ cirq/experiments/readout_confusion_matrix_test.py,sha256=ETvKHVuJWvq8KuL0l6w22UOfZHhBNH-TVeWAKqjSQEc,10632
193
193
  cirq/experiments/single_qubit_readout_calibration.py,sha256=ZmfsARZ_33Pg4lh5toJaoi4h4RGKHISAfWBODq1Icsg,14599
194
194
  cirq/experiments/single_qubit_readout_calibration_test.py,sha256=_002QXj2rIFHkH3vw9iTVMh45vCPuCI_fTqOUK8uMe4,7718
195
195
  cirq/experiments/t1_decay_experiment.py,sha256=ealdmc_RTE__z1YUcaDEncDzQOaiT0K6IRWB7lNtPfs,7087
@@ -1175,8 +1175,8 @@ cirq/work/sampler.py,sha256=JEAeQQRF3bqlO9AkOf4XbrTATDI5f5JgyM_FAUCNxao,19751
1175
1175
  cirq/work/sampler_test.py,sha256=B2ZsuqGT854gQtBIAh8k0LiG9Vj5wSzcGvkxOUoTcW4,13217
1176
1176
  cirq/work/zeros_sampler.py,sha256=x1C7cup66a43n-3tm8QjhiqJa07qcJW10FxNp9jJ59Q,2356
1177
1177
  cirq/work/zeros_sampler_test.py,sha256=JIkpBBFPJe5Ba4142vzogyWyboG1Q1ZAm0UVGgOoZn8,3279
1178
- cirq_core-1.5.0.dev20240626180854.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1179
- cirq_core-1.5.0.dev20240626180854.dist-info/METADATA,sha256=qeOYQoQu7J05WDDgOrFR-4rEmNO1ZHayBs0_Nw5_l88,2007
1180
- cirq_core-1.5.0.dev20240626180854.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
1181
- cirq_core-1.5.0.dev20240626180854.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1182
- cirq_core-1.5.0.dev20240626180854.dist-info/RECORD,,
1178
+ cirq_core-1.5.0.dev20240701205135.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
1179
+ cirq_core-1.5.0.dev20240701205135.dist-info/METADATA,sha256=TCy1YUSNHCmnT1kjhFUi8jyxdSWvfLdlT9634-F2HK8,2007
1180
+ cirq_core-1.5.0.dev20240701205135.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
1181
+ cirq_core-1.5.0.dev20240701205135.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
1182
+ cirq_core-1.5.0.dev20240701205135.dist-info/RECORD,,