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.
- cirq/_compat_test.py +4 -1
- cirq/_version.py +1 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/insert_strategy.py +7 -5
- cirq/contrib/acquaintance/gates_test.py +3 -1
- cirq/contrib/graph_device/hypergraph.py +3 -1
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +9 -3
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +2 -0
- cirq/contrib/paulistring/pauli_string_optimize.py +2 -0
- cirq/contrib/qasm_import/qasm.py +2 -0
- cirq/contrib/quimb/density_matrix.py +4 -1
- cirq/contrib/quimb/state_vector.py +4 -1
- cirq/contrib/quirk/quirk_gate.py +3 -1
- cirq/contrib/routing/router.py +2 -0
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +4 -0
- cirq/experiments/benchmarking/__init__.py +17 -0
- cirq/experiments/benchmarking/parallel_xeb.py +679 -0
- cirq/experiments/benchmarking/parallel_xeb_test.py +445 -0
- cirq/experiments/fidelity_estimation.py +11 -5
- cirq/experiments/two_qubit_xeb.py +4 -0
- cirq/linalg/combinators.py +4 -2
- cirq/linalg/predicates.py +6 -1
- cirq/linalg/tolerance.py +4 -1
- cirq/neutral_atoms/convert_to_neutral_atom_gates.py +9 -3
- cirq/ops/clifford_gate_test.py +3 -1
- cirq/ops/projector.py +13 -8
- cirq/transformers/gauge_compiling/cphase_gauge.py +2 -0
- cirq/vis/heatmap.py +1 -1
- cirq/work/sampler.py +33 -34
- cirq/work/sampler_test.py +6 -2
- cirq/work/zeros_sampler.py +3 -1
- cirq/work/zeros_sampler_test.py +3 -1
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/RECORD +37 -34
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250505203257.dist-info → cirq_core-1.6.0.dev20250507172716.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
|
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)
|
cirq/linalg/combinators.py
CHANGED
|
@@ -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:
|
|
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:
|
|
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,
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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()
|
cirq/ops/clifford_gate_test.py
CHANGED
|
@@ -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[
|
|
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
|
-
|
|
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[
|
|
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[
|
|
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[
|
|
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[
|
|
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[
|
|
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[
|
|
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
|
|