|
15 | 15 | import dataclasses
|
16 | 16 | import itertools
|
17 | 17 |
|
18 |
| -from typing import Any, cast, Iterator, List, Optional, Sequence, Tuple, TYPE_CHECKING |
| 18 | +from typing import ( |
| 19 | + Any, |
| 20 | + cast, |
| 21 | + Iterator, |
| 22 | + List, |
| 23 | + Optional, |
| 24 | + Sequence, |
| 25 | + Tuple, |
| 26 | + TYPE_CHECKING, |
| 27 | + Mapping, |
| 28 | + Dict, |
| 29 | +) |
19 | 30 | import numpy as np
|
20 | 31 | from scipy.optimize import curve_fit
|
21 | 32 |
|
@@ -207,9 +218,9 @@ def single_qubit_randomized_benchmarking(
|
207 | 218 | qubit: 'cirq.Qid',
|
208 | 219 | use_xy_basis: bool = True,
|
209 | 220 | *,
|
210 |
| - num_clifford_range: Sequence[int] = range(10, 100, 10), |
211 |
| - num_circuits: int = 20, |
212 |
| - repetitions: int = 1000, |
| 221 | + num_clifford_range: Sequence[int] = tuple(np.logspace(np.log10(5), 3, 5, dtype=int)), |
| 222 | + num_circuits: int = 10, |
| 223 | + repetitions: int = 600, |
213 | 224 | ) -> RandomizedBenchMarkResult:
|
214 | 225 | """Clifford-based randomized benchmarking (RB) of a single qubit.
|
215 | 226 |
|
@@ -245,21 +256,75 @@ def single_qubit_randomized_benchmarking(
|
245 | 256 | A RandomizedBenchMarkResult object that stores and plots the result.
|
246 | 257 | """
|
247 | 258 |
|
| 259 | + qubits = cast(Iterator['cirq.Qid'], (qubit,)) |
| 260 | + result = parallel_single_qubit_randomized_benchmarking( |
| 261 | + sampler, |
| 262 | + qubits, |
| 263 | + use_xy_basis, |
| 264 | + num_clifford_range=num_clifford_range, |
| 265 | + num_circuits=num_circuits, |
| 266 | + repetitions=repetitions, |
| 267 | + ) |
| 268 | + return result[qubit] |
| 269 | + |
| 270 | + |
| 271 | +def parallel_single_qubit_randomized_benchmarking( |
| 272 | + sampler: 'cirq.Sampler', |
| 273 | + qubits: Iterator['cirq.Qid'], |
| 274 | + use_xy_basis: bool = True, |
| 275 | + *, |
| 276 | + num_clifford_range: Sequence[int] = tuple( |
| 277 | + np.logspace(np.log10(5), np.log10(1000), 5, dtype=int) |
| 278 | + ), |
| 279 | + num_circuits: int = 10, |
| 280 | + repetitions: int = 1000, |
| 281 | +) -> Mapping['cirq.Qid', 'RandomizedBenchMarkResult']: |
| 282 | + """Clifford-based randomized benchmarking (RB) single qubits in parallel. |
| 283 | +
|
| 284 | + This is the same as `single_qubit_randomized_benchmarking` except on all |
| 285 | + of the specified qubits in parallel, i.e. with the individual randomized |
| 286 | + benchmarking circuits zipped together. |
| 287 | +
|
| 288 | + Args: |
| 289 | + sampler: The quantum engine or simulator to run the circuits. |
| 290 | + use_xy_basis: Determines if the Clifford gates are built with x and y |
| 291 | + rotations (True) or x and z rotations (False). |
| 292 | + qubits: The qubits to benchmark. |
| 293 | + num_clifford_range: The different numbers of Cliffords in the RB study. |
| 294 | + num_circuits: The number of random circuits generated for each |
| 295 | + number of Cliffords. |
| 296 | + repetitions: The number of repetitions of each circuit. |
| 297 | +
|
| 298 | + Returns: |
| 299 | + A dictionary from qubits to RandomizedBenchMarkResult objects. |
| 300 | + """ |
| 301 | + |
248 | 302 | cliffords = _single_qubit_cliffords()
|
249 | 303 | c1 = cliffords.c1_in_xy if use_xy_basis else cliffords.c1_in_xz
|
250 |
| - cfd_mats = np.array([_gate_seq_to_mats(gates) for gates in c1]) |
| 304 | + clifford_mats = np.array([_gate_seq_to_mats(gates) for gates in c1]) |
251 | 305 |
|
252 |
| - gnd_probs = [] |
253 |
| - for num_cfds in num_clifford_range: |
254 |
| - excited_probs_l = [] |
| 306 | + # create circuits |
| 307 | + circuits_all: List['cirq.AbstractCircuit'] = [] |
| 308 | + for num_cliffords in num_clifford_range: |
255 | 309 | for _ in range(num_circuits):
|
256 |
| - circuit = _random_single_q_clifford(qubit, num_cfds, c1, cfd_mats) |
257 |
| - circuit.append(ops.measure(qubit, key='z')) |
258 |
| - results = sampler.run(circuit, repetitions=repetitions) |
259 |
| - excited_probs_l.append(np.mean(results.measurements['z'])) |
260 |
| - gnd_probs.append(1.0 - np.mean(excited_probs_l)) |
| 310 | + circuits_all.append( |
| 311 | + _create_parallel_rb_circuit(qubits, num_cliffords, c1, clifford_mats) |
| 312 | + ) |
261 | 313 |
|
262 |
| - return RandomizedBenchMarkResult(num_clifford_range, gnd_probs) |
| 314 | + # run circuits |
| 315 | + results = sampler.run_batch(circuits_all, repetitions=repetitions) |
| 316 | + gnd_probs: dict = {q: [] for q in qubits} |
| 317 | + idx = 0 |
| 318 | + for num_cliffords in num_clifford_range: |
| 319 | + excited_probs: Dict['cirq.Qid', List[float]] = {q: [] for q in qubits} |
| 320 | + for _ in range(num_circuits): |
| 321 | + result = results[idx][0] |
| 322 | + for qubit in qubits: |
| 323 | + excited_probs[qubit].append(np.mean(result.measurements[str(qubit)])) |
| 324 | + idx += 1 |
| 325 | + for qubit in qubits: |
| 326 | + gnd_probs[qubit].append(1.0 - np.mean(excited_probs[qubit])) |
| 327 | + return {q: RandomizedBenchMarkResult(num_clifford_range, gnd_probs[q]) for q in qubits} |
263 | 328 |
|
264 | 329 |
|
265 | 330 | def two_qubit_randomized_benchmarking(
|
@@ -496,6 +561,16 @@ def _measurement(two_qubit_circuit: circuits.Circuit) -> np.ndarray:
|
496 | 561 | return TomographyResult(rho)
|
497 | 562 |
|
498 | 563 |
|
| 564 | +def _create_parallel_rb_circuit( |
| 565 | + qubits: Iterator['cirq.Qid'], num_cliffords: int, c1: list, clifford_mats: np.ndarray |
| 566 | +) -> 'cirq.Circuit': |
| 567 | + circuits_to_zip = [ |
| 568 | + _random_single_q_clifford(qubit, num_cliffords, c1, clifford_mats) for qubit in qubits |
| 569 | + ] |
| 570 | + circuit = circuits.Circuit.zip(*circuits_to_zip) |
| 571 | + return circuits.Circuit.from_moments(*circuit, ops.measure_each(*qubits)) |
| 572 | + |
| 573 | + |
499 | 574 | def _indices_after_basis_rot(i: int, j: int) -> Tuple[int, Sequence[int], Sequence[int]]:
|
500 | 575 | mat_idx = 3 * (3 * i + j)
|
501 | 576 | q_0_i = 3 - i
|
|
0 commit comments