cirq-core 1.6.0.dev20250505203257__py3-none-any.whl → 1.6.0.dev20250507172716__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.

Files changed (37) hide show
  1. cirq/_compat_test.py +4 -1
  2. cirq/_version.py +1 -1
  3. cirq/_version_test.py +1 -1
  4. cirq/circuits/insert_strategy.py +7 -5
  5. cirq/contrib/acquaintance/gates_test.py +3 -1
  6. cirq/contrib/graph_device/hypergraph.py +3 -1
  7. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +9 -3
  8. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +2 -0
  9. cirq/contrib/paulistring/pauli_string_optimize.py +2 -0
  10. cirq/contrib/qasm_import/qasm.py +2 -0
  11. cirq/contrib/quimb/density_matrix.py +4 -1
  12. cirq/contrib/quimb/state_vector.py +4 -1
  13. cirq/contrib/quirk/quirk_gate.py +3 -1
  14. cirq/contrib/routing/router.py +2 -0
  15. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +4 -0
  16. cirq/experiments/benchmarking/__init__.py +17 -0
  17. cirq/experiments/benchmarking/parallel_xeb.py +679 -0
  18. cirq/experiments/benchmarking/parallel_xeb_test.py +445 -0
  19. cirq/experiments/fidelity_estimation.py +11 -5
  20. cirq/experiments/two_qubit_xeb.py +4 -0
  21. cirq/linalg/combinators.py +4 -2
  22. cirq/linalg/predicates.py +6 -1
  23. cirq/linalg/tolerance.py +4 -1
  24. cirq/neutral_atoms/convert_to_neutral_atom_gates.py +9 -3
  25. cirq/ops/clifford_gate_test.py +3 -1
  26. cirq/ops/projector.py +13 -8
  27. cirq/transformers/gauge_compiling/cphase_gauge.py +2 -0
  28. cirq/vis/heatmap.py +1 -1
  29. cirq/work/sampler.py +33 -34
  30. cirq/work/sampler_test.py +6 -2
  31. cirq/work/zeros_sampler.py +3 -1
  32. cirq/work/zeros_sampler_test.py +3 -1
  33. {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/METADATA +1 -1
  34. {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/RECORD +37 -34
  35. {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/WHEEL +0 -0
  36. {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/licenses/LICENSE +0 -0
  37. {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,445 @@
1
+ # Copyright 2025 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import itertools
16
+ from concurrent import futures
17
+ from typing import Iterator
18
+
19
+ import networkx as nx
20
+ import numpy as np
21
+ import pytest
22
+
23
+ import cirq
24
+ import cirq.experiments.random_quantum_circuit_generation as rqcg
25
+ from cirq.experiments.benchmarking import parallel_xeb as xeb
26
+
27
+ _QUBITS = cirq.LineQubit.range(2)
28
+ _CIRCUIT_TEMPLATES = [
29
+ cirq.Circuit(cirq.X.on_each(_QUBITS), cirq.CZ(*_QUBITS), cirq.Y.on_each(_QUBITS)),
30
+ cirq.Circuit(cirq.Y.on_each(_QUBITS), cirq.CX(*_QUBITS), cirq.Z.on_each(_QUBITS)),
31
+ cirq.Circuit(cirq.Z.on_each(_QUBITS), cirq.CZ(*_QUBITS), cirq.X.on_each(_QUBITS)),
32
+ ]
33
+ _PAIRS = ((cirq.q(0, 0), cirq.q(0, 1)), (cirq.q(0, 2), cirq.q(0, 3)), (cirq.q(0, 4), cirq.q(0, 5)))
34
+
35
+
36
+ class TestXEBWideCircuitInfo:
37
+
38
+ def test_from_circuit(self):
39
+ permutation = [1, 2, 0]
40
+ target = cirq.CircuitOperation(cirq.FrozenCircuit(cirq.CNOT(*_QUBITS)))
41
+ wide_circuit = xeb.XEBWideCircuitInfo.from_narrow_circuits(
42
+ _CIRCUIT_TEMPLATES, permutation=permutation, pairs=_PAIRS, target=target
43
+ )
44
+ assert wide_circuit == xeb.XEBWideCircuitInfo(
45
+ wide_circuit=cirq.Circuit.from_moments(
46
+ [
47
+ cirq.Y.on_each(*_PAIRS[0]),
48
+ cirq.Z.on_each(*_PAIRS[1]),
49
+ cirq.X.on_each(*_PAIRS[2]),
50
+ ],
51
+ cirq.CircuitOperation(
52
+ cirq.FrozenCircuit(
53
+ cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
54
+ )
55
+ ),
56
+ [
57
+ cirq.Z.on_each(*_PAIRS[0]),
58
+ cirq.X.on_each(*_PAIRS[1]),
59
+ cirq.Y.on_each(*_PAIRS[2]),
60
+ ],
61
+ ),
62
+ pairs=_PAIRS,
63
+ narrow_template_indices=permutation,
64
+ )
65
+
66
+ def test_sliced_circuit(self):
67
+ wid_circuit = xeb.XEBWideCircuitInfo(
68
+ wide_circuit=cirq.Circuit.from_moments(
69
+ [
70
+ cirq.Y.on_each(*_PAIRS[0]),
71
+ cirq.Z.on_each(*_PAIRS[1]),
72
+ cirq.X.on_each(*_PAIRS[2]),
73
+ ],
74
+ cirq.CircuitOperation(
75
+ cirq.FrozenCircuit(
76
+ cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
77
+ )
78
+ ),
79
+ [
80
+ cirq.Z.on_each(*_PAIRS[0]),
81
+ cirq.X.on_each(*_PAIRS[1]),
82
+ cirq.Y.on_each(*_PAIRS[2]),
83
+ ],
84
+ ),
85
+ pairs=_PAIRS,
86
+ narrow_template_indices=[1, 2, 0],
87
+ )
88
+ sliced_circuit = xeb.XEBWideCircuitInfo(
89
+ wide_circuit=cirq.Circuit.from_moments(
90
+ [
91
+ cirq.Y.on_each(*_PAIRS[0]),
92
+ cirq.Z.on_each(*_PAIRS[1]),
93
+ cirq.X.on_each(*_PAIRS[2]),
94
+ ],
95
+ cirq.CircuitOperation(
96
+ cirq.FrozenCircuit(
97
+ cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
98
+ )
99
+ ),
100
+ [
101
+ cirq.Z.on_each(*_PAIRS[0]),
102
+ cirq.X.on_each(*_PAIRS[1]),
103
+ cirq.Y.on_each(*_PAIRS[2]),
104
+ ],
105
+ [cirq.measure(p, key=str(p)) for p in _PAIRS],
106
+ ),
107
+ pairs=_PAIRS,
108
+ narrow_template_indices=[1, 2, 0],
109
+ cycle_depth=1,
110
+ )
111
+
112
+ assert wid_circuit.sliced_circuits([1]) == [sliced_circuit]
113
+
114
+
115
+ def test_create_combination_circuits():
116
+ wide_circuits_info = xeb.create_combination_circuits(
117
+ _CIRCUIT_TEMPLATES,
118
+ [rqcg.CircuitLibraryCombination(layer=None, combinations=[[1, 2, 0]], pairs=_PAIRS)],
119
+ target=cirq.CNOT(*_QUBITS),
120
+ )
121
+
122
+ assert wide_circuits_info == [
123
+ xeb.XEBWideCircuitInfo(
124
+ wide_circuit=cirq.Circuit.from_moments(
125
+ [
126
+ cirq.Y.on_each(*_PAIRS[0]),
127
+ cirq.Z.on_each(*_PAIRS[1]),
128
+ cirq.X.on_each(*_PAIRS[2]),
129
+ ],
130
+ [cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])],
131
+ [
132
+ cirq.Z.on_each(*_PAIRS[0]),
133
+ cirq.X.on_each(*_PAIRS[1]),
134
+ cirq.Y.on_each(*_PAIRS[2]),
135
+ ],
136
+ ),
137
+ pairs=_PAIRS,
138
+ narrow_template_indices=[1, 2, 0],
139
+ )
140
+ ]
141
+
142
+
143
+ def test_create_combination_circuits_with_target_dict():
144
+ wide_circuits_info = xeb.create_combination_circuits(
145
+ _CIRCUIT_TEMPLATES,
146
+ [rqcg.CircuitLibraryCombination(layer=None, combinations=[[1, 2, 0]], pairs=_PAIRS)],
147
+ target={_PAIRS[0]: cirq.CNOT(*_QUBITS), _PAIRS[1]: cirq.CZ(*_QUBITS)},
148
+ )
149
+
150
+ # Wide circuit is created for the qubit pairs in the intersection between target.keys()
151
+ # and combination.pairs
152
+ assert wide_circuits_info == [
153
+ xeb.XEBWideCircuitInfo(
154
+ wide_circuit=cirq.Circuit.from_moments(
155
+ [cirq.Y.on_each(*_PAIRS[0]), cirq.Z.on_each(*_PAIRS[1])],
156
+ [cirq.CNOT(*_PAIRS[0]), cirq.CZ(*_PAIRS[1])],
157
+ [cirq.Z.on_each(*_PAIRS[0]), cirq.X.on_each(*_PAIRS[1])],
158
+ ),
159
+ pairs=_PAIRS,
160
+ narrow_template_indices=[1, 2, 0],
161
+ )
162
+ ]
163
+
164
+
165
+ def test_simulate_circuit():
166
+ sim = cirq.Simulator(seed=0)
167
+ circuit = cirq.Circuit.from_moments(
168
+ cirq.X.on_each(_QUBITS),
169
+ cirq.CNOT(*_QUBITS),
170
+ cirq.X.on_each(_QUBITS),
171
+ cirq.CNOT(*_QUBITS),
172
+ cirq.X.on_each(_QUBITS),
173
+ cirq.CNOT(*_QUBITS),
174
+ cirq.X.on_each(_QUBITS),
175
+ )
176
+
177
+ result = xeb.simulate_circuit(sim, circuit, [1, 3])
178
+ np.testing.assert_allclose(result, [[0, 1, 0, 0], [1, 0, 0, 0]]) # |01> # |00>
179
+
180
+
181
+ def test_simulate_circuit_library():
182
+ circuit_templates = [
183
+ cirq.Circuit.from_moments(
184
+ cirq.X.on_each(_QUBITS),
185
+ cirq.CNOT(*_QUBITS),
186
+ cirq.X.on_each(_QUBITS),
187
+ cirq.CNOT(*_QUBITS),
188
+ cirq.X.on_each(_QUBITS),
189
+ cirq.CNOT(*_QUBITS),
190
+ cirq.X.on_each(_QUBITS),
191
+ )
192
+ ]
193
+
194
+ result = xeb.simulate_circuit_library(
195
+ circuit_templates=circuit_templates, target_or_dict=cirq.CNOT(*_QUBITS), cycle_depths=(1, 3)
196
+ )
197
+ np.testing.assert_allclose(result, [[[0, 1, 0, 0], [1, 0, 0, 0]]]) # |01> # |00>
198
+
199
+
200
+ def test_simulate_circuit_library_with_target_dict():
201
+ circuit_templates = [
202
+ cirq.Circuit.from_moments(
203
+ [cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
204
+ cirq.CNOT(*_QUBITS),
205
+ [cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
206
+ cirq.CNOT(*_QUBITS),
207
+ [cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
208
+ cirq.CNOT(*_QUBITS),
209
+ [cirq.H(_QUBITS[0]), cirq.X(_QUBITS[1])],
210
+ )
211
+ ]
212
+
213
+ result = xeb.simulate_circuit_library(
214
+ circuit_templates=circuit_templates,
215
+ target_or_dict={_PAIRS[0]: cirq.CNOT(*_QUBITS), _PAIRS[1]: cirq.CZ(*_QUBITS)},
216
+ cycle_depths=(1, 3),
217
+ )
218
+
219
+ # First pair result.
220
+ np.testing.assert_allclose(result[_PAIRS[0]], [[[0.25, 0.25, 0.25, 0.25], [0, 1, 0, 0]]])
221
+
222
+ # Second pair result.
223
+ np.testing.assert_allclose(result[_PAIRS[1]], [[[0, 0, 1, 0], [1, 0, 0, 0]]]) # |10> # |00>
224
+
225
+
226
+ def test_sample_all_circuits():
227
+ wide_circuits = [
228
+ cirq.Circuit.from_moments(
229
+ [cirq.Y.on_each(*_PAIRS[0]), cirq.Z.on_each(*_PAIRS[1]), cirq.X.on_each(*_PAIRS[2])],
230
+ cirq.CircuitOperation(
231
+ cirq.FrozenCircuit(
232
+ cirq.CNOT(*_PAIRS[0]), cirq.CNOT(*_PAIRS[1]), cirq.CNOT(*_PAIRS[2])
233
+ )
234
+ ),
235
+ [cirq.Z.on_each(*_PAIRS[0]), cirq.X.on_each(*_PAIRS[1]), cirq.Y.on_each(*_PAIRS[2])],
236
+ [cirq.measure(p, key=str(p)) for p in _PAIRS],
237
+ )
238
+ ]
239
+ result = xeb.sample_all_circuits(cirq.Simulator(seed=0), circuits=wide_circuits, repetitions=10)
240
+ assert len(result) == len(wide_circuits)
241
+ assert result[0].keys() == {str(p) for p in _PAIRS}
242
+ np.testing.assert_allclose(
243
+ result[0]['(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1))'], [0, 0, 1, 0]
244
+ ) # |10>
245
+ np.testing.assert_allclose(
246
+ result[0]['(cirq.GridQubit(0, 2), cirq.GridQubit(0, 3))'], [0, 0, 0, 1]
247
+ ) # |11>
248
+ np.testing.assert_allclose(
249
+ result[0]['(cirq.GridQubit(0, 4), cirq.GridQubit(0, 5))'], [0, 1, 0, 0]
250
+ ) # |01>
251
+
252
+
253
+ def test_estimate_fidelities():
254
+ sampling_result = [{str(_PAIRS[0]): np.array([0.15, 0.15, 0.35, 0.35])}]
255
+
256
+ simulation_results = [[np.array([0.1, 0.2, 0.3, 0.4])]]
257
+
258
+ result = xeb.estimate_fidelities(
259
+ sampling_results=sampling_result,
260
+ simulation_results=simulation_results,
261
+ cycle_depths=(1,),
262
+ num_templates=1,
263
+ pairs=_PAIRS[:1],
264
+ wide_circuits_info=[
265
+ xeb.XEBWideCircuitInfo(
266
+ wide_circuit=cirq.Circuit.from_moments(
267
+ [cirq.Y.on_each(*_PAIRS[0])],
268
+ cirq.CNOT(*_PAIRS[0]),
269
+ [cirq.Z.on_each(*_PAIRS[0])],
270
+ cirq.measure(_PAIRS[0], key=str(_PAIRS[0])),
271
+ ),
272
+ cycle_depth=1,
273
+ narrow_template_indices=(0,),
274
+ pairs=_PAIRS[:1],
275
+ )
276
+ ],
277
+ )
278
+
279
+ assert result == [
280
+ xeb.XEBFidelity(pair=_PAIRS[0], cycle_depth=1, fidelity=pytest.approx(0.785, abs=2e-4))
281
+ ]
282
+
283
+
284
+ def test_estimate_fidelities_with_dict_target():
285
+ sampling_result = [{str(_PAIRS[0]): np.array([0.15, 0.15, 0.35, 0.35])}]
286
+
287
+ simulation_results = {_PAIRS[0]: [[np.array([0.1, 0.2, 0.3, 0.4])]]}
288
+
289
+ result = xeb.estimate_fidelities(
290
+ sampling_results=sampling_result,
291
+ simulation_results=simulation_results,
292
+ cycle_depths=(1,),
293
+ num_templates=1,
294
+ pairs=_PAIRS[:1],
295
+ wide_circuits_info=[
296
+ xeb.XEBWideCircuitInfo(
297
+ wide_circuit=cirq.Circuit.from_moments(
298
+ [cirq.Y.on_each(*_PAIRS[0])],
299
+ cirq.CNOT(*_PAIRS[0]),
300
+ [cirq.Z.on_each(*_PAIRS[0])],
301
+ cirq.measure(_PAIRS[0], key=str(_PAIRS[0])),
302
+ ),
303
+ cycle_depth=1,
304
+ narrow_template_indices=(0,),
305
+ pairs=_PAIRS[:1],
306
+ )
307
+ ],
308
+ )
309
+
310
+ assert result == [
311
+ xeb.XEBFidelity(pair=_PAIRS[0], cycle_depth=1, fidelity=pytest.approx(0.785, abs=2e-4))
312
+ ]
313
+
314
+
315
+ def _assert_fidelities_approx_equal(fids, expected: float, atol: float):
316
+ fids = np.asarray(fids).tolist()
317
+ fids.sort(reverse=True)
318
+ fids.pop() # discard smallest to make the test robust to randomness
319
+ np.testing.assert_allclose(fids, expected, atol=atol)
320
+
321
+
322
+ @pytest.mark.parametrize('target', [cirq.CZ, cirq.Circuit(cirq.CZ(*_QUBITS)), cirq.CZ(*_QUBITS)])
323
+ @pytest.mark.parametrize('pairs', [_PAIRS[:1], _PAIRS[:2]])
324
+ def test_parallel_two_qubit_xeb(target, pairs):
325
+ sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
326
+ result = xeb.parallel_two_qubit_xeb(
327
+ sampler=sampler,
328
+ target=target,
329
+ pairs=pairs,
330
+ parameters=xeb.XEBParameters(
331
+ n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
332
+ ),
333
+ )
334
+ _assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
335
+
336
+
337
+ class ExampleDevice(cirq.Device):
338
+ @property
339
+ def metadata(self) -> cirq.DeviceMetadata:
340
+ qubits = cirq.GridQubit.rect(3, 2, 4, 3)
341
+ graph = nx.Graph(
342
+ pair
343
+ for pair in itertools.combinations(qubits, 2)
344
+ if abs(pair[0].row - pair[1].row) + abs(pair[0].col - pair[1].col) == 1
345
+ )
346
+ return cirq.DeviceMetadata(qubits, graph)
347
+
348
+
349
+ class ExampleProcessor:
350
+ def get_device(self):
351
+ return ExampleDevice()
352
+
353
+
354
+ class DensityMatrixSimulatorWithProcessor(cirq.DensityMatrixSimulator):
355
+ @property
356
+ def processor(self):
357
+ return ExampleProcessor()
358
+
359
+
360
+ def test_parallel_two_qubit_xeb_with_device():
361
+ target = cirq.CZ
362
+ sampler = DensityMatrixSimulatorWithProcessor(noise=cirq.depolarize(0.03), seed=0)
363
+ result = xeb.parallel_two_qubit_xeb(
364
+ sampler=sampler,
365
+ target=target,
366
+ parameters=xeb.XEBParameters(
367
+ n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
368
+ ),
369
+ )
370
+ _assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
371
+ qubits = cirq.GridQubit.rect(3, 2, 4, 3)
372
+ pairs = tuple(
373
+ pair
374
+ for pair in itertools.combinations(qubits, 2)
375
+ if abs(pair[0].row - pair[1].row) + abs(pair[0].col - pair[1].col) == 1
376
+ and pair[0] < pair[1]
377
+ )
378
+ assert result.all_qubit_pairs == pairs
379
+
380
+
381
+ def test_parallel_two_qubit_xeb_with_dict_target():
382
+ target = {p: cirq.Circuit(cirq.CZ(*_QUBITS)) for p in _PAIRS[:2]}
383
+ target[_PAIRS[2]] = cirq.CZ(*_QUBITS)
384
+ sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
385
+ result = xeb.parallel_two_qubit_xeb(
386
+ sampler=sampler,
387
+ target=target,
388
+ parameters=xeb.XEBParameters(
389
+ n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
390
+ ),
391
+ )
392
+ _assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
393
+ assert result.all_qubit_pairs == _PAIRS
394
+
395
+
396
+ def test_parallel_two_qubit_xeb_with_ideal_target():
397
+ target = {p: cirq.Circuit(cirq.CZ(*_QUBITS)) for p in _PAIRS[:2]}
398
+ target[_PAIRS[2]] = cirq.CZ(*_QUBITS)
399
+ sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
400
+ result = xeb.parallel_two_qubit_xeb(
401
+ sampler=sampler,
402
+ target=target,
403
+ ideal_target=cirq.CZ,
404
+ parameters=xeb.XEBParameters(
405
+ n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
406
+ ),
407
+ )
408
+ _assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
409
+ assert result.all_qubit_pairs == _PAIRS
410
+
411
+
412
+ @pytest.fixture
413
+ def threading_pool() -> Iterator[futures.Executor]:
414
+ with futures.ThreadPoolExecutor(1) as pool:
415
+ yield pool
416
+
417
+
418
+ def test_parallel_two_qubit_xeb_with_dict_target_and_pool(threading_pool):
419
+ target = {p: cirq.Circuit(cirq.CZ(*_QUBITS)) for p in _PAIRS}
420
+ sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(0.03), seed=0)
421
+ result = xeb.parallel_two_qubit_xeb(
422
+ sampler=sampler,
423
+ target=target,
424
+ parameters=xeb.XEBParameters(
425
+ n_circuits=10, n_combinations=10, n_repetitions=10, cycle_depths=range(1, 10, 2)
426
+ ),
427
+ pool=threading_pool,
428
+ )
429
+ _assert_fidelities_approx_equal(result.fidelities.layer_fid, 0.9, atol=0.3)
430
+ assert result.all_qubit_pairs == _PAIRS
431
+
432
+
433
+ def test_parallel_two_qubit_xeb_with_invalid_input_raises():
434
+ with pytest.raises(AssertionError):
435
+ _ = xeb.parallel_two_qubit_xeb(
436
+ sampler=cirq.Simulator(seed=0), target={_PAIRS[0]: cirq.CZ}, pairs=_PAIRS
437
+ )
438
+
439
+ with pytest.raises(AssertionError):
440
+ _ = xeb.parallel_two_qubit_xeb(
441
+ sampler=cirq.Simulator(seed=0),
442
+ target=cirq.CZ,
443
+ ideal_target={_PAIRS[0]: cirq.CZ},
444
+ pairs=_PAIRS,
445
+ )
@@ -11,16 +11,22 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
14
15
  """Estimation of fidelity associated with experimental circuit executions."""
15
- from typing import Callable, Mapping, Optional, Sequence
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Callable, Mapping, Optional, Sequence, TYPE_CHECKING
16
20
 
17
21
  import numpy as np
18
22
 
19
- from cirq.circuits import Circuit
20
23
  from cirq.ops import QubitOrder, QubitOrderOrList
21
24
  from cirq.sim import final_state_vector
22
25
  from cirq.value import state_vector_to_probabilities
23
26
 
27
+ if TYPE_CHECKING:
28
+ import cirq
29
+
24
30
 
25
31
  def linear_xeb_fidelity_from_probabilities(
26
32
  hilbert_space_dimension: int, probabilities: Sequence[float]
@@ -132,7 +138,7 @@ def hog_score_xeb_fidelity_from_probabilities(
132
138
 
133
139
 
134
140
  def xeb_fidelity(
135
- circuit: Circuit,
141
+ circuit: cirq.Circuit,
136
142
  bitstrings: Sequence[int],
137
143
  qubit_order: QubitOrderOrList = QubitOrder.DEFAULT,
138
144
  amplitudes: Optional[Mapping[int, complex]] = None,
@@ -197,7 +203,7 @@ def xeb_fidelity(
197
203
 
198
204
 
199
205
  def linear_xeb_fidelity(
200
- circuit: Circuit,
206
+ circuit: cirq.Circuit,
201
207
  bitstrings: Sequence[int],
202
208
  qubit_order: QubitOrderOrList = QubitOrder.DEFAULT,
203
209
  amplitudes: Optional[Mapping[int, complex]] = None,
@@ -213,7 +219,7 @@ def linear_xeb_fidelity(
213
219
 
214
220
 
215
221
  def log_xeb_fidelity(
216
- circuit: Circuit,
222
+ circuit: cirq.Circuit,
217
223
  bitstrings: Sequence[int],
218
224
  qubit_order: QubitOrderOrList = QubitOrder.DEFAULT,
219
225
  amplitudes: Optional[Mapping[int, complex]] = None,
@@ -107,6 +107,10 @@ class TwoQubitXEBResult:
107
107
 
108
108
  @functools.cached_property
109
109
  def _qubit_pair_map(self) -> Dict[Tuple[cirq.GridQubit, cirq.GridQubit], int]:
110
+ if isinstance(self.fidelities.index[0][0], ops.Qid):
111
+ return {
112
+ (min(q0, q1), max(q0, q1)): i for i, (q0, q1) in enumerate(self.fidelities.index)
113
+ }
110
114
  return {
111
115
  (min(q0, q1), max(q0, q1)): i
112
116
  for i, (_, _, (q0, q1)) in enumerate(self.fidelities.index)
@@ -14,6 +14,8 @@
14
14
 
15
15
  """Utility methods for combining matrices."""
16
16
 
17
+ from __future__ import annotations
18
+
17
19
  import functools
18
20
  from typing import TYPE_CHECKING, Union
19
21
 
@@ -107,7 +109,7 @@ def kron_with_controls(*factors: Union[np.ndarray, complex]) -> np.ndarray:
107
109
  return product
108
110
 
109
111
 
110
- def dot(*values: 'ArrayLike') -> np.ndarray:
112
+ def dot(*values: ArrayLike) -> np.ndarray:
111
113
  """Computes the dot/matrix product of a sequence of values.
112
114
 
113
115
  Performs the computation in serial order without regard to the matrix
@@ -136,7 +138,7 @@ def dot(*values: 'ArrayLike') -> np.ndarray:
136
138
  return result
137
139
 
138
140
 
139
- def _merge_dtypes(dtype1: 'DTypeLike', dtype2: 'DTypeLike') -> np.dtype:
141
+ def _merge_dtypes(dtype1: DTypeLike, dtype2: DTypeLike) -> np.dtype:
140
142
  return (np.zeros(0, dtype1) + np.zeros(0, dtype2)).dtype
141
143
 
142
144
 
cirq/linalg/predicates.py CHANGED
@@ -11,7 +11,12 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
14
15
  """Utility methods for checking properties of matrices."""
16
+
17
+ from __future__ import annotations
18
+
19
+ from types import EllipsisType
15
20
  from typing import cast, List, Optional, Sequence, Tuple, Union
16
21
 
17
22
  import numpy as np
@@ -228,7 +233,7 @@ def slice_for_qubits_equal_to(
228
233
  big_endian_qureg_value: int = 0,
229
234
  num_qubits: Optional[int] = None,
230
235
  qid_shape: Optional[Tuple[int, ...]] = None,
231
- ) -> Tuple[Union[slice, int, 'ellipsis'], ...]:
236
+ ) -> Tuple[Union[slice, int, EllipsisType], ...]:
232
237
  """Returns an index corresponding to a desired subset of an np.ndarray.
233
238
 
234
239
  It is assumed that the np.ndarray's shape is of the form (2, 2, 2, ..., 2).
cirq/linalg/tolerance.py CHANGED
@@ -14,6 +14,9 @@
14
14
 
15
15
  """Utility for testing approximate equality of matrices and scalars within
16
16
  tolerances."""
17
+
18
+ from __future__ import annotations
19
+
17
20
  from typing import Iterable, TYPE_CHECKING, Union
18
21
 
19
22
  import numpy as np
@@ -22,7 +25,7 @@ if TYPE_CHECKING:
22
25
  from numpy.typing import ArrayLike
23
26
 
24
27
 
25
- def all_near_zero(a: 'ArrayLike', *, atol: float = 1e-8) -> bool:
28
+ def all_near_zero(a: ArrayLike, *, atol: float = 1e-8) -> bool:
26
29
  """Checks if the tensor's elements are all near zero.
27
30
 
28
31
  Args:
@@ -12,15 +12,21 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from cirq import ops
15
+ from __future__ import annotations
16
+
17
+ from typing import TYPE_CHECKING
18
+
16
19
  from cirq.neutral_atoms import neutral_atom_devices
17
20
 
21
+ if TYPE_CHECKING:
22
+ import cirq
23
+
18
24
 
19
- def is_native_neutral_atom_op(operation: ops.Operation) -> bool:
25
+ def is_native_neutral_atom_op(operation: cirq.Operation) -> bool:
20
26
  """Returns true if the operation is in the default neutral atom gateset."""
21
27
  return operation in neutral_atom_devices.neutral_atom_gateset()
22
28
 
23
29
 
24
- def is_native_neutral_atom_gate(gate: ops.Gate) -> bool:
30
+ def is_native_neutral_atom_gate(gate: cirq.Gate) -> bool:
25
31
  """Returns true if the gate is in the default neutral atom gateset."""
26
32
  return gate in neutral_atom_devices.neutral_atom_gateset()
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import functools
16
18
  import itertools
17
19
  from typing import Tuple, Type
@@ -59,7 +61,7 @@ def _all_rotation_pairs():
59
61
 
60
62
 
61
63
  @functools.lru_cache()
62
- def _all_clifford_gates() -> Tuple['cirq.SingleQubitCliffordGate', ...]:
64
+ def _all_clifford_gates() -> Tuple[cirq.SingleQubitCliffordGate, ...]:
63
65
  return tuple(
64
66
  cirq.SingleQubitCliffordGate.from_xz_map(trans_x, trans_z)
65
67
  for trans_x, trans_z in _all_rotation_pairs()
cirq/ops/projector.py CHANGED
@@ -1,13 +1,18 @@
1
1
  # pylint: disable=wrong-or-nonexistent-copyright-notice
2
+
3
+ from __future__ import annotations
4
+
2
5
  import itertools
3
6
  import math
4
- from typing import Any, Dict, Iterable, List, Mapping, Optional
7
+ from typing import Any, Dict, Iterable, List, Mapping, Optional, TYPE_CHECKING
5
8
 
6
9
  import numpy as np
7
10
  from scipy.sparse import csr_matrix
8
11
 
9
12
  from cirq import value
10
- from cirq.ops import raw_types
13
+
14
+ if TYPE_CHECKING:
15
+ import cirq
11
16
 
12
17
 
13
18
  def _check_qids_dimension(qids):
@@ -21,7 +26,7 @@ def _check_qids_dimension(qids):
21
26
  class ProjectorString:
22
27
  """Mapping of `cirq.Qid` to measurement values (with a coefficient) representing a projector."""
23
28
 
24
- def __init__(self, projector_dict: Dict[raw_types.Qid, int], coefficient: complex = 1):
29
+ def __init__(self, projector_dict: Dict[cirq.Qid, int], coefficient: complex = 1):
25
30
  """Constructor for ProjectorString
26
31
 
27
32
  Args:
@@ -34,14 +39,14 @@ class ProjectorString:
34
39
  self._coefficient = complex(coefficient)
35
40
 
36
41
  @property
37
- def projector_dict(self) -> Dict[raw_types.Qid, int]:
42
+ def projector_dict(self) -> Dict[cirq.Qid, int]:
38
43
  return self._projector_dict
39
44
 
40
45
  @property
41
46
  def coefficient(self) -> complex:
42
47
  return self._coefficient
43
48
 
44
- def matrix(self, projector_qids: Optional[Iterable[raw_types.Qid]] = None) -> csr_matrix:
49
+ def matrix(self, projector_qids: Optional[Iterable[cirq.Qid]] = None) -> csr_matrix:
45
50
  """Returns the matrix of self in computational basis of qubits.
46
51
 
47
52
  Args:
@@ -75,7 +80,7 @@ class ProjectorString:
75
80
  ([self._coefficient] * len(ones_idx), (ones_idx, ones_idx)), shape=(total_d, total_d)
76
81
  )
77
82
 
78
- def _get_idx_to_keep(self, qid_map: Mapping[raw_types.Qid, int]):
83
+ def _get_idx_to_keep(self, qid_map: Mapping[cirq.Qid, int]):
79
84
  num_qubits = len(qid_map)
80
85
  idx_to_keep: List[Any] = [slice(0, 2)] * num_qubits
81
86
  for q in self.projector_dict.keys():
@@ -83,7 +88,7 @@ class ProjectorString:
83
88
  return tuple(idx_to_keep)
84
89
 
85
90
  def expectation_from_state_vector(
86
- self, state_vector: np.ndarray, qid_map: Mapping[raw_types.Qid, int]
91
+ self, state_vector: np.ndarray, qid_map: Mapping[cirq.Qid, int]
87
92
  ) -> complex:
88
93
  """Expectation of the projection from a state vector.
89
94
 
@@ -105,7 +110,7 @@ class ProjectorString:
105
110
  )
106
111
 
107
112
  def expectation_from_density_matrix(
108
- self, state: np.ndarray, qid_map: Mapping[raw_types.Qid, int]
113
+ self, state: np.ndarray, qid_map: Mapping[cirq.Qid, int]
109
114
  ) -> complex:
110
115
  """Expectation of the projection from a density matrix.
111
116