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 +1 -1
- cirq/_version_test.py +1 -1
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +211 -107
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +347 -3
- {cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/RECORD +9 -9
- {cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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:
|
|
132
|
-
|
|
133
|
-
pauli_op =
|
|
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
|
-
|
|
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:
|
|
189
|
-
|
|
190
|
-
circuit_results:
|
|
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
|
-
) ->
|
|
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
|
|
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
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
241
|
-
|
|
329
|
+
# Create a mask for the relevant qubits in the measurement results
|
|
330
|
+
relevant_bits = measurement_results[:, qubit_indices]
|
|
242
331
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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:
|
|
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
|
|
287
|
-
For each circuit
|
|
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
|
|
297
|
-
|
|
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
|
|
325
|
-
for
|
|
326
|
-
|
|
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,
|
|
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
|
|
436
|
+
for pauli_strings in pauli_string_groups:
|
|
337
437
|
basis_change_circuit = (
|
|
338
438
|
input_circuit_unfrozen
|
|
339
|
-
+
|
|
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,
|
|
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
|
-
|
|
366
|
-
circuits_results[
|
|
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(
|
|
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(
|
|
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] =
|
|
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.
|
|
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
|
+
)
|
{cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cirq-core
|
|
3
|
-
Version: 1.6.0.
|
|
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
|
{cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/RECORD
RENAMED
|
@@ -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=
|
|
8
|
-
cirq/_version_test.py,sha256=
|
|
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=
|
|
100
|
-
cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py,sha256=
|
|
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.
|
|
1213
|
-
cirq_core-1.6.0.
|
|
1214
|
-
cirq_core-1.6.0.
|
|
1215
|
-
cirq_core-1.6.0.
|
|
1216
|
-
cirq_core-1.6.0.
|
|
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,,
|
{cirq_core-1.6.0.dev20250501192724.dist-info → cirq_core-1.6.0.dev20250501231232.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|