From 9d81eed5e8df470c72d514969a552d26fab33507 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 25 May 2022 20:50:16 +0300 Subject: [PATCH 01/39] New algorithm for generating Clifford circuits for single qubit. We generate once all 24 transpiled Cliffords. Then, for every rb_circuit, select Cliffords at random and compose them to a circuit --- .../framework/base_experiment.py | 5 +- .../randomized_benchmarking/cliff_data.py | 605 ++++++++++++++++++ .../randomized_benchmarking/fast_rb.py | 82 +++ .../randomized_benchmarking/rb_experiment.py | 20 +- .../test_randomized_benchmarking.py | 14 +- 5 files changed, 715 insertions(+), 11 deletions(-) create mode 100644 qiskit_experiments/library/randomized_benchmarking/cliff_data.py create mode 100644 qiskit_experiments/library/randomized_benchmarking/fast_rb.py diff --git a/qiskit_experiments/framework/base_experiment.py b/qiskit_experiments/framework/base_experiment.py index e0656eb986..d1d9332fe9 100644 --- a/qiskit_experiments/framework/base_experiment.py +++ b/qiskit_experiments/framework/base_experiment.py @@ -18,6 +18,7 @@ from collections import OrderedDict from typing import Sequence, Optional, Tuple, List, Dict, Union import warnings +import time from qiskit import transpile, QuantumCircuit from qiskit.providers import Job, Backend @@ -262,8 +263,10 @@ def run( experiment._finalize() # Generate and transpile circuits + start = time.time() transpiled_circuits = experiment._transpiled_circuits() - + end = time.time() + print("time for transpiled_circuits = " + str(end-start)) # Initialize result container experiment_data = experiment._initialize_experiment_data() diff --git a/qiskit_experiments/library/randomized_benchmarking/cliff_data.py b/qiskit_experiments/library/randomized_benchmarking/cliff_data.py new file mode 100644 index 0000000000..fb6dd1f086 --- /dev/null +++ b/qiskit_experiments/library/randomized_benchmarking/cliff_data.py @@ -0,0 +1,605 @@ +CLIFF_COMPOSE_DATA = { + (0, 0): 0, + (0, 1): 1, + (0, 2): 2, + (0, 3): 3, + (0, 4): 4, + (0, 5): 5, + (0, 6): 6, + (0, 7): 7, + (0, 8): 8, + (0, 9): 9, + (0, 10): 10, + (0, 11): 11, + (0, 12): 12, + (0, 13): 13, + (0, 14): 14, + (0, 15): 15, + (0, 16): 16, + (0, 17): 17, + (0, 18): 18, + (0, 19): 19, + (0, 20): 20, + (0, 21): 21, + (0, 22): 22, + (0, 23): 23, + (1, 0): 1, + (1, 1): 0, + (1, 2): 23, + (1, 3): 22, + (1, 4): 9, + (1, 5): 8, + (1, 6): 19, + (1, 7): 18, + (1, 8): 5, + (1, 9): 4, + (1, 10): 15, + (1, 11): 14, + (1, 12): 13, + (1, 13): 12, + (1, 14): 11, + (1, 15): 10, + (1, 16): 21, + (1, 17): 20, + (1, 18): 7, + (1, 19): 6, + (1, 20): 17, + (1, 21): 16, + (1, 22): 3, + (1, 23): 2, + (2, 0): 2, + (2, 1): 3, + (2, 2): 6, + (2, 3): 7, + (2, 4): 17, + (2, 5): 16, + (2, 6): 8, + (2, 7): 9, + (2, 8): 0, + (2, 9): 1, + (2, 10): 23, + (2, 11): 22, + (2, 12): 20, + (2, 13): 21, + (2, 14): 12, + (2, 15): 13, + (2, 16): 11, + (2, 17): 10, + (2, 18): 14, + (2, 19): 15, + (2, 20): 18, + (2, 21): 19, + (2, 22): 5, + (2, 23): 4, + (3, 0): 3, + (3, 1): 2, + (3, 2): 4, + (3, 3): 5, + (3, 4): 1, + (3, 5): 0, + (3, 6): 15, + (3, 7): 14, + (3, 8): 16, + (3, 9): 17, + (3, 10): 13, + (3, 11): 12, + (3, 12): 21, + (3, 13): 20, + (3, 14): 22, + (3, 15): 23, + (3, 16): 19, + (3, 17): 18, + (3, 18): 9, + (3, 19): 8, + (3, 20): 10, + (3, 21): 11, + (3, 22): 7, + (3, 23): 6, + (4, 0): 4, + (4, 1): 5, + (4, 2): 15, + (4, 3): 14, + (4, 4): 18, + (4, 5): 19, + (4, 6): 16, + (4, 7): 17, + (4, 8): 3, + (4, 9): 2, + (4, 10): 6, + (4, 11): 7, + (4, 12): 10, + (4, 13): 11, + (4, 14): 21, + (4, 15): 20, + (4, 16): 12, + (4, 17): 13, + (4, 18): 22, + (4, 19): 23, + (4, 20): 9, + (4, 21): 8, + (4, 22): 0, + (4, 23): 1, + (5, 0): 5, + (5, 1): 4, + (5, 2): 1, + (5, 3): 0, + (5, 4): 2, + (5, 5): 3, + (5, 6): 23, + (5, 7): 22, + (5, 8): 19, + (5, 9): 18, + (5, 10): 20, + (5, 11): 21, + (5, 12): 11, + (5, 13): 10, + (5, 14): 7, + (5, 15): 6, + (5, 16): 8, + (5, 17): 9, + (5, 18): 17, + (5, 19): 16, + (5, 20): 13, + (5, 21): 12, + (5, 22): 14, + (5, 23): 15, + (6, 0): 6, + (6, 1): 7, + (6, 2): 8, + (6, 3): 9, + (6, 4): 10, + (6, 5): 11, + (6, 6): 0, + (6, 7): 1, + (6, 8): 2, + (6, 9): 3, + (6, 10): 4, + (6, 11): 5, + (6, 12): 18, + (6, 13): 19, + (6, 14): 20, + (6, 15): 21, + (6, 16): 22, + (6, 17): 23, + (6, 18): 12, + (6, 19): 13, + (6, 20): 14, + (6, 21): 15, + (6, 22): 16, + (6, 23): 17, + (7, 0): 7, + (7, 1): 6, + (7, 2): 17, + (7, 3): 16, + (7, 4): 3, + (7, 5): 2, + (7, 6): 13, + (7, 7): 12, + (7, 8): 11, + (7, 9): 10, + (7, 10): 21, + (7, 11): 20, + (7, 12): 19, + (7, 13): 18, + (7, 14): 5, + (7, 15): 4, + (7, 16): 15, + (7, 17): 14, + (7, 18): 1, + (7, 19): 0, + (7, 20): 23, + (7, 21): 22, + (7, 22): 9, + (7, 23): 8, + (8, 0): 8, + (8, 1): 9, + (8, 2): 0, + (8, 3): 1, + (8, 4): 23, + (8, 5): 22, + (8, 6): 2, + (8, 7): 3, + (8, 8): 6, + (8, 9): 7, + (8, 10): 17, + (8, 11): 16, + (8, 12): 14, + (8, 13): 15, + (8, 14): 18, + (8, 15): 19, + (8, 16): 5, + (8, 17): 4, + (8, 18): 20, + (8, 19): 21, + (8, 20): 12, + (8, 21): 13, + (8, 22): 11, + (8, 23): 10, + (9, 0): 9, + (9, 1): 8, + (9, 2): 10, + (9, 3): 11, + (9, 4): 7, + (9, 5): 6, + (9, 6): 21, + (9, 7): 20, + (9, 8): 22, + (9, 9): 23, + (9, 10): 19, + (9, 11): 18, + (9, 12): 15, + (9, 13): 14, + (9, 14): 16, + (9, 15): 17, + (9, 16): 13, + (9, 17): 12, + (9, 18): 3, + (9, 19): 2, + (9, 20): 4, + (9, 21): 5, + (9, 22): 1, + (9, 23): 0, + (10, 0): 10, + (10, 1): 11, + (10, 2): 21, + (10, 3): 20, + (10, 4): 12, + (10, 5): 13, + (10, 6): 22, + (10, 7): 23, + (10, 8): 9, + (10, 9): 8, + (10, 10): 0, + (10, 11): 1, + (10, 12): 4, + (10, 13): 5, + (10, 14): 15, + (10, 15): 14, + (10, 16): 18, + (10, 17): 19, + (10, 18): 16, + (10, 19): 17, + (10, 20): 3, + (10, 21): 2, + (10, 22): 6, + (10, 23): 7, + (11, 0): 11, + (11, 1): 10, + (11, 2): 7, + (11, 3): 6, + (11, 4): 8, + (11, 5): 9, + (11, 6): 17, + (11, 7): 16, + (11, 8): 13, + (11, 9): 12, + (11, 10): 14, + (11, 11): 15, + (11, 12): 5, + (11, 13): 4, + (11, 14): 1, + (11, 15): 0, + (11, 16): 2, + (11, 17): 3, + (11, 18): 23, + (11, 19): 22, + (11, 20): 19, + (11, 21): 18, + (11, 22): 20, + (11, 23): 21, + (12, 0): 12, + (12, 1): 13, + (12, 2): 14, + (12, 3): 15, + (12, 4): 16, + (12, 5): 17, + (12, 6): 18, + (12, 7): 19, + (12, 8): 20, + (12, 9): 21, + (12, 10): 22, + (12, 11): 23, + (12, 12): 0, + (12, 13): 1, + (12, 14): 2, + (12, 15): 3, + (12, 16): 4, + (12, 17): 5, + (12, 18): 6, + (12, 19): 7, + (12, 20): 8, + (12, 21): 9, + (12, 22): 10, + (12, 23): 11, + (13, 0): 13, + (13, 1): 12, + (13, 2): 11, + (13, 3): 10, + (13, 4): 21, + (13, 5): 20, + (13, 6): 7, + (13, 7): 6, + (13, 8): 17, + (13, 9): 16, + (13, 10): 3, + (13, 11): 2, + (13, 12): 1, + (13, 13): 0, + (13, 14): 23, + (13, 15): 22, + (13, 16): 9, + (13, 17): 8, + (13, 18): 19, + (13, 19): 18, + (13, 20): 5, + (13, 21): 4, + (13, 22): 15, + (13, 23): 14, + (14, 0): 14, + (14, 1): 15, + (14, 2): 18, + (14, 3): 19, + (14, 4): 5, + (14, 5): 4, + (14, 6): 20, + (14, 7): 21, + (14, 8): 12, + (14, 9): 13, + (14, 10): 11, + (14, 11): 10, + (14, 12): 8, + (14, 13): 9, + (14, 14): 0, + (14, 15): 1, + (14, 16): 23, + (14, 17): 22, + (14, 18): 2, + (14, 19): 3, + (14, 20): 6, + (14, 21): 7, + (14, 22): 17, + (14, 23): 16, + (15, 0): 15, + (15, 1): 14, + (15, 2): 16, + (15, 3): 17, + (15, 4): 13, + (15, 5): 12, + (15, 6): 3, + (15, 7): 2, + (15, 8): 4, + (15, 9): 5, + (15, 10): 1, + (15, 11): 0, + (15, 12): 9, + (15, 13): 8, + (15, 14): 10, + (15, 15): 11, + (15, 16): 7, + (15, 17): 6, + (15, 18): 21, + (15, 19): 20, + (15, 20): 22, + (15, 21): 23, + (15, 22): 19, + (15, 23): 18, + (16, 0): 16, + (16, 1): 17, + (16, 2): 3, + (16, 3): 2, + (16, 4): 6, + (16, 5): 7, + (16, 6): 4, + (16, 7): 5, + (16, 8): 15, + (16, 9): 14, + (16, 10): 18, + (16, 11): 19, + (16, 12): 22, + (16, 13): 23, + (16, 14): 9, + (16, 15): 8, + (16, 16): 0, + (16, 17): 1, + (16, 18): 10, + (16, 19): 11, + (16, 20): 21, + (16, 21): 20, + (16, 22): 12, + (16, 23): 13, + (17, 0): 17, + (17, 1): 16, + (17, 2): 13, + (17, 3): 12, + (17, 4): 14, + (17, 5): 15, + (17, 6): 11, + (17, 7): 10, + (17, 8): 7, + (17, 9): 6, + (17, 10): 8, + (17, 11): 9, + (17, 12): 23, + (17, 13): 22, + (17, 14): 19, + (17, 15): 18, + (17, 16): 20, + (17, 17): 21, + (17, 18): 5, + (17, 19): 4, + (17, 20): 1, + (17, 21): 0, + (17, 22): 2, + (17, 23): 3, + (18, 0): 18, + (18, 1): 19, + (18, 2): 20, + (18, 3): 21, + (18, 4): 22, + (18, 5): 23, + (18, 6): 12, + (18, 7): 13, + (18, 8): 14, + (18, 9): 15, + (18, 10): 16, + (18, 11): 17, + (18, 12): 6, + (18, 13): 7, + (18, 14): 8, + (18, 15): 9, + (18, 16): 10, + (18, 17): 11, + (18, 18): 0, + (18, 19): 1, + (18, 20): 2, + (18, 21): 3, + (18, 22): 4, + (18, 23): 5, + (19, 0): 19, + (19, 1): 18, + (19, 2): 5, + (19, 3): 4, + (19, 4): 15, + (19, 5): 14, + (19, 6): 1, + (19, 7): 0, + (19, 8): 23, + (19, 9): 22, + (19, 10): 9, + (19, 11): 8, + (19, 12): 7, + (19, 13): 6, + (19, 14): 17, + (19, 15): 16, + (19, 16): 3, + (19, 17): 2, + (19, 18): 13, + (19, 19): 12, + (19, 20): 11, + (19, 21): 10, + (19, 22): 21, + (19, 23): 20, + (20, 0): 20, + (20, 1): 21, + (20, 2): 12, + (20, 3): 13, + (20, 4): 11, + (20, 5): 10, + (20, 6): 14, + (20, 7): 15, + (20, 8): 18, + (20, 9): 19, + (20, 10): 5, + (20, 11): 4, + (20, 12): 2, + (20, 13): 3, + (20, 14): 6, + (20, 15): 7, + (20, 16): 17, + (20, 17): 16, + (20, 18): 8, + (20, 19): 9, + (20, 20): 0, + (20, 21): 1, + (20, 22): 23, + (20, 23): 22, + (21, 0): 21, + (21, 1): 20, + (21, 2): 22, + (21, 3): 23, + (21, 4): 19, + (21, 5): 18, + (21, 6): 9, + (21, 7): 8, + (21, 8): 10, + (21, 9): 11, + (21, 10): 7, + (21, 11): 6, + (21, 12): 3, + (21, 13): 2, + (21, 14): 4, + (21, 15): 5, + (21, 16): 1, + (21, 17): 0, + (21, 18): 15, + (21, 19): 14, + (21, 20): 16, + (21, 21): 17, + (21, 22): 13, + (21, 23): 12, + (22, 0): 22, + (22, 1): 23, + (22, 2): 9, + (22, 3): 8, + (22, 4): 0, + (22, 5): 1, + (22, 6): 10, + (22, 7): 11, + (22, 8): 21, + (22, 9): 20, + (22, 10): 12, + (22, 11): 13, + (22, 12): 16, + (22, 13): 17, + (22, 14): 3, + (22, 15): 2, + (22, 16): 6, + (22, 17): 7, + (22, 18): 4, + (22, 19): 5, + (22, 20): 15, + (22, 21): 14, + (22, 22): 18, + (22, 23): 19, + (23, 0): 23, + (23, 1): 22, + (23, 2): 19, + (23, 3): 18, + (23, 4): 20, + (23, 5): 21, + (23, 6): 5, + (23, 7): 4, + (23, 8): 1, + (23, 9): 0, + (23, 10): 2, + (23, 11): 3, + (23, 12): 17, + (23, 13): 16, + (23, 14): 13, + (23, 15): 12, + (23, 16): 14, + (23, 17): 15, + (23, 18): 11, + (23, 19): 10, + (23, 20): 7, + (23, 21): 6, + (23, 22): 8, + (23, 23): 9, +} + +CLIFF_INVERSE_DATA = { + 0: 0, + 1: 1, + 2: 8, + 3: 5, + 4: 22, + 5: 3, + 6: 6, + 7: 19, + 8: 2, + 9: 23, + 10: 10, + 11: 15, + 12: 12, + 13: 13, + 14: 14, + 15: 11, + 16: 16, + 17: 21, + 18: 18, + 19: 7, + 20: 20, + 21: 17, + 22: 4, + 23: 9, +} \ No newline at end of file diff --git a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py new file mode 100644 index 0000000000..b85f91ed82 --- /dev/null +++ b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py @@ -0,0 +1,82 @@ +from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils +from qiskit.providers.aer import AerSimulator +from qiskit.compiler import transpile +from .cliff_data import CLIFF_COMPOSE_DATA, CLIFF_INVERSE_DATA + +from numpy.random import Generator, default_rng +import time + +def build_rb_circuits(lengths, circuits, rng): + all_clifford_circuits = [] + rand = rng.integers(0, 23) + # choose random clifford for first element + circ = circuits[rand].copy() + circ.barrier(0) + clifford_as_num = rand + + if lengths[0] == 1: + rb_circ = circ.copy() + inverse_num = CLIFF_INVERSE_DATA[rand] + inverse_circ = circuits[inverse_num] + rb_circ = rb_circ.compose(inverse_circ) + rb_circ.measure_all() + rb_circ.metadata = { + "experiment_type": "rb", + "xval": 2, + "group": "Clifford", + "physical_qubits": 0, + } + + prev_length = 2 + for length in lengths: + for i in range(prev_length, length+1): + rand = rng.integers(0, 23) + # choose random clifford + next_circ = circuits[rand] + circ = circ.compose(next_circ) + circ.barrier(0) + clifford_as_num = CLIFF_COMPOSE_DATA[clifford_as_num, rand] + if i==length: + rb_circ = circ.copy() + inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] + # append the inverse + rb_circ = rb_circ.compose(circuits[inverse_clifford_num]) + rb_circ.measure_all() + + rb_circ.metadata = { + "experiment_type": "rb", + "xval": length + 1, + "group": "Clifford", + "physical_qubits": 0, + } + + prev_length = i+1 + all_clifford_circuits.append(rb_circ) + + return all_clifford_circuits + +def generate_all_transpiled_clifford_circuits(): + utils = CliffordUtils() + circs = [] + for num in range(0, 24): + circ = utils.clifford_1_qubit_circuit(num=num) + circs.append(circ) + + backend = AerSimulator() + new_circs = [] + + for i, circ in enumerate(circs): + transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=['x','sx','rz']) + new_circ = transpiled_circ.copy() # do we need the copy? + new_circs.append(new_circ) + return new_circs + +def create_rb_transpiled_circuits(lengths, clifford_circuits, rng: Generator): + start = time.time() + final_rb_circuits = build_rb_circuits(lengths, clifford_circuits, rng) + end = time.time() + print("time for create_rb_transpiled_circuits = " + str(end-start)) + + return final_rb_circuits + + diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 0423666cb4..9056548ca9 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -19,6 +19,7 @@ import numpy as np from numpy.random import Generator, default_rng from numpy.random.bit_generator import BitGenerator, SeedSequence +import time from qiskit import QuantumCircuit, QiskitError from qiskit.circuit import Instruction @@ -29,11 +30,10 @@ from qiskit_experiments.framework.restless_mixin import RestlessMixin from .rb_analysis import RBAnalysis from .clifford_utils import CliffordUtils - +from .fast_rb import create_rb_transpiled_circuits, generate_all_transpiled_clifford_circuits LOG = logging.getLogger(__name__) - class StandardRB(BaseExperiment, RestlessMixin): """Standard randomized benchmarking experiment. @@ -64,7 +64,7 @@ def __init__( qubits: Sequence[int], lengths: Iterable[int], backend: Optional[Backend] = None, - num_samples: int = 3, + num_samples: int = 1, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, ): @@ -93,6 +93,10 @@ def __init__( # Set fixed options self._full_sampling = full_sampling self._clifford_utils = CliffordUtils() + start = time.time() + self._all_clifford_circuits = generate_all_transpiled_clifford_circuits() + end = time.time() + print("time for generate_all_transpiled_clifford_circuits="+str(end-start)) def _verify_parameters(self, lengths, num_samples): """Verify input correctness, raise QiskitError if needed""" @@ -133,10 +137,13 @@ def circuits(self) -> List[QuantumCircuit]: Returns: A list of :class:`QuantumCircuit`. """ + start = time.time() rng = default_rng(seed=self.experiment_options.seed) - circuits = [] for _ in range(self.experiment_options.num_samples): - circuits += self._sample_circuits(self.experiment_options.lengths, rng) + circuits = create_rb_transpiled_circuits(self.experiment_options.lengths, + self._all_clifford_circuits,rng) + end = time.time() + print("time for circuits = " + str(end - start)) return circuits def _sample_circuits(self, lengths: Iterable[int], rng: Generator) -> List[QuantumCircuit]: @@ -213,7 +220,8 @@ def _generate_circuit( def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" - transpiled = super()._transpiled_circuits() + print("fast rb") + transpiled = self.circuits() if self.analysis.options.get("gate_error_ratio", None) is None: # Gate errors are not computed, then counting ops is not necessary. diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 02cd291811..124b9a9442 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -16,6 +16,7 @@ import numpy as np from ddt import ddt, data, unpack +import time from qiskit.circuit import Delay, QuantumCircuit from qiskit.circuit.library import SXGate, CXGate, TGate, XGate from qiskit.exceptions import QiskitError @@ -68,9 +69,7 @@ def assertAllIdentity(self, circuits): for circ in circuits: num_qubits = circ.num_qubits iden = Clifford(np.eye(2 * num_qubits, dtype=bool)) - circ.remove_final_measurements() - self.assertEqual( Clifford(circ), iden, f"Circuit {circ.name} doesn't result in the identity matrix." ) @@ -82,17 +81,20 @@ class TestStandardRB(RBTestCase): def test_single_qubit(self): """Test single qubit RB.""" + start = time.time() exp = rb.StandardRB( qubits=(0,), lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, ) + exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) - self.assertAllIdentity(exp.circuits()) + #self.assertAllIdentity(exp.circuits()) expdata = exp.run() + self.assertExperimentDone(expdata) # Given we have gate number per Clifford n_gpc, we can compute EPC as @@ -103,9 +105,13 @@ def test_single_qubit(self): # from 0 to 2, i.e. arbitrary U gate can be decomposed into up to 2 SX with RZs. # We may want to expect the average number of SX is (0 + 1 + 2) / 3 = 1.0. epc = expdata.analysis_results("EPC") + print("epc = " + str(epc)) epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + print("epc expected = " + str(epc_expected)) + #self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + end = time.time() + print("time for test_single_qubit = " + str(end - start)) def test_two_qubit(self): """Test two qubit RB.""" From c83683156e2ea2fcba6e6fb981dccaf750ab16be Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 29 May 2022 17:01:50 +0300 Subject: [PATCH 02/39] Changed basis for transpilation to match the one in single_qubit_test. Added parameter to all calls to compose to use inplace=True. Removed redundant method generate_all_transpiled_clifford_circuits --- .../randomized_benchmarking/fast_rb.py | 26 +++++++++---------- .../randomized_benchmarking/rb_experiment.py | 10 ++++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py index b85f91ed82..c774410071 100644 --- a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py +++ b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py @@ -1,12 +1,13 @@ + from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils from qiskit.providers.aer import AerSimulator from qiskit.compiler import transpile from .cliff_data import CLIFF_COMPOSE_DATA, CLIFF_INVERSE_DATA -from numpy.random import Generator, default_rng import time def build_rb_circuits(lengths, circuits, rng): + start = time.time() all_clifford_circuits = [] rand = rng.integers(0, 23) # choose random clifford for first element @@ -18,7 +19,7 @@ def build_rb_circuits(lengths, circuits, rng): rb_circ = circ.copy() inverse_num = CLIFF_INVERSE_DATA[rand] inverse_circ = circuits[inverse_num] - rb_circ = rb_circ.compose(inverse_circ) + rb_circ.compose(inverse_circ, inplace=True) rb_circ.measure_all() rb_circ.metadata = { "experiment_type": "rb", @@ -33,14 +34,14 @@ def build_rb_circuits(lengths, circuits, rng): rand = rng.integers(0, 23) # choose random clifford next_circ = circuits[rand] - circ = circ.compose(next_circ) + circ.compose(next_circ, inplace=True) circ.barrier(0) - clifford_as_num = CLIFF_COMPOSE_DATA[clifford_as_num, rand] + clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] if i==length: rb_circ = circ.copy() inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] # append the inverse - rb_circ = rb_circ.compose(circuits[inverse_clifford_num]) + rb_circ.compose(circuits[inverse_clifford_num], inplace=True) rb_circ.measure_all() rb_circ.metadata = { @@ -52,7 +53,9 @@ def build_rb_circuits(lengths, circuits, rng): prev_length = i+1 all_clifford_circuits.append(rb_circ) - + #print(rb_circ) + end = time.time() + print(" time for build_rb_circuits = " + str(end-start)) return all_clifford_circuits def generate_all_transpiled_clifford_circuits(): @@ -66,17 +69,12 @@ def generate_all_transpiled_clifford_circuits(): new_circs = [] for i, circ in enumerate(circs): - transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=['x','sx','rz']) + transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=['sx','rz']) new_circ = transpiled_circ.copy() # do we need the copy? new_circs.append(new_circ) + #print(i) + #print(new_circ) return new_circs -def create_rb_transpiled_circuits(lengths, clifford_circuits, rng: Generator): - start = time.time() - final_rb_circuits = build_rb_circuits(lengths, clifford_circuits, rng) - end = time.time() - print("time for create_rb_transpiled_circuits = " + str(end-start)) - - return final_rb_circuits diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 9056548ca9..3159bcacf0 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -30,7 +30,7 @@ from qiskit_experiments.framework.restless_mixin import RestlessMixin from .rb_analysis import RBAnalysis from .clifford_utils import CliffordUtils -from .fast_rb import create_rb_transpiled_circuits, generate_all_transpiled_clifford_circuits +from .fast_rb import generate_all_transpiled_clifford_circuits, build_rb_circuits LOG = logging.getLogger(__name__) @@ -64,7 +64,7 @@ def __init__( qubits: Sequence[int], lengths: Iterable[int], backend: Optional[Backend] = None, - num_samples: int = 1, + num_samples: int = 10, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, ): @@ -140,10 +140,12 @@ def circuits(self) -> List[QuantumCircuit]: start = time.time() rng = default_rng(seed=self.experiment_options.seed) for _ in range(self.experiment_options.num_samples): - circuits = create_rb_transpiled_circuits(self.experiment_options.lengths, - self._all_clifford_circuits,rng) + circuits = build_rb_circuits(self.experiment_options.lengths, + self._all_clifford_circuits, rng) end = time.time() print("time for circuits = " + str(end - start)) + #for c in circuits: + #print(c) return circuits def _sample_circuits(self, lengths: Iterable[int], rng: Generator) -> List[QuantumCircuit]: From 86cad339e238779831b99cf467146838f1260706 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 31 May 2022 11:12:12 +0300 Subject: [PATCH 03/39] Modified the methods in create_clifford_map so that compose does not use front=True, because I assume front=False when creating the circuits --- .../randomized_benchmarking/cliff_data.py | 918 +++++++++--------- .../create_clifford_map.py | 42 + .../randomized_benchmarking/fast_rb.py | 3 +- 3 files changed, 502 insertions(+), 461 deletions(-) create mode 100644 qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py diff --git a/qiskit_experiments/library/randomized_benchmarking/cliff_data.py b/qiskit_experiments/library/randomized_benchmarking/cliff_data.py index fb6dd1f086..6042460fd3 100644 --- a/qiskit_experiments/library/randomized_benchmarking/cliff_data.py +++ b/qiskit_experiments/library/randomized_benchmarking/cliff_data.py @@ -25,557 +25,557 @@ (0, 23): 23, (1, 0): 1, (1, 1): 0, - (1, 2): 23, - (1, 3): 22, - (1, 4): 9, - (1, 5): 8, - (1, 6): 19, - (1, 7): 18, - (1, 8): 5, - (1, 9): 4, - (1, 10): 15, - (1, 11): 14, + (1, 2): 3, + (1, 3): 2, + (1, 4): 5, + (1, 5): 4, + (1, 6): 7, + (1, 7): 6, + (1, 8): 9, + (1, 9): 8, + (1, 10): 11, + (1, 11): 10, (1, 12): 13, (1, 13): 12, - (1, 14): 11, - (1, 15): 10, - (1, 16): 21, - (1, 17): 20, - (1, 18): 7, - (1, 19): 6, - (1, 20): 17, - (1, 21): 16, - (1, 22): 3, - (1, 23): 2, + (1, 14): 15, + (1, 15): 14, + (1, 16): 17, + (1, 17): 16, + (1, 18): 19, + (1, 19): 18, + (1, 20): 21, + (1, 21): 20, + (1, 22): 23, + (1, 23): 22, (2, 0): 2, - (2, 1): 3, + (2, 1): 23, (2, 2): 6, - (2, 3): 7, - (2, 4): 17, - (2, 5): 16, + (2, 3): 4, + (2, 4): 15, + (2, 5): 1, (2, 6): 8, - (2, 7): 9, + (2, 7): 17, (2, 8): 0, - (2, 9): 1, - (2, 10): 23, - (2, 11): 22, - (2, 12): 20, - (2, 13): 21, - (2, 14): 12, - (2, 15): 13, - (2, 16): 11, - (2, 17): 10, - (2, 18): 14, - (2, 19): 15, - (2, 20): 18, - (2, 21): 19, - (2, 22): 5, - (2, 23): 4, + (2, 9): 10, + (2, 10): 21, + (2, 11): 7, + (2, 12): 14, + (2, 13): 11, + (2, 14): 18, + (2, 15): 16, + (2, 16): 3, + (2, 17): 13, + (2, 18): 20, + (2, 19): 5, + (2, 20): 12, + (2, 21): 22, + (2, 22): 9, + (2, 23): 19, (3, 0): 3, - (3, 1): 2, - (3, 2): 4, + (3, 1): 22, + (3, 2): 7, (3, 3): 5, - (3, 4): 1, + (3, 4): 14, (3, 5): 0, - (3, 6): 15, - (3, 7): 14, - (3, 8): 16, - (3, 9): 17, - (3, 10): 13, - (3, 11): 12, - (3, 12): 21, - (3, 13): 20, - (3, 14): 22, - (3, 15): 23, - (3, 16): 19, - (3, 17): 18, - (3, 18): 9, - (3, 19): 8, - (3, 20): 10, - (3, 21): 11, - (3, 22): 7, - (3, 23): 6, + (3, 6): 9, + (3, 7): 16, + (3, 8): 1, + (3, 9): 11, + (3, 10): 20, + (3, 11): 6, + (3, 12): 15, + (3, 13): 10, + (3, 14): 19, + (3, 15): 17, + (3, 16): 2, + (3, 17): 12, + (3, 18): 21, + (3, 19): 4, + (3, 20): 13, + (3, 21): 23, + (3, 22): 8, + (3, 23): 18, (4, 0): 4, - (4, 1): 5, - (4, 2): 15, - (4, 3): 14, + (4, 1): 9, + (4, 2): 17, + (4, 3): 1, (4, 4): 18, - (4, 5): 19, - (4, 6): 16, - (4, 7): 17, - (4, 8): 3, - (4, 9): 2, - (4, 10): 6, - (4, 11): 7, - (4, 12): 10, - (4, 13): 11, - (4, 14): 21, - (4, 15): 20, - (4, 16): 12, - (4, 17): 13, + (4, 5): 2, + (4, 6): 10, + (4, 7): 3, + (4, 8): 23, + (4, 9): 7, + (4, 10): 12, + (4, 11): 8, + (4, 12): 16, + (4, 13): 21, + (4, 14): 5, + (4, 15): 13, + (4, 16): 6, + (4, 17): 14, (4, 18): 22, - (4, 19): 23, - (4, 20): 9, - (4, 21): 8, + (4, 19): 15, + (4, 20): 11, + (4, 21): 19, (4, 22): 0, - (4, 23): 1, + (4, 23): 20, (5, 0): 5, - (5, 1): 4, - (5, 2): 1, + (5, 1): 8, + (5, 2): 16, (5, 3): 0, - (5, 4): 2, + (5, 4): 19, (5, 5): 3, - (5, 6): 23, - (5, 7): 22, - (5, 8): 19, - (5, 9): 18, - (5, 10): 20, - (5, 11): 21, - (5, 12): 11, - (5, 13): 10, - (5, 14): 7, - (5, 15): 6, - (5, 16): 8, - (5, 17): 9, - (5, 18): 17, - (5, 19): 16, - (5, 20): 13, - (5, 21): 12, - (5, 22): 14, - (5, 23): 15, + (5, 6): 11, + (5, 7): 2, + (5, 8): 22, + (5, 9): 6, + (5, 10): 13, + (5, 11): 9, + (5, 12): 17, + (5, 13): 20, + (5, 14): 4, + (5, 15): 12, + (5, 16): 7, + (5, 17): 15, + (5, 18): 23, + (5, 19): 14, + (5, 20): 10, + (5, 21): 18, + (5, 22): 1, + (5, 23): 21, (6, 0): 6, - (6, 1): 7, + (6, 1): 19, (6, 2): 8, - (6, 3): 9, - (6, 4): 10, - (6, 5): 11, + (6, 3): 15, + (6, 4): 16, + (6, 5): 23, (6, 6): 0, - (6, 7): 1, + (6, 7): 13, (6, 8): 2, - (6, 9): 3, - (6, 10): 4, - (6, 11): 5, + (6, 9): 21, + (6, 10): 22, + (6, 11): 17, (6, 12): 18, - (6, 13): 19, + (6, 13): 7, (6, 14): 20, - (6, 15): 21, - (6, 16): 22, - (6, 17): 23, + (6, 15): 3, + (6, 16): 4, + (6, 17): 11, (6, 18): 12, - (6, 19): 13, + (6, 19): 1, (6, 20): 14, - (6, 21): 15, - (6, 22): 16, - (6, 23): 17, + (6, 21): 9, + (6, 22): 10, + (6, 23): 5, (7, 0): 7, - (7, 1): 6, - (7, 2): 17, - (7, 3): 16, - (7, 4): 3, - (7, 5): 2, - (7, 6): 13, + (7, 1): 18, + (7, 2): 9, + (7, 3): 14, + (7, 4): 17, + (7, 5): 22, + (7, 6): 1, (7, 7): 12, - (7, 8): 11, - (7, 9): 10, - (7, 10): 21, - (7, 11): 20, + (7, 8): 3, + (7, 9): 20, + (7, 10): 23, + (7, 11): 16, (7, 12): 19, - (7, 13): 18, - (7, 14): 5, - (7, 15): 4, - (7, 16): 15, - (7, 17): 14, - (7, 18): 1, + (7, 13): 6, + (7, 14): 21, + (7, 15): 2, + (7, 16): 5, + (7, 17): 10, + (7, 18): 13, (7, 19): 0, - (7, 20): 23, - (7, 21): 22, - (7, 22): 9, - (7, 23): 8, + (7, 20): 15, + (7, 21): 8, + (7, 22): 11, + (7, 23): 4, (8, 0): 8, - (8, 1): 9, + (8, 1): 5, (8, 2): 0, - (8, 3): 1, - (8, 4): 23, - (8, 5): 22, + (8, 3): 16, + (8, 4): 3, + (8, 5): 19, (8, 6): 2, - (8, 7): 3, + (8, 7): 11, (8, 8): 6, - (8, 9): 7, - (8, 10): 17, - (8, 11): 16, - (8, 12): 14, - (8, 13): 15, - (8, 14): 18, - (8, 15): 19, - (8, 16): 5, - (8, 17): 4, - (8, 18): 20, - (8, 19): 21, - (8, 20): 12, - (8, 21): 13, - (8, 22): 11, - (8, 23): 10, + (8, 9): 22, + (8, 10): 9, + (8, 11): 13, + (8, 12): 20, + (8, 13): 17, + (8, 14): 12, + (8, 15): 4, + (8, 16): 15, + (8, 17): 7, + (8, 18): 14, + (8, 19): 23, + (8, 20): 18, + (8, 21): 10, + (8, 22): 21, + (8, 23): 1, (9, 0): 9, - (9, 1): 8, - (9, 2): 10, - (9, 3): 11, - (9, 4): 7, - (9, 5): 6, - (9, 6): 21, - (9, 7): 20, - (9, 8): 22, + (9, 1): 4, + (9, 2): 1, + (9, 3): 17, + (9, 4): 2, + (9, 5): 18, + (9, 6): 3, + (9, 7): 10, + (9, 8): 7, (9, 9): 23, - (9, 10): 19, - (9, 11): 18, - (9, 12): 15, - (9, 13): 14, - (9, 14): 16, - (9, 15): 17, - (9, 16): 13, - (9, 17): 12, - (9, 18): 3, - (9, 19): 2, - (9, 20): 4, - (9, 21): 5, - (9, 22): 1, + (9, 10): 8, + (9, 11): 12, + (9, 12): 21, + (9, 13): 16, + (9, 14): 13, + (9, 15): 5, + (9, 16): 14, + (9, 17): 6, + (9, 18): 15, + (9, 19): 22, + (9, 20): 19, + (9, 21): 11, + (9, 22): 20, (9, 23): 0, (10, 0): 10, - (10, 1): 11, - (10, 2): 21, - (10, 3): 20, - (10, 4): 12, - (10, 5): 13, - (10, 6): 22, - (10, 7): 23, - (10, 8): 9, - (10, 9): 8, + (10, 1): 15, + (10, 2): 23, + (10, 3): 13, + (10, 4): 6, + (10, 5): 20, + (10, 6): 4, + (10, 7): 21, + (10, 8): 17, + (10, 9): 19, (10, 10): 0, - (10, 11): 1, - (10, 12): 4, - (10, 13): 5, - (10, 14): 15, - (10, 15): 14, + (10, 11): 14, + (10, 12): 22, + (10, 13): 3, + (10, 14): 11, + (10, 15): 1, (10, 16): 18, - (10, 17): 19, + (10, 17): 8, (10, 18): 16, - (10, 19): 17, - (10, 20): 3, - (10, 21): 2, - (10, 22): 6, - (10, 23): 7, + (10, 19): 9, + (10, 20): 5, + (10, 21): 7, + (10, 22): 12, + (10, 23): 2, (11, 0): 11, - (11, 1): 10, - (11, 2): 7, - (11, 3): 6, - (11, 4): 8, - (11, 5): 9, - (11, 6): 17, - (11, 7): 16, - (11, 8): 13, - (11, 9): 12, - (11, 10): 14, + (11, 1): 14, + (11, 2): 22, + (11, 3): 12, + (11, 4): 7, + (11, 5): 21, + (11, 6): 5, + (11, 7): 20, + (11, 8): 16, + (11, 9): 18, + (11, 10): 1, (11, 11): 15, - (11, 12): 5, - (11, 13): 4, - (11, 14): 1, + (11, 12): 23, + (11, 13): 2, + (11, 14): 10, (11, 15): 0, - (11, 16): 2, - (11, 17): 3, - (11, 18): 23, - (11, 19): 22, - (11, 20): 19, - (11, 21): 18, - (11, 22): 20, - (11, 23): 21, + (11, 16): 19, + (11, 17): 9, + (11, 18): 17, + (11, 19): 8, + (11, 20): 4, + (11, 21): 6, + (11, 22): 13, + (11, 23): 3, (12, 0): 12, (12, 1): 13, - (12, 2): 14, - (12, 3): 15, - (12, 4): 16, - (12, 5): 17, + (12, 2): 20, + (12, 3): 21, + (12, 4): 10, + (12, 5): 11, (12, 6): 18, (12, 7): 19, - (12, 8): 20, - (12, 9): 21, - (12, 10): 22, - (12, 11): 23, + (12, 8): 14, + (12, 9): 15, + (12, 10): 4, + (12, 11): 5, (12, 12): 0, (12, 13): 1, - (12, 14): 2, - (12, 15): 3, - (12, 16): 4, - (12, 17): 5, + (12, 14): 8, + (12, 15): 9, + (12, 16): 22, + (12, 17): 23, (12, 18): 6, (12, 19): 7, - (12, 20): 8, - (12, 21): 9, - (12, 22): 10, - (12, 23): 11, + (12, 20): 2, + (12, 21): 3, + (12, 22): 16, + (12, 23): 17, (13, 0): 13, (13, 1): 12, - (13, 2): 11, - (13, 3): 10, - (13, 4): 21, - (13, 5): 20, - (13, 6): 7, - (13, 7): 6, - (13, 8): 17, - (13, 9): 16, - (13, 10): 3, - (13, 11): 2, + (13, 2): 21, + (13, 3): 20, + (13, 4): 11, + (13, 5): 10, + (13, 6): 19, + (13, 7): 18, + (13, 8): 15, + (13, 9): 14, + (13, 10): 5, + (13, 11): 4, (13, 12): 1, (13, 13): 0, - (13, 14): 23, - (13, 15): 22, - (13, 16): 9, - (13, 17): 8, - (13, 18): 19, - (13, 19): 18, - (13, 20): 5, - (13, 21): 4, - (13, 22): 15, - (13, 23): 14, + (13, 14): 9, + (13, 15): 8, + (13, 16): 23, + (13, 17): 22, + (13, 18): 7, + (13, 19): 6, + (13, 20): 3, + (13, 21): 2, + (13, 22): 17, + (13, 23): 16, (14, 0): 14, - (14, 1): 15, - (14, 2): 18, - (14, 3): 19, - (14, 4): 5, - (14, 5): 4, + (14, 1): 11, + (14, 2): 12, + (14, 3): 22, + (14, 4): 21, + (14, 5): 7, (14, 6): 20, - (14, 7): 21, - (14, 8): 12, - (14, 9): 13, - (14, 10): 11, - (14, 11): 10, - (14, 12): 8, - (14, 13): 9, + (14, 7): 5, + (14, 8): 18, + (14, 9): 16, + (14, 10): 15, + (14, 11): 1, + (14, 12): 2, + (14, 13): 23, (14, 14): 0, - (14, 15): 1, - (14, 16): 23, - (14, 17): 22, - (14, 18): 2, - (14, 19): 3, + (14, 15): 10, + (14, 16): 9, + (14, 17): 19, + (14, 18): 8, + (14, 19): 17, (14, 20): 6, - (14, 21): 7, - (14, 22): 17, - (14, 23): 16, + (14, 21): 4, + (14, 22): 3, + (14, 23): 13, (15, 0): 15, - (15, 1): 14, - (15, 2): 16, - (15, 3): 17, - (15, 4): 13, - (15, 5): 12, - (15, 6): 3, - (15, 7): 2, - (15, 8): 4, - (15, 9): 5, - (15, 10): 1, + (15, 1): 10, + (15, 2): 13, + (15, 3): 23, + (15, 4): 20, + (15, 5): 6, + (15, 6): 21, + (15, 7): 4, + (15, 8): 19, + (15, 9): 17, + (15, 10): 14, (15, 11): 0, - (15, 12): 9, - (15, 13): 8, - (15, 14): 10, + (15, 12): 3, + (15, 13): 22, + (15, 14): 1, (15, 15): 11, - (15, 16): 7, - (15, 17): 6, - (15, 18): 21, - (15, 19): 20, - (15, 20): 22, - (15, 21): 23, - (15, 22): 19, - (15, 23): 18, + (15, 16): 8, + (15, 17): 18, + (15, 18): 9, + (15, 19): 16, + (15, 20): 7, + (15, 21): 5, + (15, 22): 2, + (15, 23): 12, (16, 0): 16, - (16, 1): 17, - (16, 2): 3, - (16, 3): 2, - (16, 4): 6, - (16, 5): 7, - (16, 6): 4, - (16, 7): 5, - (16, 8): 15, - (16, 9): 14, + (16, 1): 21, + (16, 2): 11, + (16, 3): 19, + (16, 4): 12, + (16, 5): 8, + (16, 6): 22, + (16, 7): 15, + (16, 8): 5, + (16, 9): 13, (16, 10): 18, - (16, 11): 19, - (16, 12): 22, - (16, 13): 23, - (16, 14): 9, - (16, 15): 8, + (16, 11): 2, + (16, 12): 4, + (16, 13): 9, + (16, 14): 23, + (16, 15): 7, (16, 16): 0, - (16, 17): 1, + (16, 17): 20, (16, 18): 10, - (16, 19): 11, - (16, 20): 21, - (16, 21): 20, - (16, 22): 12, - (16, 23): 13, + (16, 19): 3, + (16, 20): 17, + (16, 21): 1, + (16, 22): 6, + (16, 23): 14, (17, 0): 17, - (17, 1): 16, - (17, 2): 13, - (17, 3): 12, - (17, 4): 14, - (17, 5): 15, - (17, 6): 11, - (17, 7): 10, - (17, 8): 7, - (17, 9): 6, - (17, 10): 8, - (17, 11): 9, - (17, 12): 23, - (17, 13): 22, - (17, 14): 19, - (17, 15): 18, - (17, 16): 20, + (17, 1): 20, + (17, 2): 10, + (17, 3): 18, + (17, 4): 13, + (17, 5): 9, + (17, 6): 23, + (17, 7): 14, + (17, 8): 4, + (17, 9): 12, + (17, 10): 19, + (17, 11): 3, + (17, 12): 5, + (17, 13): 8, + (17, 14): 22, + (17, 15): 6, + (17, 16): 1, (17, 17): 21, - (17, 18): 5, - (17, 19): 4, - (17, 20): 1, + (17, 18): 11, + (17, 19): 2, + (17, 20): 16, (17, 21): 0, - (17, 22): 2, - (17, 23): 3, + (17, 22): 7, + (17, 23): 15, (18, 0): 18, - (18, 1): 19, - (18, 2): 20, - (18, 3): 21, + (18, 1): 7, + (18, 2): 14, + (18, 3): 9, (18, 4): 22, - (18, 5): 23, + (18, 5): 17, (18, 6): 12, - (18, 7): 13, - (18, 8): 14, - (18, 9): 15, + (18, 7): 1, + (18, 8): 20, + (18, 9): 3, (18, 10): 16, - (18, 11): 17, + (18, 11): 23, (18, 12): 6, - (18, 13): 7, - (18, 14): 8, - (18, 15): 9, + (18, 13): 19, + (18, 14): 2, + (18, 15): 21, (18, 16): 10, - (18, 17): 11, + (18, 17): 5, (18, 18): 0, - (18, 19): 1, - (18, 20): 2, - (18, 21): 3, + (18, 19): 13, + (18, 20): 8, + (18, 21): 15, (18, 22): 4, - (18, 23): 5, + (18, 23): 11, (19, 0): 19, - (19, 1): 18, - (19, 2): 5, - (19, 3): 4, - (19, 4): 15, - (19, 5): 14, - (19, 6): 1, + (19, 1): 6, + (19, 2): 15, + (19, 3): 8, + (19, 4): 23, + (19, 5): 16, + (19, 6): 13, (19, 7): 0, - (19, 8): 23, - (19, 9): 22, - (19, 10): 9, - (19, 11): 8, + (19, 8): 21, + (19, 9): 2, + (19, 10): 17, + (19, 11): 22, (19, 12): 7, - (19, 13): 6, - (19, 14): 17, - (19, 15): 16, - (19, 16): 3, - (19, 17): 2, - (19, 18): 13, + (19, 13): 18, + (19, 14): 3, + (19, 15): 20, + (19, 16): 11, + (19, 17): 4, + (19, 18): 1, (19, 19): 12, - (19, 20): 11, - (19, 21): 10, - (19, 22): 21, - (19, 23): 20, + (19, 20): 9, + (19, 21): 14, + (19, 22): 5, + (19, 23): 10, (20, 0): 20, - (20, 1): 21, - (20, 2): 12, - (20, 3): 13, - (20, 4): 11, - (20, 5): 10, + (20, 1): 17, + (20, 2): 18, + (20, 3): 10, + (20, 4): 9, + (20, 5): 13, (20, 6): 14, - (20, 7): 15, - (20, 8): 18, - (20, 9): 19, - (20, 10): 5, - (20, 11): 4, - (20, 12): 2, - (20, 13): 3, + (20, 7): 23, + (20, 8): 12, + (20, 9): 4, + (20, 10): 3, + (20, 11): 19, + (20, 12): 8, + (20, 13): 5, (20, 14): 6, - (20, 15): 7, - (20, 16): 17, - (20, 17): 16, - (20, 18): 8, - (20, 19): 9, + (20, 15): 22, + (20, 16): 21, + (20, 17): 1, + (20, 18): 2, + (20, 19): 11, (20, 20): 0, - (20, 21): 1, - (20, 22): 23, - (20, 23): 22, + (20, 21): 16, + (20, 22): 15, + (20, 23): 7, (21, 0): 21, - (21, 1): 20, - (21, 2): 22, - (21, 3): 23, - (21, 4): 19, - (21, 5): 18, - (21, 6): 9, - (21, 7): 8, - (21, 8): 10, - (21, 9): 11, - (21, 10): 7, - (21, 11): 6, - (21, 12): 3, - (21, 13): 2, - (21, 14): 4, - (21, 15): 5, - (21, 16): 1, + (21, 1): 16, + (21, 2): 19, + (21, 3): 11, + (21, 4): 8, + (21, 5): 12, + (21, 6): 15, + (21, 7): 22, + (21, 8): 13, + (21, 9): 5, + (21, 10): 2, + (21, 11): 18, + (21, 12): 9, + (21, 13): 4, + (21, 14): 7, + (21, 15): 23, + (21, 16): 20, (21, 17): 0, - (21, 18): 15, - (21, 19): 14, - (21, 20): 16, + (21, 18): 3, + (21, 19): 10, + (21, 20): 1, (21, 21): 17, - (21, 22): 13, - (21, 23): 12, + (21, 22): 14, + (21, 23): 6, (22, 0): 22, - (22, 1): 23, - (22, 2): 9, - (22, 3): 8, + (22, 1): 3, + (22, 2): 5, + (22, 3): 7, (22, 4): 0, - (22, 5): 1, - (22, 6): 10, - (22, 7): 11, - (22, 8): 21, - (22, 9): 20, - (22, 10): 12, - (22, 11): 13, - (22, 12): 16, - (22, 13): 17, - (22, 14): 3, - (22, 15): 2, - (22, 16): 6, - (22, 17): 7, + (22, 5): 14, + (22, 6): 16, + (22, 7): 9, + (22, 8): 11, + (22, 9): 1, + (22, 10): 6, + (22, 11): 20, + (22, 12): 10, + (22, 13): 15, + (22, 14): 17, + (22, 15): 19, + (22, 16): 12, + (22, 17): 2, (22, 18): 4, - (22, 19): 5, - (22, 20): 15, - (22, 21): 14, + (22, 19): 21, + (22, 20): 23, + (22, 21): 13, (22, 22): 18, - (22, 23): 19, + (22, 23): 8, (23, 0): 23, - (23, 1): 22, - (23, 2): 19, - (23, 3): 18, - (23, 4): 20, - (23, 5): 21, - (23, 6): 5, - (23, 7): 4, - (23, 8): 1, + (23, 1): 2, + (23, 2): 4, + (23, 3): 6, + (23, 4): 1, + (23, 5): 15, + (23, 6): 17, + (23, 7): 8, + (23, 8): 10, (23, 9): 0, - (23, 10): 2, - (23, 11): 3, - (23, 12): 17, - (23, 13): 16, - (23, 14): 13, - (23, 15): 12, - (23, 16): 14, - (23, 17): 15, - (23, 18): 11, - (23, 19): 10, - (23, 20): 7, - (23, 21): 6, - (23, 22): 8, - (23, 23): 9, -} + (23, 10): 7, + (23, 11): 21, + (23, 12): 11, + (23, 13): 14, + (23, 14): 16, + (23, 15): 18, + (23, 16): 13, + (23, 17): 3, + (23, 18): 5, + (23, 19): 20, + (23, 20): 22, + (23, 21): 12, + (23, 22): 19, + (23, 23): 9 + } CLIFF_INVERSE_DATA = { 0: 0, @@ -602,4 +602,4 @@ 21: 17, 22: 4, 23: 9, -} \ No newline at end of file + } \ No newline at end of file diff --git a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py new file mode 100644 index 0000000000..d24fd1c972 --- /dev/null +++ b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py @@ -0,0 +1,42 @@ +# Written by Sasha +from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils + +def create_compose_map(): + utils = CliffordUtils() + + num_to_cliff = {} + cliff_to_num = {} + + for i in range(24): + cliff = utils.clifford_1_qubit(i) + num_to_cliff[i] = cliff + cliff_to_num[cliff.__repr__()] = i + + prods = {} + + for i in range(24): + cliff1 = num_to_cliff[i] + for j in range(24): + cliff2 = num_to_cliff[j] + cliff = cliff1.compose(cliff2) + prods[i, j] = cliff_to_num[cliff.__repr__()] + + invs = {} + for i in range(24): + cliff1 = num_to_cliff[i] + cliff = cliff1.adjoint() + invs[i] = cliff_to_num[cliff.__repr__()] + + print("CLIFF_COMPOSE_DATA = {") + for i in prods: + print(f" {i}: {prods[i]},") + #print(prods) + print(" }") + + print("CLIFF_INVERSE_DATA = {") + #print(invs) + for i in invs: + print(f" {i}: {invs[i]},") + print(" }") + +create_compose_map() diff --git a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py index c774410071..ec610e7408 100644 --- a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py +++ b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py @@ -70,8 +70,7 @@ def generate_all_transpiled_clifford_circuits(): for i, circ in enumerate(circs): transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=['sx','rz']) - new_circ = transpiled_circ.copy() # do we need the copy? - new_circs.append(new_circ) + new_circs.append(transpiled_circ) #print(i) #print(new_circ) return new_circs From 9a873dc17190f177823313df0a684b69a1e2750c Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 31 May 2022 14:46:57 +0300 Subject: [PATCH 04/39] Changed generation of generation of random numbers to be identical to the previous version of rb_experiment. --- .../library/randomized_benchmarking/cliff_data.py | 4 ++-- .../library/randomized_benchmarking/fast_rb.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/cliff_data.py b/qiskit_experiments/library/randomized_benchmarking/cliff_data.py index 6042460fd3..3a59f4958f 100644 --- a/qiskit_experiments/library/randomized_benchmarking/cliff_data.py +++ b/qiskit_experiments/library/randomized_benchmarking/cliff_data.py @@ -574,7 +574,7 @@ (23, 20): 22, (23, 21): 12, (23, 22): 19, - (23, 23): 9 + (23, 23): 9, } CLIFF_INVERSE_DATA = { @@ -602,4 +602,4 @@ 21: 17, 22: 4, 23: 9, - } \ No newline at end of file + } diff --git a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py index ec610e7408..00dbdf6e68 100644 --- a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py +++ b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py @@ -9,7 +9,9 @@ def build_rb_circuits(lengths, circuits, rng): start = time.time() all_clifford_circuits = [] - rand = rng.integers(0, 23) + random_samples = rng.integers(24, size=lengths[-1]) + rand = random_samples[0] + index = 1 # choose random clifford for first element circ = circuits[rand].copy() circ.barrier(0) @@ -31,9 +33,10 @@ def build_rb_circuits(lengths, circuits, rng): prev_length = 2 for length in lengths: for i in range(prev_length, length+1): - rand = rng.integers(0, 23) + rand = random_samples[index] # choose random clifford next_circ = circuits[rand] + index += 1 circ.compose(next_circ, inplace=True) circ.barrier(0) clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] From 76ff3667375032e645df3ae381337e98b4a2e01f Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 1 Jun 2022 12:15:32 +0300 Subject: [PATCH 05/39] Test to run on device --- rb_on_device.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 rb_on_device.py diff --git a/rb_on_device.py b/rb_on_device.py new file mode 100644 index 0000000000..b387872531 --- /dev/null +++ b/rb_on_device.py @@ -0,0 +1,87 @@ +# This code is part of Qiskit. +# (C) Copyright IBM 2022. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Test for randomized benchmarking experiments.""" + +from test.base import QiskitExperimentsTestCase +import numpy as np +from ddt import ddt, data, unpack +import time + +from qiskit import IBMQ + +from qiskit_experiments.library import randomized_benchmarking as rb + +class RBTestCase(QiskitExperimentsTestCase): + """Base test case for randomized benchmarking defining a common noise model.""" + + def __init__(self): + """Set up the tests.""" + + # basis gates + self.basis_gates = ["sx", "rz"] + + # Need level1 for consecutive gate cancellation for reference EPC value calculation + self.transpiler_options = { + "basis_gates": self.basis_gates, + "optimization_level": 1, + } + IBMQ.load_account() + provider = IBMQ.get_provider(hub="ibm-q-internal", group="deployed", project="default") + self.backend = provider.backend.ibmq_armonk + +@ddt +class TestStandardRB(RBTestCase): + """Test for standard RB.""" + + def test_single_qubit(self, lengths): + """Test single qubit RB.""" + exp = rb.StandardRB( + qubits=(0,), + lengths = lengths, + seed=123, + backend=self.backend, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**self.transpiler_options) + #assertAllIdentity(exp.circuits()) + expdata = exp.run() + epc = expdata.analysis_results("EPC") + epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.15 * epc_expected) + + def time_rb_single_qubit(self): + maxcliff = 4000 + nCliffs = np.logspace(np.log10(1.5), np.log10(maxcliff), int(np.log10(maxcliff) * 4), dtype=int) + lengths_list = [list(range(1, 300, 30)), + list(range(1, 1002, 100)), + nCliffs] + + iters = 3 + result_times = {} + for lengths in lengths_list: + sum_time = 0.0 + for iter in range(iters): + start = time.time() + self.test_single_qubit(lengths=lengths) + end = time.time() + sum_time += end-start + sum_time /= iters + result_times[lengths[-1]] = sum_time + print("lengths = " + str(lengths)) + print(result_times) + + + +# For testing the methods standalone +test1 = TestStandardRB() +test1.time_rb_single_qubit() + From 274432a788caafe87d0ad1030f56a09ef5ffce95 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Thu, 9 Jun 2022 13:05:36 +0300 Subject: [PATCH 06/39] added methods for new algorithm to generate rb circuits: build_rb_circuits, generate_1q_transpiled_clifford_circuits --- .../{cliff_data.py => clifford_data.py} | 0 .../randomized_benchmarking/clifford_utils.py | 19 ++++- .../randomized_benchmarking/rb_experiment.py | 73 +++++++++++++++++-- 3 files changed, 85 insertions(+), 7 deletions(-) rename qiskit_experiments/library/randomized_benchmarking/{cliff_data.py => clifford_data.py} (100%) diff --git a/qiskit_experiments/library/randomized_benchmarking/cliff_data.py b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py similarity index 100% rename from qiskit_experiments/library/randomized_benchmarking/cliff_data.py rename to qiskit_experiments/library/randomized_benchmarking/clifford_data.py diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index a7756ec126..0d310fc60c 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -13,13 +13,15 @@ Utilities for using the Clifford group in randomized benchmarking """ -from typing import Optional, Union +from typing import Optional, Union, List from functools import lru_cache from numpy.random import Generator, default_rng from qiskit import QuantumCircuit, QuantumRegister from qiskit.circuit import Gate from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate from qiskit.quantum_info import Clifford, random_clifford +from qiskit.compiler import transpile +from qiskit.providers.aer import AerSimulator class VGate(Gate): @@ -219,3 +221,18 @@ def _unpack_num_multi_sigs(self, num, sigs): return [i] + self._unpack_num(num, sig) num -= sig_size return None + + def generate_1q_transpiled_clifford_circuits(basis_gates : List[str]): + utils = CliffordUtils() + circs = [] + for num in range(0, 24): + circ = utils.clifford_1_qubit_circuit(num=num) + circs.append(circ) + + backend = AerSimulator() + transpiled_circs = [] + + for i, circ in enumerate(circs): + transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=basis_gates) + transpiled_circs.append(transpiled_circ) + return transpiled_circs diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 3159bcacf0..a00fc8fdb8 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -15,6 +15,7 @@ import logging from collections import defaultdict from typing import Union, Iterable, Optional, List, Sequence +import copy import numpy as np from numpy.random import Generator, default_rng @@ -30,7 +31,7 @@ from qiskit_experiments.framework.restless_mixin import RestlessMixin from .rb_analysis import RBAnalysis from .clifford_utils import CliffordUtils -from .fast_rb import generate_all_transpiled_clifford_circuits, build_rb_circuits +from .clifford_data import CLIFF_COMPOSE_DATA, CLIFF_INVERSE_DATA LOG = logging.getLogger(__name__) @@ -94,7 +95,8 @@ def __init__( self._full_sampling = full_sampling self._clifford_utils = CliffordUtils() start = time.time() - self._all_clifford_circuits = generate_all_transpiled_clifford_circuits() + basis_gates = ["rz", "sx"] + self._all_rb_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) end = time.time() print("time for generate_all_transpiled_clifford_circuits="+str(end-start)) @@ -131,6 +133,62 @@ def _default_experiment_options(cls) -> Options: return options + def build_rb_circuits(self, lengths, circuits, rng): + start = time.time() + all_rb_circuits = [] + for length in lengths if self._full_sampling else [lengths[-1]]: + random_samples = rng.integers(24, size=length) + rand = random_samples[0] + index = 1 + # choose random clifford for first element + circ = circuits[rand].copy() + circ.barrier(0) + clifford_as_num = rand + + if lengths[0] == 1: + rb_circ = circ.copy() + inverse_num = CLIFF_INVERSE_DATA[rand] + inverse_circ = circuits[inverse_num] + rb_circ.compose(inverse_circ, inplace=True) + rb_circ.measure_all() + rb_circ.metadata = { + "experiment_type": "rb", + "xval": 2, + "group": "Clifford", + "physical_qubits": 0, + } + + prev_length = 2 + for length in lengths: + for i in range(prev_length, length + 1): + rand = random_samples[index] + # choose random clifford + next_circ = circuits[rand] + index += 1 + circ.compose(next_circ, inplace=True) + circ.barrier(0) + clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] + if i == length: + rb_circ = circ.copy() + inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] + # append the inverse + rb_circ.compose(circuits[inverse_clifford_num], inplace=True) + rb_circ.measure_all() + + rb_circ.metadata = { + "experiment_type": "rb", + "xval": length + 1, + "group": "Clifford", + "physical_qubits": 0, + } + + prev_length = i + 1 + all_rb_circuits.append(rb_circ) + # print(rb_circ) + end = time.time() + print(" time for build_rb_circuits = " + str(end - start)) + return all_rb_circuits + def circuits(self) -> List[QuantumCircuit]: """Return a list of RB circuits. @@ -140,8 +198,11 @@ def circuits(self) -> List[QuantumCircuit]: start = time.time() rng = default_rng(seed=self.experiment_options.seed) for _ in range(self.experiment_options.num_samples): - circuits = build_rb_circuits(self.experiment_options.lengths, - self._all_clifford_circuits, rng) + if self.num_qubits == 1: + circuits = self.build_rb_circuits(self.experiment_options.lengths, + self._all_rb_circuits, rng) + else: + circuits += self._sample_circuits(self.experiment_options.lengths, rng) end = time.time() print("time for circuits = " + str(end - start)) #for c in circuits: @@ -222,8 +283,7 @@ def _generate_circuit( def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" - print("fast rb") - transpiled = self.circuits() + transpiled = super()._transpiled_circuits() if self.analysis.options.get("gate_error_ratio", None) is None: # Gate errors are not computed, then counting ops is not necessary. @@ -257,3 +317,4 @@ def _metadata(self): metadata[run_opt] = getattr(self.run_options, run_opt) return metadata + From 890d890eb34ad559932ea4f7b081fbc3ae73d7a0 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 12 Jun 2022 17:51:48 +0300 Subject: [PATCH 07/39] Added the method _layout_for_rb_single_qubit and added test_full_sampling_single_qubit --- .../randomized_benchmarking/rb_experiment.py | 116 ++++++++++++++---- .../test_randomized_benchmarking.py | 27 +++- 2 files changed, 119 insertions(+), 24 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index a00fc8fdb8..b85866c9db 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -15,15 +15,15 @@ import logging from collections import defaultdict from typing import Union, Iterable, Optional, List, Sequence -import copy import numpy as np from numpy.random import Generator, default_rng from numpy.random.bit_generator import BitGenerator, SeedSequence import time -from qiskit import QuantumCircuit, QiskitError +from qiskit import QuantumCircuit, QuantumRegister, QiskitError from qiskit.circuit import Instruction +from qiskit.circuit.quantumregister import Qubit from qiskit.quantum_info import Clifford from qiskit.providers.backend import Backend @@ -65,7 +65,7 @@ def __init__( qubits: Sequence[int], lengths: Iterable[int], backend: Optional[Backend] = None, - num_samples: int = 10, + num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, ): @@ -96,7 +96,7 @@ def __init__( self._clifford_utils = CliffordUtils() start = time.time() basis_gates = ["rz", "sx"] - self._all_rb_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) + self._transpiled_cliff_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) end = time.time() print("time for generate_all_transpiled_clifford_circuits="+str(end-start)) @@ -133,22 +133,74 @@ def _default_experiment_options(cls) -> Options: return options - def build_rb_circuits(self, lengths, circuits, rng): - start = time.time() + def _build_rb_circuits_full_sampling(self, lengths, rng): all_rb_circuits = [] - for length in lengths if self._full_sampling else [lengths[-1]]: + + for length in lengths: + rb_circ = QuantumCircuit(1) random_samples = rng.integers(24, size=length) + print(random_samples) + + clifford_as_num = 0 + for i in range(length): + # choose random clifford + rand = random_samples[i] + next_circ = self._transpiled_cliff_circuits[rand].copy() + + rb_circ.compose(next_circ, inplace=True) + rb_circ.barrier(0) + clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] + + inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] + # append the inverse + rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) + rb_circ.measure_all() + + rb_circ.metadata = { + "experiment_type": "rb", + "xval": length + 1, + "group": "Clifford", + "physical_qubits": 0, + } + all_rb_circuits.append(rb_circ) + return all_rb_circuits + + def build_rb_circuits(self, lengths, rng): + """ + build_rb_circuits + Args: + qubits: list of physical qubits for the experiment. + lengths: A list of RB sequence lengths. We create random circuits + where the number of cliffords in each is in lengths. + backend: The backend to run the experiment on. + """ + if self._full_sampling: + return self._build_rb_circuits_full_sampling(lengths, rng) + all_rb_circuits = [] + # length = lengths[-1] if self._full_sampling else sum(lengths) + random_samples = rng.integers(24, size=lengths[-1]) rand = random_samples[0] - index = 1 - # choose random clifford for first element - circ = circuits[rand].copy() + rand_index = 1 + + # We define the circuit size here, for the layout that will + # be created later + max_qubit = max(self.physical_qubits) + 1 + circ = QuantumCircuit(max_qubit) + # choose random clifford for the first element of the rb circuit + circ.compose(self._transpiled_cliff_circuits[rand]) circ.barrier(0) clifford_as_num = rand + prev_length = 2 if lengths[0] == 1: + # rb_circ will be the final circuit of length 1 + # If full_sampling==False: + # - circ will be used as the prefix of the next circuits + # - prev_lengths indicates how many Cliffords were in the previous rb_circ + rb_circ = circ.copy() inverse_num = CLIFF_INVERSE_DATA[rand] - inverse_circ = circuits[inverse_num] + inverse_circ = self._transpiled_cliff_circuits[inverse_num] rb_circ.compose(inverse_circ, inplace=True) rb_circ.measure_all() rb_circ.metadata = { @@ -158,21 +210,22 @@ def build_rb_circuits(self, lengths, circuits, rng): "physical_qubits": 0, } - prev_length = 2 for length in lengths: for i in range(prev_length, length + 1): - rand = random_samples[index] + if i == 0: + circ = QuantumCircuit(1) + rand = random_samples[rand_index] # choose random clifford - next_circ = circuits[rand] - index += 1 + next_circ = self._transpiled_cliff_circuits[rand] + rand_index += 1 circ.compose(next_circ, inplace=True) circ.barrier(0) clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] if i == length: - rb_circ = circ.copy() + rb_circ = circ.copy() # circ is used as the prefix of the next circuit inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] # append the inverse - rb_circ.compose(circuits[inverse_clifford_num], inplace=True) + rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) rb_circ.measure_all() rb_circ.metadata = { @@ -184,9 +237,6 @@ def build_rb_circuits(self, lengths, circuits, rng): prev_length = i + 1 all_rb_circuits.append(rb_circ) - # print(rb_circ) - end = time.time() - print(" time for build_rb_circuits = " + str(end - start)) return all_rb_circuits def circuits(self) -> List[QuantumCircuit]: @@ -197,10 +247,10 @@ def circuits(self) -> List[QuantumCircuit]: """ start = time.time() rng = default_rng(seed=self.experiment_options.seed) + circuits = [] for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1: - circuits = self.build_rb_circuits(self.experiment_options.lengths, - self._all_rb_circuits, rng) + circuits = self.build_rb_circuits(self.experiment_options.lengths, rng) else: circuits += self._sample_circuits(self.experiment_options.lengths, rng) end = time.time() @@ -281,9 +331,29 @@ def _generate_circuit( circuits.append(rb_circ) return circuits + def _layout_for_rb_single_qubit(self): + circuits = self.circuits() + transpiled = [] + for c in circuits: + qr = QuantumRegister(c.num_qubits, name='q') + qubit = Qubit(qr, self.physical_qubits[0]) + c_new = QuantumCircuit( + *c.qregs, + *c.cregs, + name=c.name, + global_phase=c.global_phase, + metadata=c.metadata + ) + new_data = [] + for inst, qargs, cargs in c.data: + new_data.append((inst, [qubit], cargs)) + c_new.data = new_data + transpiled.append(c_new) + return transpiled + def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" - transpiled = super()._transpiled_circuits() + transpiled = self._layout_for_rb_single_qubit() if self.analysis.options.get("gate_error_ratio", None) is None: # Gate errors are not computed, then counting ops is not necessary. diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 124b9a9442..39318a931a 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -192,7 +192,32 @@ def test_return_same_circuit(self): self.assertEqual(circs1[1].decompose(), circs2[1].decompose()) self.assertEqual(circs1[2].decompose(), circs2[2].decompose()) - def test_full_sampling(self): + def test_full_sampling_single_qubit(self): + """Test if full sampling generates different circuits.""" + exp1 = rb.StandardRB( + qubits=(0,), + lengths=[10, 20, 30], + seed=123, + backend=self.backend, + full_sampling=False, + ) + exp2 = rb.StandardRB( + qubits=(0,), + lengths=[10, 20, 30], + seed=123, + backend=self.backend, + full_sampling=True, + ) + circs1 = exp1.circuits() + circs2 = exp2.circuits() + + self.assertEqual(circs1[0].decompose(), circs2[0].decompose()) + + # fully sampled circuits are regenerated while other is just built on top of previous length + self.assertNotEqual(circs1[1].decompose(), circs2[1].decompose()) + self.assertNotEqual(circs1[2].decompose(), circs2[2].decompose()) + + def test_full_sampling_2_qubits(self): """Test if full sampling generates different circuits.""" exp1 = rb.StandardRB( qubits=(0, 1), From 8dc9aa1bf989039b9930ae2b5a710d4a01349e1a Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 12 Jun 2022 21:38:36 +0300 Subject: [PATCH 08/39] In test_full_sampling_single_qubit fixed num_samples to be 1, because otherwise randomization is not identical in the two experiments --- .../randomized_benchmarking/rb_experiment.py | 15 ++++++++++----- .../test_randomized_benchmarking.py | 2 ++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index b85866c9db..ac847e8014 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -135,11 +135,12 @@ def _default_experiment_options(cls) -> Options: def _build_rb_circuits_full_sampling(self, lengths, rng): all_rb_circuits = [] - for length in lengths: - rb_circ = QuantumCircuit(1) + # We define the circuit size here, for the layout that will + # be created later + max_qubit = max(self.physical_qubits) + 1 + rb_circ = QuantumCircuit(max_qubit) random_samples = rng.integers(24, size=length) - print(random_samples) clifford_as_num = 0 for i in range(length): @@ -176,17 +177,17 @@ def build_rb_circuits(self, lengths, rng): """ if self._full_sampling: return self._build_rb_circuits_full_sampling(lengths, rng) + print("not full sampling") all_rb_circuits = [] - # length = lengths[-1] if self._full_sampling else sum(lengths) random_samples = rng.integers(24, size=lengths[-1]) rand = random_samples[0] rand_index = 1 - # We define the circuit size here, for the layout that will # be created later max_qubit = max(self.physical_qubits) + 1 circ = QuantumCircuit(max_qubit) # choose random clifford for the first element of the rb circuit + circ.compose(self._transpiled_cliff_circuits[rand]) circ.barrier(0) clifford_as_num = rand @@ -331,6 +332,10 @@ def _generate_circuit( circuits.append(rb_circ) return circuits + # This method does a quick layout to avoid calling 'transpile()' which is + # very costly in performance + # We simply copy the circuit to a new circuit where we define the mapping + # of the qubit to the single physical qubit that was requested by the user def _layout_for_rb_single_qubit(self): circuits = self.circuits() transpiled = [] diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 39318a931a..c06139a300 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -197,6 +197,7 @@ def test_full_sampling_single_qubit(self): exp1 = rb.StandardRB( qubits=(0,), lengths=[10, 20, 30], + num_samples = 1, seed=123, backend=self.backend, full_sampling=False, @@ -204,6 +205,7 @@ def test_full_sampling_single_qubit(self): exp2 = rb.StandardRB( qubits=(0,), lengths=[10, 20, 30], + num_samples=1, seed=123, backend=self.backend, full_sampling=True, From f0c3cc89358fbb1c5e4bfa4cbddb7f0029980369 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Mon, 13 Jun 2022 13:04:25 +0300 Subject: [PATCH 09/39] Tidied up build_rb_circuits --- .../randomized_benchmarking/rb_experiment.py | 62 +++++-------------- 1 file changed, 16 insertions(+), 46 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index ac847e8014..0cfea35257 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -65,7 +65,7 @@ def __init__( qubits: Sequence[int], lengths: Iterable[int], backend: Optional[Backend] = None, - num_samples: int = 3, + num_samples: int = 1, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, ): @@ -135,11 +135,11 @@ def _default_experiment_options(cls) -> Options: def _build_rb_circuits_full_sampling(self, lengths, rng): all_rb_circuits = [] + max_qubit = max(self.physical_qubits) + 1 for length in lengths: # We define the circuit size here, for the layout that will # be created later - max_qubit = max(self.physical_qubits) + 1 - rb_circ = QuantumCircuit(max_qubit) + rb_circ = QuantumCircuit(max_qubit, 1) random_samples = rng.integers(24, size=length) clifford_as_num = 0 @@ -155,13 +155,13 @@ def _build_rb_circuits_full_sampling(self, lengths, rng): inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] # append the inverse rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) - rb_circ.measure_all() + rb_circ.measure(0, 0) rb_circ.metadata = { "experiment_type": "rb", - "xval": length + 1, + "xval": length, "group": "Clifford", - "physical_qubits": 0, + "physical_qubits": self.physical_qubits, } all_rb_circuits.append(rb_circ) return all_rb_circuits @@ -180,64 +180,34 @@ def build_rb_circuits(self, lengths, rng): print("not full sampling") all_rb_circuits = [] random_samples = rng.integers(24, size=lengths[-1]) - rand = random_samples[0] - rand_index = 1 - # We define the circuit size here, for the layout that will - # be created later max_qubit = max(self.physical_qubits) + 1 - circ = QuantumCircuit(max_qubit) - # choose random clifford for the first element of the rb circuit - - circ.compose(self._transpiled_cliff_circuits[rand]) - circ.barrier(0) - clifford_as_num = rand - - prev_length = 2 - if lengths[0] == 1: - # rb_circ will be the final circuit of length 1 - # If full_sampling==False: - # - circ will be used as the prefix of the next circuits - # - prev_lengths indicates how many Cliffords were in the previous rb_circ - - rb_circ = circ.copy() - inverse_num = CLIFF_INVERSE_DATA[rand] - inverse_circ = self._transpiled_cliff_circuits[inverse_num] - rb_circ.compose(inverse_circ, inplace=True) - rb_circ.measure_all() - rb_circ.metadata = { - "experiment_type": "rb", - "xval": 2, - "group": "Clifford", - "physical_qubits": 0, - } + circ = QuantumCircuit(max_qubit, 1) + clifford_as_num = 0 # 0 is the Clifford that is Id + prev_length = 0 for length in lengths: - for i in range(prev_length, length + 1): - if i == 0: - circ = QuantumCircuit(1) - rand = random_samples[rand_index] + for i in range(prev_length, length): + rand = random_samples[i] # choose random clifford next_circ = self._transpiled_cliff_circuits[rand] - rand_index += 1 circ.compose(next_circ, inplace=True) circ.barrier(0) clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] - if i == length: + if i == length-1: rb_circ = circ.copy() # circ is used as the prefix of the next circuit inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] # append the inverse rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) - rb_circ.measure_all() + rb_circ.measure(0, 0) rb_circ.metadata = { "experiment_type": "rb", - "xval": length + 1, + "xval": length, "group": "Clifford", - "physical_qubits": 0, + "physical_qubits": self.physical_qubits, } - + all_rb_circuits.append(rb_circ) prev_length = i + 1 - all_rb_circuits.append(rb_circ) return all_rb_circuits def circuits(self) -> List[QuantumCircuit]: From 10a7e9f9d9a3f17847c01b77971df4b82d3be431 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Mon, 13 Jun 2022 14:05:45 +0300 Subject: [PATCH 10/39] Added documentation and moved methods --- .../randomized_benchmarking/rb_experiment.py | 165 +++++++++--------- 1 file changed, 87 insertions(+), 78 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 0cfea35257..beadaa8017 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -133,83 +133,6 @@ def _default_experiment_options(cls) -> Options: return options - def _build_rb_circuits_full_sampling(self, lengths, rng): - all_rb_circuits = [] - max_qubit = max(self.physical_qubits) + 1 - for length in lengths: - # We define the circuit size here, for the layout that will - # be created later - rb_circ = QuantumCircuit(max_qubit, 1) - random_samples = rng.integers(24, size=length) - - clifford_as_num = 0 - for i in range(length): - # choose random clifford - rand = random_samples[i] - next_circ = self._transpiled_cliff_circuits[rand].copy() - - rb_circ.compose(next_circ, inplace=True) - rb_circ.barrier(0) - clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] - - inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] - # append the inverse - rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) - rb_circ.measure(0, 0) - - rb_circ.metadata = { - "experiment_type": "rb", - "xval": length, - "group": "Clifford", - "physical_qubits": self.physical_qubits, - } - all_rb_circuits.append(rb_circ) - return all_rb_circuits - - def build_rb_circuits(self, lengths, rng): - """ - build_rb_circuits - Args: - qubits: list of physical qubits for the experiment. - lengths: A list of RB sequence lengths. We create random circuits - where the number of cliffords in each is in lengths. - backend: The backend to run the experiment on. - """ - if self._full_sampling: - return self._build_rb_circuits_full_sampling(lengths, rng) - print("not full sampling") - all_rb_circuits = [] - random_samples = rng.integers(24, size=lengths[-1]) - max_qubit = max(self.physical_qubits) + 1 - circ = QuantumCircuit(max_qubit, 1) - clifford_as_num = 0 # 0 is the Clifford that is Id - prev_length = 0 - - for length in lengths: - for i in range(prev_length, length): - rand = random_samples[i] - # choose random clifford - next_circ = self._transpiled_cliff_circuits[rand] - circ.compose(next_circ, inplace=True) - circ.barrier(0) - clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] - if i == length-1: - rb_circ = circ.copy() # circ is used as the prefix of the next circuit - inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] - # append the inverse - rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) - rb_circ.measure(0, 0) - - rb_circ.metadata = { - "experiment_type": "rb", - "xval": length, - "group": "Clifford", - "physical_qubits": self.physical_qubits, - } - all_rb_circuits.append(rb_circ) - prev_length = i + 1 - return all_rb_circuits - def circuits(self) -> List[QuantumCircuit]: """Return a list of RB circuits. @@ -221,7 +144,7 @@ def circuits(self) -> List[QuantumCircuit]: circuits = [] for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1: - circuits = self.build_rb_circuits(self.experiment_options.lengths, rng) + circuits = self._build_rb_circuits(self.experiment_options.lengths, rng) else: circuits += self._sample_circuits(self.experiment_options.lengths, rng) end = time.time() @@ -302,10 +225,96 @@ def _generate_circuit( circuits.append(rb_circ) return circuits + def _build_rb_circuits(self, lengths, rng): + """ + build_rb_circuits + Args: + lengths: A list of RB sequence lengths. We create random circuits + where the number of cliffords in each is in lengths. + rng: Generator object for random number generation. + If None, default_rng will be used. + To create the RB circuit, we use a mapping between Cliffords and integers + defined in the file clifford_data.py. The operations compose and inverse are much faster + when performed on the integers rather than on the Cliffords. + """ + if self._full_sampling: + return self._build_rb_circuits_full_sampling(lengths, rng) + print("not full sampling") + all_rb_circuits = [] + random_samples = rng.integers(24, size=lengths[-1]) + max_qubit = max(self.physical_qubits) + 1 + + # When full_sampling==False, each circuit is the prefix of the next circuit (without the + # inverse Clifford at the end of the circuit. The variable 'circ' will contain the growing circuit. + # When each circuit reaches its length, we copy it to rb_circ, append the inverse, + # and add it to the list of circuits. + circ = QuantumCircuit(max_qubit, 1) + clifford_as_num = 0 # 0 is the Clifford that is Id + prev_length = 0 + + for length in lengths: + for i in range(prev_length, length): + rand = random_samples[i] + # choose random clifford + next_circ = self._transpiled_cliff_circuits[rand] + circ.compose(next_circ, inplace=True) + circ.barrier(0) + clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] + if i == length-1: + rb_circ = circ.copy() # circ is used as the prefix of the next circuit + inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] + # append the inverse + rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) + rb_circ.measure(0, 0) + + rb_circ.metadata = { + "experiment_type": "rb", + "xval": length, + "group": "Clifford", + "physical_qubits": self.physical_qubits, + } + all_rb_circuits.append(rb_circ) + prev_length = i + 1 + return all_rb_circuits + + def _build_rb_circuits_full_sampling(self, lengths, rng): + all_rb_circuits = [] + max_qubit = max(self.physical_qubits) + 1 + for length in lengths: + # We define the circuit size here, for the layout that will + # be created later + rb_circ = QuantumCircuit(max_qubit, 1) + random_samples = rng.integers(24, size=length) + # For full_sampling, we create each circuit independently. + clifford_as_num = 0 + for i in range(length): + # choose random clifford + rand = random_samples[i] + next_circ = self._transpiled_cliff_circuits[rand].copy() + + rb_circ.compose(next_circ, inplace=True) + rb_circ.barrier(0) + clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] + + inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] + # append the inverse + rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) + rb_circ.measure(0, 0) + + rb_circ.metadata = { + "experiment_type": "rb", + "xval": length, + "group": "Clifford", + "physical_qubits": self.physical_qubits, + } + all_rb_circuits.append(rb_circ) + return all_rb_circuits + # This method does a quick layout to avoid calling 'transpile()' which is # very costly in performance # We simply copy the circuit to a new circuit where we define the mapping # of the qubit to the single physical qubit that was requested by the user + # This is a hack, and would be better if transpile() implemented it. def _layout_for_rb_single_qubit(self): circuits = self.circuits() transpiled = [] From aea856a26ba4990b76774dd2f1c511a2d33c5778 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Mon, 13 Jun 2022 15:26:44 +0300 Subject: [PATCH 11/39] Added test_single_qubit_parallel --- .../test_randomized_benchmarking.py | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index c06139a300..e5bc9e2b6f 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -26,6 +26,7 @@ from qiskit_experiments.library import randomized_benchmarking as rb from qiskit_experiments.database_service.exceptions import DbExperimentEntryNotFound +from qiskit_experiments.framework.composite import ParallelExperiment class RBTestCase(QiskitExperimentsTestCase): @@ -88,7 +89,6 @@ def test_single_qubit(self): seed=123, backend=self.backend, ) - exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) #self.assertAllIdentity(exp.circuits()) @@ -108,8 +108,7 @@ def test_single_qubit(self): print("epc = " + str(epc)) epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 - print("epc expected = " + str(epc_expected)) - #self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) end = time.time() print("time for test_single_qubit = " + str(end - start)) @@ -290,6 +289,29 @@ def test_expdata_serialization(self): self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) + def test_single_qubit_parallel(self): + """Test single qubit RB in parallel.""" + qubits = [0, 2] + lengths = list(range(30, 301, 30)) + exps = [] + for qubit in qubits: + exp = rb.StandardRB( + qubits=[qubit], + lengths=lengths, + seed=123, + backend=self.backend, + ) + exp.analysis.set_options(gate_error_ratio=None, plot_raw_data=False) + exps.append(exp) + + par_exp = ParallelExperiment(exps) + par_exp.set_transpile_options(optimization_level=1) + + par_expdata = par_exp.run(backend=self.backend) + epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 + for i in range(2): + epc = par_expdata.child_data(i).analysis_results("EPC") + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) @ddt class TestInterleavedRB(RBTestCase): From dd0b62bddf7f9c985b80b24843550dc8723a0610 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 14 Jun 2022 18:53:34 +0300 Subject: [PATCH 12/39] Changed name _format_data to format_data because the method wasn't being called by the child class CurveAnalaysis. Added parameter to rb_experiment to determine whether to use the old algorithm or new one --- .../curve_analysis/base_curve_analysis.py | 2 +- .../curve_analysis/curve_analysis.py | 2 +- .../randomized_benchmarking/rb_experiment.py | 16 +++++++--------- .../test_randomized_benchmarking.py | 1 + 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/qiskit_experiments/curve_analysis/base_curve_analysis.py b/qiskit_experiments/curve_analysis/base_curve_analysis.py index bd7b12aa65..8c3aa569da 100644 --- a/qiskit_experiments/curve_analysis/base_curve_analysis.py +++ b/qiskit_experiments/curve_analysis/base_curve_analysis.py @@ -265,7 +265,7 @@ def _generate_fit_guesses( """ return user_opt - def _format_data( + def format_data( self, curve_data: CurveData, ) -> CurveData: diff --git a/qiskit_experiments/curve_analysis/curve_analysis.py b/qiskit_experiments/curve_analysis/curve_analysis.py index 9db69780d3..50ece2cd7a 100644 --- a/qiskit_experiments/curve_analysis/curve_analysis.py +++ b/qiskit_experiments/curve_analysis/curve_analysis.py @@ -176,7 +176,7 @@ def _run_analysis( self.__processed_data_set["raw_data"] = processed_data # Format data - formatted_data = self._format_data(processed_data) + formatted_data = self.format_data(processed_data) if self.options.plot: for model in self._models: sub_data = formatted_data.get_subset_of(model._name) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index beadaa8017..207ced3db9 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -68,6 +68,7 @@ def __init__( num_samples: int = 1, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, + new_rb: Optional[bool] = True ): """Initialize a standard randomized benchmarking experiment. @@ -93,12 +94,11 @@ def __init__( # Set fixed options self._full_sampling = full_sampling + self._new_rb = new_rb self._clifford_utils = CliffordUtils() start = time.time() basis_gates = ["rz", "sx"] self._transpiled_cliff_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) - end = time.time() - print("time for generate_all_transpiled_clifford_circuits="+str(end-start)) def _verify_parameters(self, lengths, num_samples): """Verify input correctness, raise QiskitError if needed""" @@ -139,18 +139,13 @@ def circuits(self) -> List[QuantumCircuit]: Returns: A list of :class:`QuantumCircuit`. """ - start = time.time() rng = default_rng(seed=self.experiment_options.seed) circuits = [] for _ in range(self.experiment_options.num_samples): - if self.num_qubits == 1: + if self.num_qubits == 1 and self._new_rb: circuits = self._build_rb_circuits(self.experiment_options.lengths, rng) else: circuits += self._sample_circuits(self.experiment_options.lengths, rng) - end = time.time() - print("time for circuits = " + str(end - start)) - #for c in circuits: - #print(c) return circuits def _sample_circuits(self, lengths: Iterable[int], rng: Generator) -> List[QuantumCircuit]: @@ -337,7 +332,10 @@ def _layout_for_rb_single_qubit(self): def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" - transpiled = self._layout_for_rb_single_qubit() + if self.num_qubits==1 and self._new_rb: + transpiled = self._layout_for_rb_single_qubit() + else: + transpiled = super()._transpiled_circuits() if self.analysis.options.get("gate_error_ratio", None) is None: # Gate errors are not computed, then counting ops is not necessary. diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index e5bc9e2b6f..728dddee2a 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -88,6 +88,7 @@ def test_single_qubit(self): lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, + new_rb=True ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) From b9c9f410f67a20a326128d02afba71dce2a70b0d Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 15 Jun 2022 12:15:56 +0300 Subject: [PATCH 13/39] Fixed handling of num_samples>1. Cleaned out prints. Reverted previous change regarding _format_data --- .../curve_analysis/base_curve_analysis.py | 2 +- qiskit_experiments/curve_analysis/curve_analysis.py | 2 +- qiskit_experiments/framework/base_experiment.py | 3 --- .../library/randomized_benchmarking/rb_experiment.py | 12 ++++++------ .../test_randomized_benchmarking.py | 6 +----- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/qiskit_experiments/curve_analysis/base_curve_analysis.py b/qiskit_experiments/curve_analysis/base_curve_analysis.py index 8c3aa569da..bd7b12aa65 100644 --- a/qiskit_experiments/curve_analysis/base_curve_analysis.py +++ b/qiskit_experiments/curve_analysis/base_curve_analysis.py @@ -265,7 +265,7 @@ def _generate_fit_guesses( """ return user_opt - def format_data( + def _format_data( self, curve_data: CurveData, ) -> CurveData: diff --git a/qiskit_experiments/curve_analysis/curve_analysis.py b/qiskit_experiments/curve_analysis/curve_analysis.py index 50ece2cd7a..9db69780d3 100644 --- a/qiskit_experiments/curve_analysis/curve_analysis.py +++ b/qiskit_experiments/curve_analysis/curve_analysis.py @@ -176,7 +176,7 @@ def _run_analysis( self.__processed_data_set["raw_data"] = processed_data # Format data - formatted_data = self.format_data(processed_data) + formatted_data = self._format_data(processed_data) if self.options.plot: for model in self._models: sub_data = formatted_data.get_subset_of(model._name) diff --git a/qiskit_experiments/framework/base_experiment.py b/qiskit_experiments/framework/base_experiment.py index d1d9332fe9..ee41c5b995 100644 --- a/qiskit_experiments/framework/base_experiment.py +++ b/qiskit_experiments/framework/base_experiment.py @@ -263,10 +263,7 @@ def run( experiment._finalize() # Generate and transpile circuits - start = time.time() transpiled_circuits = experiment._transpiled_circuits() - end = time.time() - print("time for transpiled_circuits = " + str(end-start)) # Initialize result container experiment_data = experiment._initialize_experiment_data() diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 207ced3db9..ab77bb4426 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -65,7 +65,7 @@ def __init__( qubits: Sequence[int], lengths: Iterable[int], backend: Optional[Backend] = None, - num_samples: int = 1, + num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, new_rb: Optional[bool] = True @@ -97,7 +97,7 @@ def __init__( self._new_rb = new_rb self._clifford_utils = CliffordUtils() start = time.time() - basis_gates = ["rz", "sx"] + basis_gates = ["rz", "sx", "cx"] self._transpiled_cliff_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) def _verify_parameters(self, lengths, num_samples): @@ -143,7 +143,7 @@ def circuits(self) -> List[QuantumCircuit]: circuits = [] for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._new_rb: - circuits = self._build_rb_circuits(self.experiment_options.lengths, rng) + circuits += self._build_rb_circuits(self.experiment_options.lengths, rng) else: circuits += self._sample_circuits(self.experiment_options.lengths, rng) return circuits @@ -225,16 +225,16 @@ def _build_rb_circuits(self, lengths, rng): build_rb_circuits Args: lengths: A list of RB sequence lengths. We create random circuits - where the number of cliffords in each is in lengths. + where the number of cliffords in each is defined in lengths. rng: Generator object for random number generation. If None, default_rng will be used. To create the RB circuit, we use a mapping between Cliffords and integers defined in the file clifford_data.py. The operations compose and inverse are much faster - when performed on the integers rather than on the Cliffords. + when performed on the integers rather than on the Cliffords themselves. """ if self._full_sampling: return self._build_rb_circuits_full_sampling(lengths, rng) - print("not full sampling") + all_rb_circuits = [] random_samples = rng.integers(24, size=lengths[-1]) max_qubit = max(self.physical_qubits) + 1 diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 728dddee2a..c4e9ebc09a 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -82,7 +82,6 @@ class TestStandardRB(RBTestCase): def test_single_qubit(self): """Test single qubit RB.""" - start = time.time() exp = rb.StandardRB( qubits=(0,), lengths=list(range(1, 300, 30)), @@ -106,12 +105,9 @@ def test_single_qubit(self): # from 0 to 2, i.e. arbitrary U gate can be decomposed into up to 2 SX with RZs. # We may want to expect the average number of SX is (0 + 1 + 2) / 3 = 1.0. epc = expdata.analysis_results("EPC") - print("epc = " + str(epc)) epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - end = time.time() - print("time for test_single_qubit = " + str(end - start)) def test_two_qubit(self): """Test two qubit RB.""" @@ -293,7 +289,7 @@ def test_expdata_serialization(self): def test_single_qubit_parallel(self): """Test single qubit RB in parallel.""" qubits = [0, 2] - lengths = list(range(30, 301, 30)) + lengths = list(range(1, 300, 30)) exps = [] for qubit in qubits: exp = rb.StandardRB( From 92f5580b02808dbc039998572466a3904e6ce209 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 15 Jun 2022 14:27:56 +0300 Subject: [PATCH 14/39] Added assertExperimentDone to test_single-qubit_parallel. Fixed parameters for test_full_sampling_single_qubit --- test/randomized_benchmarking/test_randomized_benchmarking.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index c4e9ebc09a..0bfcb12b1f 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -193,7 +193,6 @@ def test_full_sampling_single_qubit(self): exp1 = rb.StandardRB( qubits=(0,), lengths=[10, 20, 30], - num_samples = 1, seed=123, backend=self.backend, full_sampling=False, @@ -201,7 +200,6 @@ def test_full_sampling_single_qubit(self): exp2 = rb.StandardRB( qubits=(0,), lengths=[10, 20, 30], - num_samples=1, seed=123, backend=self.backend, full_sampling=True, @@ -305,6 +303,7 @@ def test_single_qubit_parallel(self): par_exp.set_transpile_options(optimization_level=1) par_expdata = par_exp.run(backend=self.backend) + self.assertExperimentDone(par_expdata) epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 for i in range(2): epc = par_expdata.child_data(i).analysis_results("EPC") From 3e9c386b5dd0b83ec643c3d2c4e5ca0c0d871e68 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 15 Jun 2022 16:21:00 +0300 Subject: [PATCH 15/39] Modified assertAllIdentity to support circuits with rz gates --- .../test_randomized_benchmarking.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 0bfcb12b1f..e6cf69384c 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -16,13 +16,12 @@ import numpy as np from ddt import ddt, data, unpack -import time from qiskit.circuit import Delay, QuantumCircuit from qiskit.circuit.library import SXGate, CXGate, TGate, XGate from qiskit.exceptions import QiskitError from qiskit.providers.aer import AerSimulator from qiskit.providers.aer.noise import NoiseModel, depolarizing_error -from qiskit.quantum_info import Clifford +from qiskit.quantum_info import Clifford, Operator from qiskit_experiments.library import randomized_benchmarking as rb from qiskit_experiments.database_service.exceptions import DbExperimentEntryNotFound @@ -69,12 +68,9 @@ def assertAllIdentity(self, circuits): """Test if all experiment circuits are identity.""" for circ in circuits: num_qubits = circ.num_qubits - iden = Clifford(np.eye(2 * num_qubits, dtype=bool)) + qc_iden = QuantumCircuit(num_qubits) circ.remove_final_measurements() - self.assertEqual( - Clifford(circ), iden, f"Circuit {circ.name} doesn't result in the identity matrix." - ) - + assert (Operator(circ).equiv(Operator(qc_iden))) @ddt class TestStandardRB(RBTestCase): @@ -87,11 +83,11 @@ def test_single_qubit(self): lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, - new_rb=True + new_rb=False ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) - #self.assertAllIdentity(exp.circuits()) + self.assertAllIdentity(exp.circuits()) expdata = exp.run() From 45575721fa21660c3a860e004fb52b02971b4d7b Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 15 Jun 2022 16:54:36 +0300 Subject: [PATCH 16/39] Changed name _new_rb to _transpiled_rb. Also changed default to be False, so that all tests will pass --- .../library/randomized_benchmarking/rb_experiment.py | 8 ++++---- .../test_randomized_benchmarking.py | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index ab77bb4426..2fbcba2da4 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -68,7 +68,7 @@ def __init__( num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, - new_rb: Optional[bool] = True + transpiled_rb: Optional[bool] = False ): """Initialize a standard randomized benchmarking experiment. @@ -94,7 +94,7 @@ def __init__( # Set fixed options self._full_sampling = full_sampling - self._new_rb = new_rb + self._transpiled_rb = transpiled_rb self._clifford_utils = CliffordUtils() start = time.time() basis_gates = ["rz", "sx", "cx"] @@ -142,7 +142,7 @@ def circuits(self) -> List[QuantumCircuit]: rng = default_rng(seed=self.experiment_options.seed) circuits = [] for _ in range(self.experiment_options.num_samples): - if self.num_qubits == 1 and self._new_rb: + if self.num_qubits == 1 and self._transpiled_rb: circuits += self._build_rb_circuits(self.experiment_options.lengths, rng) else: circuits += self._sample_circuits(self.experiment_options.lengths, rng) @@ -332,7 +332,7 @@ def _layout_for_rb_single_qubit(self): def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" - if self.num_qubits==1 and self._new_rb: + if self.num_qubits==1 and self._transpiled_rb: transpiled = self._layout_for_rb_single_qubit() else: transpiled = super()._transpiled_circuits() diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index e6cf69384c..d88cff9ed2 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -83,7 +83,7 @@ def test_single_qubit(self): lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, - new_rb=False + transpiled_rb=True ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) @@ -192,6 +192,7 @@ def test_full_sampling_single_qubit(self): seed=123, backend=self.backend, full_sampling=False, + transpiled_rb=True ) exp2 = rb.StandardRB( qubits=(0,), @@ -199,6 +200,7 @@ def test_full_sampling_single_qubit(self): seed=123, backend=self.backend, full_sampling=True, + transpiled_rb=True ) circs1 = exp1.circuits() circs2 = exp2.circuits() @@ -249,14 +251,14 @@ def test_invalid_configuration(self, configs): def test_experiment_config(self): """Test converting to and from config works""" - exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123) + exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123, transpiled_rb=True) loaded_exp = rb.StandardRB.from_config(exp.config()) self.assertNotEqual(exp, loaded_exp) self.assertTrue(self.json_equiv(exp, loaded_exp)) def test_roundtrip_serializable(self): """Test round trip JSON serialization""" - exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123) + exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123, transpiled_rb=True) self.assertRoundTripSerializable(exp, self.json_equiv) def test_analysis_config(self): @@ -273,6 +275,7 @@ def test_expdata_serialization(self): lengths=list(range(1, 200, 50)), seed=123, backend=self.backend, + transpiled_rb=True ) exp.set_transpile_options(**self.transpiler_options) expdata = exp.run() @@ -291,6 +294,7 @@ def test_single_qubit_parallel(self): lengths=lengths, seed=123, backend=self.backend, + transpiled_rb=True ) exp.analysis.set_options(gate_error_ratio=None, plot_raw_data=False) exps.append(exp) From 0673e239b7b0c2eb5344178ce9877c09bcb4b574 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 15 Jun 2022 16:56:53 +0300 Subject: [PATCH 17/39] removed fast_rb.py --- .../randomized_benchmarking/fast_rb.py | 82 ------------------- 1 file changed, 82 deletions(-) delete mode 100644 qiskit_experiments/library/randomized_benchmarking/fast_rb.py diff --git a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py b/qiskit_experiments/library/randomized_benchmarking/fast_rb.py deleted file mode 100644 index 00dbdf6e68..0000000000 --- a/qiskit_experiments/library/randomized_benchmarking/fast_rb.py +++ /dev/null @@ -1,82 +0,0 @@ - -from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils -from qiskit.providers.aer import AerSimulator -from qiskit.compiler import transpile -from .cliff_data import CLIFF_COMPOSE_DATA, CLIFF_INVERSE_DATA - -import time - -def build_rb_circuits(lengths, circuits, rng): - start = time.time() - all_clifford_circuits = [] - random_samples = rng.integers(24, size=lengths[-1]) - rand = random_samples[0] - index = 1 - # choose random clifford for first element - circ = circuits[rand].copy() - circ.barrier(0) - clifford_as_num = rand - - if lengths[0] == 1: - rb_circ = circ.copy() - inverse_num = CLIFF_INVERSE_DATA[rand] - inverse_circ = circuits[inverse_num] - rb_circ.compose(inverse_circ, inplace=True) - rb_circ.measure_all() - rb_circ.metadata = { - "experiment_type": "rb", - "xval": 2, - "group": "Clifford", - "physical_qubits": 0, - } - - prev_length = 2 - for length in lengths: - for i in range(prev_length, length+1): - rand = random_samples[index] - # choose random clifford - next_circ = circuits[rand] - index += 1 - circ.compose(next_circ, inplace=True) - circ.barrier(0) - clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] - if i==length: - rb_circ = circ.copy() - inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] - # append the inverse - rb_circ.compose(circuits[inverse_clifford_num], inplace=True) - rb_circ.measure_all() - - rb_circ.metadata = { - "experiment_type": "rb", - "xval": length + 1, - "group": "Clifford", - "physical_qubits": 0, - } - - prev_length = i+1 - all_clifford_circuits.append(rb_circ) - #print(rb_circ) - end = time.time() - print(" time for build_rb_circuits = " + str(end-start)) - return all_clifford_circuits - -def generate_all_transpiled_clifford_circuits(): - utils = CliffordUtils() - circs = [] - for num in range(0, 24): - circ = utils.clifford_1_qubit_circuit(num=num) - circs.append(circ) - - backend = AerSimulator() - new_circs = [] - - for i, circ in enumerate(circs): - transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=['sx','rz']) - new_circs.append(transpiled_circ) - #print(i) - #print(new_circ) - return new_circs - - - From c543fa4de8e96ec10c9bfc05d8f384c08f948cd8 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 15 Jun 2022 16:57:50 +0300 Subject: [PATCH 18/39] removed rb_on_device.py --- rb_on_device.py | 87 ------------------------------------------------- 1 file changed, 87 deletions(-) delete mode 100644 rb_on_device.py diff --git a/rb_on_device.py b/rb_on_device.py deleted file mode 100644 index b387872531..0000000000 --- a/rb_on_device.py +++ /dev/null @@ -1,87 +0,0 @@ -# This code is part of Qiskit. -# (C) Copyright IBM 2022. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Test for randomized benchmarking experiments.""" - -from test.base import QiskitExperimentsTestCase -import numpy as np -from ddt import ddt, data, unpack -import time - -from qiskit import IBMQ - -from qiskit_experiments.library import randomized_benchmarking as rb - -class RBTestCase(QiskitExperimentsTestCase): - """Base test case for randomized benchmarking defining a common noise model.""" - - def __init__(self): - """Set up the tests.""" - - # basis gates - self.basis_gates = ["sx", "rz"] - - # Need level1 for consecutive gate cancellation for reference EPC value calculation - self.transpiler_options = { - "basis_gates": self.basis_gates, - "optimization_level": 1, - } - IBMQ.load_account() - provider = IBMQ.get_provider(hub="ibm-q-internal", group="deployed", project="default") - self.backend = provider.backend.ibmq_armonk - -@ddt -class TestStandardRB(RBTestCase): - """Test for standard RB.""" - - def test_single_qubit(self, lengths): - """Test single qubit RB.""" - exp = rb.StandardRB( - qubits=(0,), - lengths = lengths, - seed=123, - backend=self.backend, - ) - exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**self.transpiler_options) - #assertAllIdentity(exp.circuits()) - expdata = exp.run() - epc = expdata.analysis_results("EPC") - epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.15 * epc_expected) - - def time_rb_single_qubit(self): - maxcliff = 4000 - nCliffs = np.logspace(np.log10(1.5), np.log10(maxcliff), int(np.log10(maxcliff) * 4), dtype=int) - lengths_list = [list(range(1, 300, 30)), - list(range(1, 1002, 100)), - nCliffs] - - iters = 3 - result_times = {} - for lengths in lengths_list: - sum_time = 0.0 - for iter in range(iters): - start = time.time() - self.test_single_qubit(lengths=lengths) - end = time.time() - sum_time += end-start - sum_time /= iters - result_times[lengths[-1]] = sum_time - print("lengths = " + str(lengths)) - print(result_times) - - - -# For testing the methods standalone -test1 = TestStandardRB() -test1.time_rb_single_qubit() - From 3c2dca83cac5b1060c129a7a46aa3667e49c5141 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 15 Jun 2022 16:59:55 +0300 Subject: [PATCH 19/39] Removed temporary 'import time' --- qiskit_experiments/framework/base_experiment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_experiments/framework/base_experiment.py b/qiskit_experiments/framework/base_experiment.py index ee41c5b995..a8ac13bce8 100644 --- a/qiskit_experiments/framework/base_experiment.py +++ b/qiskit_experiments/framework/base_experiment.py @@ -18,7 +18,6 @@ from collections import OrderedDict from typing import Sequence, Optional, Tuple, List, Dict, Union import warnings -import time from qiskit import transpile, QuantumCircuit from qiskit.providers import Job, Backend @@ -264,6 +263,7 @@ def run( # Generate and transpile circuits transpiled_circuits = experiment._transpiled_circuits() + # Initialize result container experiment_data = experiment._initialize_experiment_data() From b9e0884d8f05ce4010b092fc95b5bb71421aaf1f Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 21 Jun 2022 10:22:55 +0300 Subject: [PATCH 20/39] Added support for interleaved rb single qubit --- .../framework/base_experiment.py | 2 +- .../randomized_benchmarking/clifford_data.py | 1220 +++++++++-------- .../interleaved_rb_experiment.py | 24 +- .../randomized_benchmarking/rb_experiment.py | 90 +- .../test_randomized_benchmarking.py | 52 +- 5 files changed, 754 insertions(+), 634 deletions(-) diff --git a/qiskit_experiments/framework/base_experiment.py b/qiskit_experiments/framework/base_experiment.py index a8ac13bce8..e0656eb986 100644 --- a/qiskit_experiments/framework/base_experiment.py +++ b/qiskit_experiments/framework/base_experiment.py @@ -263,7 +263,7 @@ def run( # Generate and transpile circuits transpiled_circuits = experiment._transpiled_circuits() - + # Initialize result container experiment_data = experiment._initialize_experiment_data() diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py index 3a59f4958f..f4ddc1330e 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py @@ -1,605 +1,621 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +This file contains the Clifford group represented as integers. +""" +#In CLIFF_COMPOSE_DATA, (i, j): k represents Clifford(i).compose(clifford(j)) = Clifford(k) CLIFF_COMPOSE_DATA = { - (0, 0): 0, - (0, 1): 1, - (0, 2): 2, - (0, 3): 3, - (0, 4): 4, - (0, 5): 5, - (0, 6): 6, - (0, 7): 7, - (0, 8): 8, - (0, 9): 9, - (0, 10): 10, - (0, 11): 11, - (0, 12): 12, - (0, 13): 13, - (0, 14): 14, - (0, 15): 15, - (0, 16): 16, - (0, 17): 17, - (0, 18): 18, - (0, 19): 19, - (0, 20): 20, - (0, 21): 21, - (0, 22): 22, - (0, 23): 23, - (1, 0): 1, - (1, 1): 0, - (1, 2): 3, - (1, 3): 2, - (1, 4): 5, - (1, 5): 4, - (1, 6): 7, - (1, 7): 6, - (1, 8): 9, - (1, 9): 8, - (1, 10): 11, - (1, 11): 10, - (1, 12): 13, - (1, 13): 12, - (1, 14): 15, - (1, 15): 14, - (1, 16): 17, - (1, 17): 16, - (1, 18): 19, - (1, 19): 18, - (1, 20): 21, - (1, 21): 20, - (1, 22): 23, - (1, 23): 22, - (2, 0): 2, - (2, 1): 23, - (2, 2): 6, - (2, 3): 4, - (2, 4): 15, - (2, 5): 1, - (2, 6): 8, - (2, 7): 17, - (2, 8): 0, - (2, 9): 10, - (2, 10): 21, - (2, 11): 7, - (2, 12): 14, - (2, 13): 11, - (2, 14): 18, - (2, 15): 16, - (2, 16): 3, - (2, 17): 13, - (2, 18): 20, - (2, 19): 5, - (2, 20): 12, - (2, 21): 22, - (2, 22): 9, - (2, 23): 19, - (3, 0): 3, - (3, 1): 22, - (3, 2): 7, - (3, 3): 5, - (3, 4): 14, - (3, 5): 0, - (3, 6): 9, - (3, 7): 16, - (3, 8): 1, - (3, 9): 11, - (3, 10): 20, - (3, 11): 6, - (3, 12): 15, - (3, 13): 10, - (3, 14): 19, - (3, 15): 17, - (3, 16): 2, - (3, 17): 12, - (3, 18): 21, - (3, 19): 4, - (3, 20): 13, - (3, 21): 23, - (3, 22): 8, - (3, 23): 18, - (4, 0): 4, - (4, 1): 9, - (4, 2): 17, - (4, 3): 1, - (4, 4): 18, - (4, 5): 2, - (4, 6): 10, - (4, 7): 3, - (4, 8): 23, - (4, 9): 7, - (4, 10): 12, - (4, 11): 8, - (4, 12): 16, - (4, 13): 21, - (4, 14): 5, - (4, 15): 13, - (4, 16): 6, - (4, 17): 14, - (4, 18): 22, - (4, 19): 15, - (4, 20): 11, - (4, 21): 19, - (4, 22): 0, - (4, 23): 20, - (5, 0): 5, - (5, 1): 8, - (5, 2): 16, - (5, 3): 0, - (5, 4): 19, - (5, 5): 3, - (5, 6): 11, - (5, 7): 2, - (5, 8): 22, - (5, 9): 6, - (5, 10): 13, - (5, 11): 9, - (5, 12): 17, - (5, 13): 20, - (5, 14): 4, - (5, 15): 12, - (5, 16): 7, - (5, 17): 15, - (5, 18): 23, - (5, 19): 14, - (5, 20): 10, - (5, 21): 18, - (5, 22): 1, - (5, 23): 21, - (6, 0): 6, - (6, 1): 19, - (6, 2): 8, - (6, 3): 15, - (6, 4): 16, - (6, 5): 23, - (6, 6): 0, - (6, 7): 13, - (6, 8): 2, - (6, 9): 21, - (6, 10): 22, - (6, 11): 17, - (6, 12): 18, - (6, 13): 7, - (6, 14): 20, - (6, 15): 3, - (6, 16): 4, - (6, 17): 11, - (6, 18): 12, - (6, 19): 1, - (6, 20): 14, - (6, 21): 9, - (6, 22): 10, - (6, 23): 5, - (7, 0): 7, - (7, 1): 18, - (7, 2): 9, - (7, 3): 14, - (7, 4): 17, - (7, 5): 22, - (7, 6): 1, - (7, 7): 12, - (7, 8): 3, - (7, 9): 20, - (7, 10): 23, - (7, 11): 16, - (7, 12): 19, - (7, 13): 6, - (7, 14): 21, - (7, 15): 2, - (7, 16): 5, - (7, 17): 10, - (7, 18): 13, - (7, 19): 0, - (7, 20): 15, - (7, 21): 8, - (7, 22): 11, - (7, 23): 4, - (8, 0): 8, - (8, 1): 5, - (8, 2): 0, - (8, 3): 16, - (8, 4): 3, - (8, 5): 19, - (8, 6): 2, - (8, 7): 11, - (8, 8): 6, - (8, 9): 22, - (8, 10): 9, - (8, 11): 13, - (8, 12): 20, - (8, 13): 17, - (8, 14): 12, - (8, 15): 4, - (8, 16): 15, - (8, 17): 7, - (8, 18): 14, - (8, 19): 23, - (8, 20): 18, - (8, 21): 10, - (8, 22): 21, - (8, 23): 1, - (9, 0): 9, - (9, 1): 4, - (9, 2): 1, - (9, 3): 17, - (9, 4): 2, - (9, 5): 18, - (9, 6): 3, - (9, 7): 10, - (9, 8): 7, - (9, 9): 23, - (9, 10): 8, - (9, 11): 12, - (9, 12): 21, - (9, 13): 16, - (9, 14): 13, - (9, 15): 5, - (9, 16): 14, - (9, 17): 6, - (9, 18): 15, - (9, 19): 22, - (9, 20): 19, - (9, 21): 11, - (9, 22): 20, - (9, 23): 0, - (10, 0): 10, - (10, 1): 15, - (10, 2): 23, - (10, 3): 13, - (10, 4): 6, - (10, 5): 20, - (10, 6): 4, - (10, 7): 21, - (10, 8): 17, - (10, 9): 19, - (10, 10): 0, - (10, 11): 14, - (10, 12): 22, - (10, 13): 3, - (10, 14): 11, - (10, 15): 1, - (10, 16): 18, - (10, 17): 8, - (10, 18): 16, - (10, 19): 9, - (10, 20): 5, - (10, 21): 7, - (10, 22): 12, - (10, 23): 2, - (11, 0): 11, - (11, 1): 14, - (11, 2): 22, - (11, 3): 12, - (11, 4): 7, - (11, 5): 21, - (11, 6): 5, - (11, 7): 20, - (11, 8): 16, - (11, 9): 18, - (11, 10): 1, - (11, 11): 15, - (11, 12): 23, - (11, 13): 2, - (11, 14): 10, - (11, 15): 0, - (11, 16): 19, - (11, 17): 9, - (11, 18): 17, - (11, 19): 8, - (11, 20): 4, - (11, 21): 6, - (11, 22): 13, - (11, 23): 3, - (12, 0): 12, - (12, 1): 13, - (12, 2): 20, - (12, 3): 21, - (12, 4): 10, - (12, 5): 11, - (12, 6): 18, - (12, 7): 19, - (12, 8): 14, - (12, 9): 15, - (12, 10): 4, - (12, 11): 5, - (12, 12): 0, - (12, 13): 1, - (12, 14): 8, - (12, 15): 9, - (12, 16): 22, - (12, 17): 23, - (12, 18): 6, - (12, 19): 7, - (12, 20): 2, - (12, 21): 3, - (12, 22): 16, - (12, 23): 17, - (13, 0): 13, - (13, 1): 12, - (13, 2): 21, - (13, 3): 20, - (13, 4): 11, - (13, 5): 10, - (13, 6): 19, - (13, 7): 18, - (13, 8): 15, - (13, 9): 14, - (13, 10): 5, - (13, 11): 4, - (13, 12): 1, - (13, 13): 0, - (13, 14): 9, - (13, 15): 8, - (13, 16): 23, - (13, 17): 22, - (13, 18): 7, - (13, 19): 6, - (13, 20): 3, - (13, 21): 2, - (13, 22): 17, - (13, 23): 16, - (14, 0): 14, - (14, 1): 11, - (14, 2): 12, - (14, 3): 22, - (14, 4): 21, - (14, 5): 7, - (14, 6): 20, - (14, 7): 5, - (14, 8): 18, - (14, 9): 16, - (14, 10): 15, - (14, 11): 1, - (14, 12): 2, - (14, 13): 23, - (14, 14): 0, - (14, 15): 10, - (14, 16): 9, - (14, 17): 19, - (14, 18): 8, - (14, 19): 17, - (14, 20): 6, - (14, 21): 4, - (14, 22): 3, - (14, 23): 13, - (15, 0): 15, - (15, 1): 10, - (15, 2): 13, - (15, 3): 23, - (15, 4): 20, - (15, 5): 6, - (15, 6): 21, - (15, 7): 4, - (15, 8): 19, - (15, 9): 17, - (15, 10): 14, - (15, 11): 0, - (15, 12): 3, - (15, 13): 22, - (15, 14): 1, - (15, 15): 11, - (15, 16): 8, - (15, 17): 18, - (15, 18): 9, - (15, 19): 16, - (15, 20): 7, - (15, 21): 5, - (15, 22): 2, - (15, 23): 12, - (16, 0): 16, - (16, 1): 21, - (16, 2): 11, - (16, 3): 19, - (16, 4): 12, - (16, 5): 8, - (16, 6): 22, - (16, 7): 15, - (16, 8): 5, - (16, 9): 13, - (16, 10): 18, - (16, 11): 2, - (16, 12): 4, - (16, 13): 9, - (16, 14): 23, - (16, 15): 7, - (16, 16): 0, - (16, 17): 20, - (16, 18): 10, - (16, 19): 3, - (16, 20): 17, - (16, 21): 1, - (16, 22): 6, - (16, 23): 14, - (17, 0): 17, - (17, 1): 20, - (17, 2): 10, - (17, 3): 18, - (17, 4): 13, - (17, 5): 9, - (17, 6): 23, - (17, 7): 14, - (17, 8): 4, - (17, 9): 12, - (17, 10): 19, - (17, 11): 3, - (17, 12): 5, - (17, 13): 8, - (17, 14): 22, - (17, 15): 6, - (17, 16): 1, - (17, 17): 21, - (17, 18): 11, - (17, 19): 2, - (17, 20): 16, - (17, 21): 0, - (17, 22): 7, - (17, 23): 15, - (18, 0): 18, - (18, 1): 7, - (18, 2): 14, - (18, 3): 9, - (18, 4): 22, - (18, 5): 17, - (18, 6): 12, - (18, 7): 1, - (18, 8): 20, - (18, 9): 3, - (18, 10): 16, - (18, 11): 23, - (18, 12): 6, - (18, 13): 19, - (18, 14): 2, - (18, 15): 21, - (18, 16): 10, - (18, 17): 5, - (18, 18): 0, - (18, 19): 13, - (18, 20): 8, - (18, 21): 15, - (18, 22): 4, - (18, 23): 11, - (19, 0): 19, - (19, 1): 6, - (19, 2): 15, - (19, 3): 8, - (19, 4): 23, - (19, 5): 16, - (19, 6): 13, - (19, 7): 0, - (19, 8): 21, - (19, 9): 2, - (19, 10): 17, - (19, 11): 22, - (19, 12): 7, - (19, 13): 18, - (19, 14): 3, - (19, 15): 20, - (19, 16): 11, - (19, 17): 4, - (19, 18): 1, - (19, 19): 12, - (19, 20): 9, - (19, 21): 14, - (19, 22): 5, - (19, 23): 10, - (20, 0): 20, - (20, 1): 17, - (20, 2): 18, - (20, 3): 10, - (20, 4): 9, - (20, 5): 13, - (20, 6): 14, - (20, 7): 23, - (20, 8): 12, - (20, 9): 4, - (20, 10): 3, - (20, 11): 19, - (20, 12): 8, - (20, 13): 5, - (20, 14): 6, - (20, 15): 22, - (20, 16): 21, - (20, 17): 1, - (20, 18): 2, - (20, 19): 11, - (20, 20): 0, - (20, 21): 16, - (20, 22): 15, - (20, 23): 7, - (21, 0): 21, - (21, 1): 16, - (21, 2): 19, - (21, 3): 11, - (21, 4): 8, - (21, 5): 12, - (21, 6): 15, - (21, 7): 22, - (21, 8): 13, - (21, 9): 5, - (21, 10): 2, - (21, 11): 18, - (21, 12): 9, - (21, 13): 4, - (21, 14): 7, - (21, 15): 23, - (21, 16): 20, - (21, 17): 0, - (21, 18): 3, - (21, 19): 10, - (21, 20): 1, - (21, 21): 17, - (21, 22): 14, - (21, 23): 6, - (22, 0): 22, - (22, 1): 3, - (22, 2): 5, - (22, 3): 7, - (22, 4): 0, - (22, 5): 14, - (22, 6): 16, - (22, 7): 9, - (22, 8): 11, - (22, 9): 1, - (22, 10): 6, - (22, 11): 20, - (22, 12): 10, - (22, 13): 15, - (22, 14): 17, - (22, 15): 19, - (22, 16): 12, - (22, 17): 2, - (22, 18): 4, - (22, 19): 21, - (22, 20): 23, - (22, 21): 13, - (22, 22): 18, - (22, 23): 8, - (23, 0): 23, - (23, 1): 2, - (23, 2): 4, - (23, 3): 6, - (23, 4): 1, - (23, 5): 15, - (23, 6): 17, - (23, 7): 8, - (23, 8): 10, - (23, 9): 0, - (23, 10): 7, - (23, 11): 21, - (23, 12): 11, - (23, 13): 14, - (23, 14): 16, - (23, 15): 18, - (23, 16): 13, - (23, 17): 3, - (23, 18): 5, - (23, 19): 20, - (23, 20): 22, - (23, 21): 12, - (23, 22): 19, - (23, 23): 9, - } + (0, 0): 0, + (0, 1): 1, + (0, 2): 2, + (0, 3): 3, + (0, 4): 4, + (0, 5): 5, + (0, 6): 6, + (0, 7): 7, + (0, 8): 8, + (0, 9): 9, + (0, 10): 10, + (0, 11): 11, + (0, 12): 12, + (0, 13): 13, + (0, 14): 14, + (0, 15): 15, + (0, 16): 16, + (0, 17): 17, + (0, 18): 18, + (0, 19): 19, + (0, 20): 20, + (0, 21): 21, + (0, 22): 22, + (0, 23): 23, + (1, 0): 1, + (1, 1): 0, + (1, 2): 3, + (1, 3): 2, + (1, 4): 5, + (1, 5): 4, + (1, 6): 7, + (1, 7): 6, + (1, 8): 9, + (1, 9): 8, + (1, 10): 11, + (1, 11): 10, + (1, 12): 13, + (1, 13): 12, + (1, 14): 15, + (1, 15): 14, + (1, 16): 17, + (1, 17): 16, + (1, 18): 19, + (1, 19): 18, + (1, 20): 21, + (1, 21): 20, + (1, 22): 23, + (1, 23): 22, + (2, 0): 2, + (2, 1): 23, + (2, 2): 6, + (2, 3): 4, + (2, 4): 15, + (2, 5): 1, + (2, 6): 8, + (2, 7): 17, + (2, 8): 0, + (2, 9): 10, + (2, 10): 21, + (2, 11): 7, + (2, 12): 14, + (2, 13): 11, + (2, 14): 18, + (2, 15): 16, + (2, 16): 3, + (2, 17): 13, + (2, 18): 20, + (2, 19): 5, + (2, 20): 12, + (2, 21): 22, + (2, 22): 9, + (2, 23): 19, + (3, 0): 3, + (3, 1): 22, + (3, 2): 7, + (3, 3): 5, + (3, 4): 14, + (3, 5): 0, + (3, 6): 9, + (3, 7): 16, + (3, 8): 1, + (3, 9): 11, + (3, 10): 20, + (3, 11): 6, + (3, 12): 15, + (3, 13): 10, + (3, 14): 19, + (3, 15): 17, + (3, 16): 2, + (3, 17): 12, + (3, 18): 21, + (3, 19): 4, + (3, 20): 13, + (3, 21): 23, + (3, 22): 8, + (3, 23): 18, + (4, 0): 4, + (4, 1): 9, + (4, 2): 17, + (4, 3): 1, + (4, 4): 18, + (4, 5): 2, + (4, 6): 10, + (4, 7): 3, + (4, 8): 23, + (4, 9): 7, + (4, 10): 12, + (4, 11): 8, + (4, 12): 16, + (4, 13): 21, + (4, 14): 5, + (4, 15): 13, + (4, 16): 6, + (4, 17): 14, + (4, 18): 22, + (4, 19): 15, + (4, 20): 11, + (4, 21): 19, + (4, 22): 0, + (4, 23): 20, + (5, 0): 5, + (5, 1): 8, + (5, 2): 16, + (5, 3): 0, + (5, 4): 19, + (5, 5): 3, + (5, 6): 11, + (5, 7): 2, + (5, 8): 22, + (5, 9): 6, + (5, 10): 13, + (5, 11): 9, + (5, 12): 17, + (5, 13): 20, + (5, 14): 4, + (5, 15): 12, + (5, 16): 7, + (5, 17): 15, + (5, 18): 23, + (5, 19): 14, + (5, 20): 10, + (5, 21): 18, + (5, 22): 1, + (5, 23): 21, + (6, 0): 6, + (6, 1): 19, + (6, 2): 8, + (6, 3): 15, + (6, 4): 16, + (6, 5): 23, + (6, 6): 0, + (6, 7): 13, + (6, 8): 2, + (6, 9): 21, + (6, 10): 22, + (6, 11): 17, + (6, 12): 18, + (6, 13): 7, + (6, 14): 20, + (6, 15): 3, + (6, 16): 4, + (6, 17): 11, + (6, 18): 12, + (6, 19): 1, + (6, 20): 14, + (6, 21): 9, + (6, 22): 10, + (6, 23): 5, + (7, 0): 7, + (7, 1): 18, + (7, 2): 9, + (7, 3): 14, + (7, 4): 17, + (7, 5): 22, + (7, 6): 1, + (7, 7): 12, + (7, 8): 3, + (7, 9): 20, + (7, 10): 23, + (7, 11): 16, + (7, 12): 19, + (7, 13): 6, + (7, 14): 21, + (7, 15): 2, + (7, 16): 5, + (7, 17): 10, + (7, 18): 13, + (7, 19): 0, + (7, 20): 15, + (7, 21): 8, + (7, 22): 11, + (7, 23): 4, + (8, 0): 8, + (8, 1): 5, + (8, 2): 0, + (8, 3): 16, + (8, 4): 3, + (8, 5): 19, + (8, 6): 2, + (8, 7): 11, + (8, 8): 6, + (8, 9): 22, + (8, 10): 9, + (8, 11): 13, + (8, 12): 20, + (8, 13): 17, + (8, 14): 12, + (8, 15): 4, + (8, 16): 15, + (8, 17): 7, + (8, 18): 14, + (8, 19): 23, + (8, 20): 18, + (8, 21): 10, + (8, 22): 21, + (8, 23): 1, + (9, 0): 9, + (9, 1): 4, + (9, 2): 1, + (9, 3): 17, + (9, 4): 2, + (9, 5): 18, + (9, 6): 3, + (9, 7): 10, + (9, 8): 7, + (9, 9): 23, + (9, 10): 8, + (9, 11): 12, + (9, 12): 21, + (9, 13): 16, + (9, 14): 13, + (9, 15): 5, + (9, 16): 14, + (9, 17): 6, + (9, 18): 15, + (9, 19): 22, + (9, 20): 19, + (9, 21): 11, + (9, 22): 20, + (9, 23): 0, + (10, 0): 10, + (10, 1): 15, + (10, 2): 23, + (10, 3): 13, + (10, 4): 6, + (10, 5): 20, + (10, 6): 4, + (10, 7): 21, + (10, 8): 17, + (10, 9): 19, + (10, 10): 0, + (10, 11): 14, + (10, 12): 22, + (10, 13): 3, + (10, 14): 11, + (10, 15): 1, + (10, 16): 18, + (10, 17): 8, + (10, 18): 16, + (10, 19): 9, + (10, 20): 5, + (10, 21): 7, + (10, 22): 12, + (10, 23): 2, + (11, 0): 11, + (11, 1): 14, + (11, 2): 22, + (11, 3): 12, + (11, 4): 7, + (11, 5): 21, + (11, 6): 5, + (11, 7): 20, + (11, 8): 16, + (11, 9): 18, + (11, 10): 1, + (11, 11): 15, + (11, 12): 23, + (11, 13): 2, + (11, 14): 10, + (11, 15): 0, + (11, 16): 19, + (11, 17): 9, + (11, 18): 17, + (11, 19): 8, + (11, 20): 4, + (11, 21): 6, + (11, 22): 13, + (11, 23): 3, + (12, 0): 12, + (12, 1): 13, + (12, 2): 20, + (12, 3): 21, + (12, 4): 10, + (12, 5): 11, + (12, 6): 18, + (12, 7): 19, + (12, 8): 14, + (12, 9): 15, + (12, 10): 4, + (12, 11): 5, + (12, 12): 0, + (12, 13): 1, + (12, 14): 8, + (12, 15): 9, + (12, 16): 22, + (12, 17): 23, + (12, 18): 6, + (12, 19): 7, + (12, 20): 2, + (12, 21): 3, + (12, 22): 16, + (12, 23): 17, + (13, 0): 13, + (13, 1): 12, + (13, 2): 21, + (13, 3): 20, + (13, 4): 11, + (13, 5): 10, + (13, 6): 19, + (13, 7): 18, + (13, 8): 15, + (13, 9): 14, + (13, 10): 5, + (13, 11): 4, + (13, 12): 1, + (13, 13): 0, + (13, 14): 9, + (13, 15): 8, + (13, 16): 23, + (13, 17): 22, + (13, 18): 7, + (13, 19): 6, + (13, 20): 3, + (13, 21): 2, + (13, 22): 17, + (13, 23): 16, + (14, 0): 14, + (14, 1): 11, + (14, 2): 12, + (14, 3): 22, + (14, 4): 21, + (14, 5): 7, + (14, 6): 20, + (14, 7): 5, + (14, 8): 18, + (14, 9): 16, + (14, 10): 15, + (14, 11): 1, + (14, 12): 2, + (14, 13): 23, + (14, 14): 0, + (14, 15): 10, + (14, 16): 9, + (14, 17): 19, + (14, 18): 8, + (14, 19): 17, + (14, 20): 6, + (14, 21): 4, + (14, 22): 3, + (14, 23): 13, + (15, 0): 15, + (15, 1): 10, + (15, 2): 13, + (15, 3): 23, + (15, 4): 20, + (15, 5): 6, + (15, 6): 21, + (15, 7): 4, + (15, 8): 19, + (15, 9): 17, + (15, 10): 14, + (15, 11): 0, + (15, 12): 3, + (15, 13): 22, + (15, 14): 1, + (15, 15): 11, + (15, 16): 8, + (15, 17): 18, + (15, 18): 9, + (15, 19): 16, + (15, 20): 7, + (15, 21): 5, + (15, 22): 2, + (15, 23): 12, + (16, 0): 16, + (16, 1): 21, + (16, 2): 11, + (16, 3): 19, + (16, 4): 12, + (16, 5): 8, + (16, 6): 22, + (16, 7): 15, + (16, 8): 5, + (16, 9): 13, + (16, 10): 18, + (16, 11): 2, + (16, 12): 4, + (16, 13): 9, + (16, 14): 23, + (16, 15): 7, + (16, 16): 0, + (16, 17): 20, + (16, 18): 10, + (16, 19): 3, + (16, 20): 17, + (16, 21): 1, + (16, 22): 6, + (16, 23): 14, + (17, 0): 17, + (17, 1): 20, + (17, 2): 10, + (17, 3): 18, + (17, 4): 13, + (17, 5): 9, + (17, 6): 23, + (17, 7): 14, + (17, 8): 4, + (17, 9): 12, + (17, 10): 19, + (17, 11): 3, + (17, 12): 5, + (17, 13): 8, + (17, 14): 22, + (17, 15): 6, + (17, 16): 1, + (17, 17): 21, + (17, 18): 11, + (17, 19): 2, + (17, 20): 16, + (17, 21): 0, + (17, 22): 7, + (17, 23): 15, + (18, 0): 18, + (18, 1): 7, + (18, 2): 14, + (18, 3): 9, + (18, 4): 22, + (18, 5): 17, + (18, 6): 12, + (18, 7): 1, + (18, 8): 20, + (18, 9): 3, + (18, 10): 16, + (18, 11): 23, + (18, 12): 6, + (18, 13): 19, + (18, 14): 2, + (18, 15): 21, + (18, 16): 10, + (18, 17): 5, + (18, 18): 0, + (18, 19): 13, + (18, 20): 8, + (18, 21): 15, + (18, 22): 4, + (18, 23): 11, + (19, 0): 19, + (19, 1): 6, + (19, 2): 15, + (19, 3): 8, + (19, 4): 23, + (19, 5): 16, + (19, 6): 13, + (19, 7): 0, + (19, 8): 21, + (19, 9): 2, + (19, 10): 17, + (19, 11): 22, + (19, 12): 7, + (19, 13): 18, + (19, 14): 3, + (19, 15): 20, + (19, 16): 11, + (19, 17): 4, + (19, 18): 1, + (19, 19): 12, + (19, 20): 9, + (19, 21): 14, + (19, 22): 5, + (19, 23): 10, + (20, 0): 20, + (20, 1): 17, + (20, 2): 18, + (20, 3): 10, + (20, 4): 9, + (20, 5): 13, + (20, 6): 14, + (20, 7): 23, + (20, 8): 12, + (20, 9): 4, + (20, 10): 3, + (20, 11): 19, + (20, 12): 8, + (20, 13): 5, + (20, 14): 6, + (20, 15): 22, + (20, 16): 21, + (20, 17): 1, + (20, 18): 2, + (20, 19): 11, + (20, 20): 0, + (20, 21): 16, + (20, 22): 15, + (20, 23): 7, + (21, 0): 21, + (21, 1): 16, + (21, 2): 19, + (21, 3): 11, + (21, 4): 8, + (21, 5): 12, + (21, 6): 15, + (21, 7): 22, + (21, 8): 13, + (21, 9): 5, + (21, 10): 2, + (21, 11): 18, + (21, 12): 9, + (21, 13): 4, + (21, 14): 7, + (21, 15): 23, + (21, 16): 20, + (21, 17): 0, + (21, 18): 3, + (21, 19): 10, + (21, 20): 1, + (21, 21): 17, + (21, 22): 14, + (21, 23): 6, + (22, 0): 22, + (22, 1): 3, + (22, 2): 5, + (22, 3): 7, + (22, 4): 0, + (22, 5): 14, + (22, 6): 16, + (22, 7): 9, + (22, 8): 11, + (22, 9): 1, + (22, 10): 6, + (22, 11): 20, + (22, 12): 10, + (22, 13): 15, + (22, 14): 17, + (22, 15): 19, + (22, 16): 12, + (22, 17): 2, + (22, 18): 4, + (22, 19): 21, + (22, 20): 23, + (22, 21): 13, + (22, 22): 18, + (22, 23): 8, + (23, 0): 23, + (23, 1): 2, + (23, 2): 4, + (23, 3): 6, + (23, 4): 1, + (23, 5): 15, + (23, 6): 17, + (23, 7): 8, + (23, 8): 10, + (23, 9): 0, + (23, 10): 7, + (23, 11): 21, + (23, 12): 11, + (23, 13): 14, + (23, 14): 16, + (23, 15): 18, + (23, 16): 13, + (23, 17): 3, + (23, 18): 5, + (23, 19): 20, + (23, 20): 22, + (23, 21): 12, + (23, 22): 19, + (23, 23): 9, +} +# In CLIFF_INVERSE_DATA, i: j represents Clifford(i).inverse = Clifford(j) CLIFF_INVERSE_DATA = { - 0: 0, - 1: 1, - 2: 8, - 3: 5, - 4: 22, - 5: 3, - 6: 6, - 7: 19, - 8: 2, - 9: 23, - 10: 10, - 11: 15, - 12: 12, - 13: 13, - 14: 14, - 15: 11, - 16: 16, - 17: 21, - 18: 18, - 19: 7, - 20: 20, - 21: 17, - 22: 4, - 23: 9, - } + 0: 0, + 1: 1, + 2: 8, + 3: 5, + 4: 22, + 5: 3, + 6: 6, + 7: 19, + 8: 2, + 9: 23, + 10: 10, + 11: 15, + 12: 12, + 13: 13, + 14: 14, + 15: 11, + 16: 16, + 17: 21, + 18: 18, + 19: 7, + 20: 20, + 21: 17, + 22: 4, + 23: 9, +} diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index bee0e31c2e..b56c456a28 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -14,7 +14,7 @@ """ from typing import Union, Iterable, Optional, List, Sequence -from numpy.random import Generator +from numpy.random import Generator, default_rng from numpy.random.bit_generator import BitGenerator, SeedSequence from qiskit import QuantumCircuit @@ -57,6 +57,7 @@ def __init__( num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: bool = False, + transpiled_rb = False ): """Initialize an interleaved randomized benchmarking experiment. @@ -84,10 +85,31 @@ def __init__( num_samples=num_samples, seed=seed, full_sampling=full_sampling, + transpiled_rb=transpiled_rb ) self.analysis = InterleavedRBAnalysis() self.analysis.set_options(outcome="0" * self.num_qubits) + def circuits(self) -> List[QuantumCircuit]: + """Return a list of RB circuits. + + Returns: + A list of :class:`QuantumCircuit`. + """ + rng = default_rng(seed=self.experiment_options.seed) + circuits = [] + + for _ in range(self.experiment_options.num_samples): + if self.num_qubits == 1 and self._transpiled_rb: + std_circuits, int_circuits = self._build_rb_circuits(self.experiment_options.lengths, rng, + is_interleaved=True, + interleaved_element=self._interleaved_element) + circuits += std_circuits + circuits += int_circuits + else: + circuits += self._sample_circuits(self.experiment_options.lengths, rng) + return circuits + def _sample_circuits(self, lengths, rng): circuits = [] for length in lengths if self._full_sampling else [lengths[-1]]: diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 2fbcba2da4..8329895160 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -23,6 +23,7 @@ from qiskit import QuantumCircuit, QuantumRegister, QiskitError from qiskit.circuit import Instruction +#from qiskit.circuit.library import XGate from qiskit.circuit.quantumregister import Qubit from qiskit.quantum_info import Clifford from qiskit.providers.backend import Backend @@ -220,7 +221,8 @@ def _generate_circuit( circuits.append(rb_circ) return circuits - def _build_rb_circuits(self, lengths, rng): + def _build_rb_circuits(self, lengths, rng, is_interleaved=False, + interleaved_element=None): """ build_rb_circuits Args: @@ -233,17 +235,32 @@ def _build_rb_circuits(self, lengths, rng): when performed on the integers rather than on the Cliffords themselves. """ if self._full_sampling: - return self._build_rb_circuits_full_sampling(lengths, rng) + return self._build_rb_circuits_full_sampling(lengths, rng, is_interleaved, + interleaved_element) - all_rb_circuits = [] - random_samples = rng.integers(24, size=lengths[-1]) max_qubit = max(self.physical_qubits) + 1 + all_rb_circuits = [] + if is_interleaved: + all_rb_interleaved_circuits = [] + else: + all_rb_interleaved_circuits = None # When full_sampling==False, each circuit is the prefix of the next circuit (without the # inverse Clifford at the end of the circuit. The variable 'circ' will contain the growing circuit. # When each circuit reaches its length, we copy it to rb_circ, append the inverse, # and add it to the list of circuits. + + if is_interleaved: + interleaved_circ = QuantumCircuit(max_qubit, 1) + interleaved_circ.barrier(0) + else: + interleaved_circ = None + + random_samples = rng.integers(24, size=lengths[-1]) + circ = QuantumCircuit(max_qubit, 1) + circ.barrier(0) + clifford_as_num = 0 # 0 is the Clifford that is Id prev_length = 0 @@ -254,6 +271,12 @@ def _build_rb_circuits(self, lengths, rng): next_circ = self._transpiled_cliff_circuits[rand] circ.compose(next_circ, inplace=True) circ.barrier(0) + if is_interleaved: + interleaved_circ.compose(next_circ, inplace=True) + interleaved_circ.barrier(0) + interleaved_circ.append(interleaved_element[0], [0]) + interleaved_circ.barrier(0) + clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] if i == length-1: rb_circ = circ.copy() # circ is used as the prefix of the next circuit @@ -267,18 +290,49 @@ def _build_rb_circuits(self, lengths, rng): "xval": length, "group": "Clifford", "physical_qubits": self.physical_qubits, + "interleaved" : False } all_rb_circuits.append(rb_circ) + if is_interleaved: + rb_interleaved_circ = interleaved_circ.copy() # interleaved_circ is used as the prefix of the next circuit + # append the inverse + rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) + rb_interleaved_circ.append(interleaved_element[0], [0]) + rb_interleaved_circ.barrier(0) + rb_interleaved_circ.measure(0, 0) + + rb_interleaved_circ.metadata = { + "experiment_type": "rb", + "xval": length, + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "interleaved": True, + } + all_rb_interleaved_circuits.append(rb_interleaved_circ) + prev_length = i + 1 - return all_rb_circuits + return all_rb_circuits, all_rb_interleaved_circuits - def _build_rb_circuits_full_sampling(self, lengths, rng): + def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, + interleaved_element=None): all_rb_circuits = [] + if is_interleaved: + all_rb_interleaved_circuits = [] + else: + all_rb_interleaved_circuits = None + max_qubit = max(self.physical_qubits) + 1 for length in lengths: # We define the circuit size here, for the layout that will # be created later rb_circ = QuantumCircuit(max_qubit, 1) + rb_circ.barrier(0) + if is_interleaved: + rb_interleaved_circ = QuantumCircuit(max_qubit, 1) + rb_interleaved_circ.barrier(0) + else: + rb_interleaved_circ = None + random_samples = rng.integers(24, size=length) # For full_sampling, we create each circuit independently. clifford_as_num = 0 @@ -286,24 +340,44 @@ def _build_rb_circuits_full_sampling(self, lengths, rng): # choose random clifford rand = random_samples[i] next_circ = self._transpiled_cliff_circuits[rand].copy() - rb_circ.compose(next_circ, inplace=True) rb_circ.barrier(0) + if is_interleaved: + rb_interleaved_circ.compose(next_circ, inplace=True) + rb_interleaved_circ.barrier(0) + + rb_interleaved_circ.append(interleaved_element[0], [0]) + rb_interleaved_circ.barrier(0) + clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] # append the inverse rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) rb_circ.measure(0, 0) + if is_interleaved: + rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) + rb_interleaved_circ.append(interleaved_element[0], [0]) + rb_interleaved_circ.measure(0, 0) rb_circ.metadata = { "experiment_type": "rb", "xval": length, "group": "Clifford", "physical_qubits": self.physical_qubits, + "interleaved" : False, + } + rb_interleaved_circ.metadata = { + "experiment_type": "rb", + "xval": length, + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "interleaved" : True, } all_rb_circuits.append(rb_circ) - return all_rb_circuits + if is_interleaved: + all_rb_interleaved_circuits.append(rb_interleaved_circ) + return all_rb_circuits, all_rb_interleaved_circuits # This method does a quick layout to avoid calling 'transpile()' which is # very costly in performance diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index d88cff9ed2..a172b277a8 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -320,29 +320,37 @@ def test_interleaved_structure(self, interleaved_element, qubits, length): identical to the original circuit up to additions of barrier and interleaved element between any two Cliffords. """ - exp = rb.InterleavedRB( - interleaved_element=interleaved_element, qubits=qubits, lengths=[length], num_samples=1 - ) + full_sampling =[True, False] + for val in full_sampling: + exp = rb.InterleavedRB( + interleaved_element=interleaved_element, qubits=qubits, lengths=[length], + num_samples=1, full_sampling=val, transpiled_rb=True + ) - circuits = exp.circuits() - c_std = circuits[0] - c_int = circuits[1] - if c_std.metadata["interleaved"]: - c_std, c_int = c_int, c_std - num_cliffords = c_std.metadata["xval"] - std_idx = 0 - int_idx = 0 - for _ in range(num_cliffords): - # barrier - self.assertEqual(c_std[std_idx][0].name, "barrier") - self.assertEqual(c_int[int_idx][0].name, "barrier") - # clifford - self.assertEqual(c_std[std_idx + 1], c_int[int_idx + 1]) - # for interleaved circuit: barrier + interleaved element - self.assertEqual(c_int[int_idx + 2][0].name, "barrier") - self.assertEqual(c_int[int_idx + 3][0].name, interleaved_element.name) - std_idx += 2 - int_idx += 4 + circuits = exp.circuits() + c_std = circuits[0] + c_int = circuits[1] + if c_std.metadata["interleaved"]: + c_std, c_int = c_int, c_std + num_cliffords = c_std.metadata["xval"] + std_idx = 0 + int_idx = 0 + for _ in range(num_cliffords): + # barrier + self.assertEqual(c_std[std_idx][0].name, "barrier") + self.assertEqual(c_int[int_idx][0].name, "barrier") + # clifford + std_idx += 1 + int_idx += 1 + while c_std[std_idx][0].name != "barrier": + self.assertEqual(c_std[std_idx], c_int[int_idx]) + std_idx += 1 + int_idx += 1 + # for interleaved circuit: barrier + interleaved element + self.assertEqual(c_int[int_idx][0].name, "barrier") + int_idx += 1 + self.assertEqual(c_int[int_idx][0].name, interleaved_element.name) + int_idx += 1 def test_single_qubit(self): """Test single qubit IRB.""" From f899247c5395ae0a405c7d51e681ab0a1d61d412 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 21 Jun 2022 18:53:28 +0300 Subject: [PATCH 21/39] Fixed handling of interleaved element --- .../randomized_benchmarking/clifford_utils.py | 27 ++++++++++++++- .../randomized_benchmarking/rb_experiment.py | 34 +++++++++++-------- .../test_randomized_benchmarking.py | 9 +++-- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 0d310fc60c..347240cddb 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -18,10 +18,11 @@ from numpy.random import Generator, default_rng from qiskit import QuantumCircuit, QuantumRegister from qiskit.circuit import Gate -from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate +from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate, XGate, YGate, ZGate from qiskit.quantum_info import Clifford, random_clifford from qiskit.compiler import transpile from qiskit.providers.aer import AerSimulator +from qiskit.exceptions import QiskitError class VGate(Gate): @@ -236,3 +237,27 @@ def generate_1q_transpiled_clifford_circuits(basis_gates : List[str]): transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=basis_gates) transpiled_circs.append(transpiled_circ) return transpiled_circs + + + def num_from_1_qubit_clifford(self, name): + """ + This method does the reverse of clifford_1_qubit_circuit - + given a clifford, it returns the corresponding integer. + """ + if name == "H" or name == "h": + return 1 + if name == "SXdg" or name == "sxdg": + return 2 + if name == "S" or name == "s": + return 4 + if name == "X" or name == "x": + return 6 + if name == "SX" or name == "sx": + return 8 + if name == "Y" or name == "y": + return 12 + if name == "Z" or name == "z": + return 18 + raise QiskitError( + "Instruction {} could not be converted to Clifford gate".format(name) + ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 8329895160..25a479b4fc 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -100,7 +100,7 @@ def __init__( start = time.time() basis_gates = ["rz", "sx", "cx"] self._transpiled_cliff_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) - + def _verify_parameters(self, lengths, num_samples): """Verify input correctness, raise QiskitError if needed""" if any(length <= 0 for length in lengths): @@ -242,6 +242,7 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, all_rb_circuits = [] if is_interleaved: all_rb_interleaved_circuits = [] + interleaved_elem_num = self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0].name) else: all_rb_interleaved_circuits = None @@ -257,11 +258,11 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, interleaved_circ = None random_samples = rng.integers(24, size=lengths[-1]) - circ = QuantumCircuit(max_qubit, 1) circ.barrier(0) - clifford_as_num = 0 # 0 is the Clifford that is Id + composed_cliff_num = 0 # 0 is the Clifford that is Id + composed_interleaved_num = 0 prev_length = 0 for length in lengths: @@ -270,17 +271,19 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, # choose random clifford next_circ = self._transpiled_cliff_circuits[rand] circ.compose(next_circ, inplace=True) + composed_cliff_num = CLIFF_COMPOSE_DATA[(composed_cliff_num, rand)] circ.barrier(0) if is_interleaved: interleaved_circ.compose(next_circ, inplace=True) + composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, rand)] interleaved_circ.barrier(0) interleaved_circ.append(interleaved_element[0], [0]) + composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, interleaved_elem_num)] interleaved_circ.barrier(0) - clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] if i == length-1: rb_circ = circ.copy() # circ is used as the prefix of the next circuit - inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] + inverse_clifford_num = CLIFF_INVERSE_DATA[composed_cliff_num] # append the inverse rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) rb_circ.measure(0, 0) @@ -296,9 +299,8 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, if is_interleaved: rb_interleaved_circ = interleaved_circ.copy() # interleaved_circ is used as the prefix of the next circuit # append the inverse - rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) - rb_interleaved_circ.append(interleaved_element[0], [0]) - rb_interleaved_circ.barrier(0) + inverse_interleaved_num = CLIFF_INVERSE_DATA[composed_interleaved_num] + rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True) rb_interleaved_circ.measure(0, 0) rb_interleaved_circ.metadata = { @@ -318,6 +320,7 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, all_rb_circuits = [] if is_interleaved: all_rb_interleaved_circuits = [] + interleaved_elem_num = self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0].name) else: all_rb_interleaved_circuits = None @@ -335,29 +338,30 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, random_samples = rng.integers(24, size=length) # For full_sampling, we create each circuit independently. - clifford_as_num = 0 + composed_cliff_num = 0 + composed_interleaved_num = 0 for i in range(length): # choose random clifford rand = random_samples[i] next_circ = self._transpiled_cliff_circuits[rand].copy() rb_circ.compose(next_circ, inplace=True) + composed_cliff_num = CLIFF_COMPOSE_DATA[(composed_cliff_num, rand)] rb_circ.barrier(0) if is_interleaved: rb_interleaved_circ.compose(next_circ, inplace=True) + composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, rand)] rb_interleaved_circ.barrier(0) - rb_interleaved_circ.append(interleaved_element[0], [0]) + composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, interleaved_elem_num)] rb_interleaved_circ.barrier(0) - clifford_as_num = CLIFF_COMPOSE_DATA[(clifford_as_num, rand)] - - inverse_clifford_num = CLIFF_INVERSE_DATA[clifford_as_num] + inverse_clifford_num = CLIFF_INVERSE_DATA[composed_cliff_num] # append the inverse rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) rb_circ.measure(0, 0) if is_interleaved: - rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) - rb_interleaved_circ.append(interleaved_element[0], [0]) + inverse_interleaved_num = CLIFF_INVERSE_DATA[composed_interleaved_num] + rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True) rb_interleaved_circ.measure(0, 0) rb_circ.metadata = { diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index a172b277a8..52cd25e96d 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -17,7 +17,7 @@ import numpy as np from ddt import ddt, data, unpack from qiskit.circuit import Delay, QuantumCircuit -from qiskit.circuit.library import SXGate, CXGate, TGate, XGate +from qiskit.circuit.library import SXGate, CXGate, TGate, XGate, YGate, ZGate, HGate, SGate from qiskit.exceptions import QiskitError from qiskit.providers.aer import AerSimulator from qiskit.providers.aer.noise import NoiseModel, depolarizing_error @@ -360,6 +360,7 @@ def test_single_qubit(self): lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, + transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) self.assertAllIdentity(exp.circuits()) @@ -414,6 +415,7 @@ def test_interleaving_delay(self): qubits=[0], lengths=[1], num_samples=1, + transpiled_rb=True ) # Not raises an error _, int_circ = exp.circuits() @@ -428,7 +430,7 @@ def test_interleaving_circuit_with_delay(self): delay_qc.x(1) exp = rb.InterleavedRB( - interleaved_element=delay_qc, qubits=[1, 2], lengths=[1], seed=123, num_samples=1 + interleaved_element=delay_qc, qubits=[1, 2], lengths=[1], seed=123, num_samples=1, transpiled_rb=True ) _, int_circ = exp.circuits() @@ -441,7 +443,7 @@ def test_interleaving_circuit_with_delay(self): def test_experiment_config(self): """Test converting to and from config works""" exp = rb.InterleavedRB( - interleaved_element=SXGate(), qubits=(0,), lengths=[10, 20, 30], seed=123 + interleaved_element=SXGate(), qubits=(0,), lengths=[10, 20, 30], seed=123, transpiled_rb=True ) loaded_exp = rb.InterleavedRB.from_config(exp.config()) self.assertNotEqual(exp, loaded_exp) @@ -469,6 +471,7 @@ def test_expdata_serialization(self): lengths=list(range(1, 200, 50)), seed=123, backend=self.backend, + transpiled_rb=True ) exp.set_transpile_options(**self.transpiler_options) expdata = exp.run() From 2bc7469980d30dea313cc9ba03736c5fa925fd42 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 22 Jun 2022 13:41:40 +0300 Subject: [PATCH 22/39] Fixed bug caused by change of interface of _buil_rb_circuits after adding support for interleave --- .../library/randomized_benchmarking/rb_experiment.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 25a479b4fc..769f571244 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -100,7 +100,7 @@ def __init__( start = time.time() basis_gates = ["rz", "sx", "cx"] self._transpiled_cliff_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) - + def _verify_parameters(self, lengths, num_samples): """Verify input correctness, raise QiskitError if needed""" if any(length <= 0 for length in lengths): @@ -144,7 +144,8 @@ def circuits(self) -> List[QuantumCircuit]: circuits = [] for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: - circuits += self._build_rb_circuits(self.experiment_options.lengths, rng) + rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng) + circuits += rb_circuits else: circuits += self._sample_circuits(self.experiment_options.lengths, rng) return circuits From bbaf21840e18cb53285da137ece12cae883f27b9 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Thu, 23 Jun 2022 16:06:07 +0300 Subject: [PATCH 23/39] added test_number_to_clifford_mapping and fixed the method num_from_1_qubit_clifford --- .../randomized_benchmarking/clifford_utils.py | 56 +++++++++++++------ .../randomized_benchmarking/rb_experiment.py | 8 ++- test/randomized_benchmarking/test_rb_utils.py | 32 ++++++++++- 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 347240cddb..4da07d4ccc 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -15,10 +15,11 @@ from typing import Optional, Union, List from functools import lru_cache +import numpy as np from numpy.random import Generator, default_rng from qiskit import QuantumCircuit, QuantumRegister from qiskit.circuit import Gate -from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate, XGate, YGate, ZGate +from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate from qiskit.quantum_info import Clifford, random_clifford from qiskit.compiler import transpile from qiskit.providers.aer import AerSimulator @@ -236,28 +237,49 @@ def generate_1q_transpiled_clifford_circuits(basis_gates : List[str]): for i, circ in enumerate(circs): transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=basis_gates) transpiled_circs.append(transpiled_circ) + print(i) + print(circ) + print(transpiled_circ) + print() return transpiled_circs - def num_from_1_qubit_clifford(self, name): + def num_from_1_qubit_clifford(self, inst, basis_gates): """ This method does the reverse of clifford_1_qubit_circuit - - given a clifford, it returns the corresponding integer. + given a clifford, it returns the corresponding integer, with the mapping + defined in the above method. + The mapping is in the context of the basis_gates. Therefore, we define here + the possible supersets of basis gates, and verify that the given inst belong to + one of these sets. """ - if name == "H" or name == "h": - return 1 - if name == "SXdg" or name == "sxdg": - return 2 - if name == "S" or name == "s": - return 4 - if name == "X" or name == "x": - return 6 - if name == "SX" or name == "sx": - return 8 - if name == "Y" or name == "y": - return 12 - if name == "Z" or name == "z": - return 18 + name = inst.name + general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "y", "z"] + transpiled_cliff_list = ["sx", "rz", "cx"] + + if not name in basis_gates: + raise QiskitError( + "Instruction {} is not in the basis gates".format(inst.name) + ) + if(set(basis_gates).issubset(set(general_cliff_list))): + num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22} + return num_dict[inst.name] + + if (set(basis_gates).issubset(set(transpiled_cliff_list))): + if name == "sx": + return 8 + if name == "rz": + # The next two are identical up to a phase, which makes no difference + # for the associated Cliffords + if inst.params == [np.pi] or inst.params == [-np.pi]: + return 18 + if inst.params == [np.pi / 2]: + return 4 + if inst.params == [-np.pi / 2]: + return 22 + else: + print("wrong param" + str(inst.params)) + raise QiskitError( "Instruction {} could not be converted to Clifford gate".format(name) ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 769f571244..258792c003 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -243,7 +243,9 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, all_rb_circuits = [] if is_interleaved: all_rb_interleaved_circuits = [] - interleaved_elem_num = self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0].name) + interleaved_elem_num = \ + self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0], + self.transpile_options.__dict__["basis_gates"]) else: all_rb_interleaved_circuits = None @@ -321,7 +323,9 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, all_rb_circuits = [] if is_interleaved: all_rb_interleaved_circuits = [] - interleaved_elem_num = self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0].name) + interleaved_elem_num = \ + self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0], + self.transpile_options.__dict__["basis_gates"]) else: all_rb_interleaved_circuits = None diff --git a/test/randomized_benchmarking/test_rb_utils.py b/test/randomized_benchmarking/test_rb_utils.py index c9163e287d..ab7a5aff86 100644 --- a/test/randomized_benchmarking/test_rb_utils.py +++ b/test/randomized_benchmarking/test_rb_utils.py @@ -18,7 +18,8 @@ from uncertainties import ufloat from ddt import ddt, data, unpack -from qiskit import QuantumCircuit +from qiskit import QuantumCircuit, QuantumRegister +from qiskit.quantum_info import Operator from qiskit.circuit.library import ( IGate, XGate, @@ -27,13 +28,16 @@ HGate, SGate, SdgGate, + SXGate, CXGate, CZGate, SwapGate, + RZGate, ) from qiskit.quantum_info import Clifford import qiskit_experiments.library.randomized_benchmarking as rb from qiskit_experiments.framework import AnalysisResultData +from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils @ddt @@ -1014,3 +1018,29 @@ def test_clifford_2_qubit_generation(self): for other_phase in phases: self.assertNotEqual(phase, other_phase) phases.append(phase) + + def test_number_to_clifford_mapping(self): + """ Testing that the methods num_from_1_qubit_clifford and + clifford_1_qubit_circuit perform the reverse operations from + each other""" + transpiled_cliff_list = [SXGate(), RZGate(np.pi), RZGate(-np.pi), + RZGate(np.pi/2), RZGate(-np.pi/2)] + transpiled_cliff_names = [gate.name for gate in transpiled_cliff_list] + utils = CliffordUtils() + for inst in transpiled_cliff_list: + num = utils.num_from_1_qubit_clifford(inst, transpiled_cliff_names) + qc_from_num = utils.clifford_1_qubit_circuit(num=num) + qr = QuantumRegister(1) + qc_from_inst = QuantumCircuit(qr) + qc_from_inst._append(inst, [qr[0]], []) + assert (Operator(qc_from_num).equiv(Operator(qc_from_inst))) + + general_cliff_list = [IGate(), HGate(), SdgGate(), SGate(), XGate(), SXGate(), YGate(), ZGate()] + general_cliff_names = [gate.name for gate in general_cliff_list] + for inst in general_cliff_list: + num = utils.num_from_1_qubit_clifford(inst, general_cliff_names) + qc_from_num = utils.clifford_1_qubit_circuit(num=num) + qr = QuantumRegister(1) + qc_from_inst = QuantumCircuit(qr) + qc_from_inst._append(inst, [qr[0]], []) + assert (Operator(qc_from_num).equiv(Operator(qc_from_inst))) From 402bf6993fd33bf932dd95ab24a60cf5d9aeb4f6 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Thu, 23 Jun 2022 17:56:18 +0300 Subject: [PATCH 24/39] Added support for computation of the Clifford to number mapping of a circuit --- .../randomized_benchmarking/clifford_utils.py | 24 +++++++++++-------- .../randomized_benchmarking/rb_experiment.py | 13 ++++++---- test/randomized_benchmarking/test_rb_utils.py | 20 +++++++++++----- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 4da07d4ccc..199f49ebc4 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -17,12 +17,14 @@ from functools import lru_cache import numpy as np from numpy.random import Generator, default_rng +from math import isclose from qiskit import QuantumCircuit, QuantumRegister from qiskit.circuit import Gate from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate from qiskit.quantum_info import Clifford, random_clifford from qiskit.compiler import transpile from qiskit.providers.aer import AerSimulator +from .clifford_data import CLIFF_COMPOSE_DATA, CLIFF_INVERSE_DATA from qiskit.exceptions import QiskitError @@ -237,14 +239,9 @@ def generate_1q_transpiled_clifford_circuits(basis_gates : List[str]): for i, circ in enumerate(circs): transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=basis_gates) transpiled_circs.append(transpiled_circ) - print(i) - print(circ) - print(transpiled_circ) - print() return transpiled_circs - - def num_from_1_qubit_clifford(self, inst, basis_gates): + def num_from_1_qubit_clifford_single_gate(inst, basis_gates): """ This method does the reverse of clifford_1_qubit_circuit - given a clifford, it returns the corresponding integer, with the mapping @@ -271,15 +268,22 @@ def num_from_1_qubit_clifford(self, inst, basis_gates): if name == "rz": # The next two are identical up to a phase, which makes no difference # for the associated Cliffords - if inst.params == [np.pi] or inst.params == [-np.pi]: + if isclose(inst.params[0], np.pi) or isclose(inst.params[0], -np.pi): return 18 - if inst.params == [np.pi / 2]: + if isclose(inst.params[0], np.pi / 2): return 4 - if inst.params == [-np.pi / 2]: + if isclose(inst.params[0], -np.pi / 2): return 22 else: - print("wrong param" + str(inst.params)) + raise QiskitError("wrong param {} for rz in clifford".format(inst.params[0])) raise QiskitError( "Instruction {} could not be converted to Clifford gate".format(name) ) + + def num_from_1_qubit_clifford(qc, basis_gates): + composed_num = 0 + for inst in qc: + num = CliffordUtils.num_from_1_qubit_clifford_single_gate(inst[0], basis_gates) + composed_num = CLIFF_COMPOSE_DATA[(composed_num, num)] + return composed_num diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 258792c003..9f88e81c6b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -23,7 +23,6 @@ from qiskit import QuantumCircuit, QuantumRegister, QiskitError from qiskit.circuit import Instruction -#from qiskit.circuit.library import XGate from qiskit.circuit.quantumregister import Qubit from qiskit.quantum_info import Clifford from qiskit.providers.backend import Backend @@ -244,8 +243,10 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, if is_interleaved: all_rb_interleaved_circuits = [] interleaved_elem_num = \ - self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0], - self.transpile_options.__dict__["basis_gates"]) + CliffordUtils.num_from_1_qubit_clifford_single_gate( + interleaved_element[0], + self.transpile_options.__dict__["basis_gates"] + ) else: all_rb_interleaved_circuits = None @@ -324,8 +325,10 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, if is_interleaved: all_rb_interleaved_circuits = [] interleaved_elem_num = \ - self._clifford_utils.num_from_1_qubit_clifford(interleaved_element[0], - self.transpile_options.__dict__["basis_gates"]) + CliffordUtils.num_from_1_qubit_clifford_single_gate( + interleaved_element[0], + self.transpile_options.__dict__["basis_gates"] + ) else: all_rb_interleaved_circuits = None diff --git a/test/randomized_benchmarking/test_rb_utils.py b/test/randomized_benchmarking/test_rb_utils.py index ab7a5aff86..9b2c83694c 100644 --- a/test/randomized_benchmarking/test_rb_utils.py +++ b/test/randomized_benchmarking/test_rb_utils.py @@ -1019,17 +1019,16 @@ def test_clifford_2_qubit_generation(self): self.assertNotEqual(phase, other_phase) phases.append(phase) - def test_number_to_clifford_mapping(self): + def test_number_to_clifford_mapping_single_gate(self): """ Testing that the methods num_from_1_qubit_clifford and clifford_1_qubit_circuit perform the reverse operations from each other""" transpiled_cliff_list = [SXGate(), RZGate(np.pi), RZGate(-np.pi), RZGate(np.pi/2), RZGate(-np.pi/2)] transpiled_cliff_names = [gate.name for gate in transpiled_cliff_list] - utils = CliffordUtils() for inst in transpiled_cliff_list: - num = utils.num_from_1_qubit_clifford(inst, transpiled_cliff_names) - qc_from_num = utils.clifford_1_qubit_circuit(num=num) + num = CliffordUtils.num_from_1_qubit_clifford_single_gate(inst, transpiled_cliff_names) + qc_from_num = CliffordUtils.clifford_1_qubit_circuit(num=num) qr = QuantumRegister(1) qc_from_inst = QuantumCircuit(qr) qc_from_inst._append(inst, [qr[0]], []) @@ -1038,9 +1037,18 @@ def test_number_to_clifford_mapping(self): general_cliff_list = [IGate(), HGate(), SdgGate(), SGate(), XGate(), SXGate(), YGate(), ZGate()] general_cliff_names = [gate.name for gate in general_cliff_list] for inst in general_cliff_list: - num = utils.num_from_1_qubit_clifford(inst, general_cliff_names) - qc_from_num = utils.clifford_1_qubit_circuit(num=num) + num = CliffordUtils.num_from_1_qubit_clifford(inst, general_cliff_names) + qc_from_num = CliffordUtils.clifford_1_qubit_circuit(num=num) qr = QuantumRegister(1) qc_from_inst = QuantumCircuit(qr) qc_from_inst._append(inst, [qr[0]], []) assert (Operator(qc_from_num).equiv(Operator(qc_from_inst))) + + def test_number_to_clifford_mapping(self): + transpiled_cliff_list = [SXGate(), RZGate(np.pi), RZGate(-np.pi), + RZGate(np.pi / 2), RZGate(-np.pi / 2)] + transpiled_cliff_names = [gate.name for gate in transpiled_cliff_list] + all_transpiled_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(transpiled_cliff_names) + for index, qc in enumerate(all_transpiled_circuits): + num = CliffordUtils.num_from_1_qubit_clifford(qc, transpiled_cliff_names) + assert(num == index) From 67f07ca24eb79bdef02fa57516071af9c8976ce8 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 26 Jun 2022 12:07:02 +0300 Subject: [PATCH 25/39] Moved setting of interleaved metadata to be under 'if is_interleaved' --- .../randomized_benchmarking/rb_experiment.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 9f88e81c6b..05e8665b47 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -367,25 +367,24 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, # append the inverse rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) rb_circ.measure(0, 0) - if is_interleaved: - inverse_interleaved_num = CLIFF_INVERSE_DATA[composed_interleaved_num] - rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True) - rb_interleaved_circ.measure(0, 0) - rb_circ.metadata = { "experiment_type": "rb", "xval": length, "group": "Clifford", "physical_qubits": self.physical_qubits, - "interleaved" : False, - } - rb_interleaved_circ.metadata = { - "experiment_type": "rb", - "xval": length, - "group": "Clifford", - "physical_qubits": self.physical_qubits, - "interleaved" : True, + "interleaved": False, } + if is_interleaved: + inverse_interleaved_num = CLIFF_INVERSE_DATA[composed_interleaved_num] + rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True) + rb_interleaved_circ.measure(0, 0) + rb_interleaved_circ.metadata = { + "experiment_type": "rb", + "xval": length, + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "interleaved" : True, + } all_rb_circuits.append(rb_circ) if is_interleaved: all_rb_interleaved_circuits.append(rb_interleaved_circ) From d72beb168a79f4b72a767fb039d9edcf501d3572 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 26 Jun 2022 21:35:55 +0300 Subject: [PATCH 26/39] Added transpilation of interleaved element before creating the rb circuits. Transformed interleaved element into a transpiled clifford circuit. Added relevant tests --- .../randomized_benchmarking/clifford_utils.py | 12 ++-- .../interleaved_rb_experiment.py | 30 +++++++++- .../randomized_benchmarking/rb_experiment.py | 17 +++--- .../test_randomized_benchmarking.py | 56 +++++++++++++------ 4 files changed, 81 insertions(+), 34 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 199f49ebc4..85a63c20ab 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -19,7 +19,7 @@ from numpy.random import Generator, default_rng from math import isclose from qiskit import QuantumCircuit, QuantumRegister -from qiskit.circuit import Gate +from qiskit.circuit import Gate, Instruction from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate from qiskit.quantum_info import Clifford, random_clifford from qiskit.compiler import transpile @@ -226,13 +226,16 @@ def _unpack_num_multi_sigs(self, num, sigs): num -= sig_size return None + def transpile_single_clifford(cliff_circ, basis_gates : List[str]): + backend = AerSimulator() + return transpile(cliff_circ, backend, optimization_level=1, basis_gates=basis_gates) + def generate_1q_transpiled_clifford_circuits(basis_gates : List[str]): utils = CliffordUtils() circs = [] for num in range(0, 24): circ = utils.clifford_1_qubit_circuit(num=num) circs.append(circ) - backend = AerSimulator() transpiled_circs = [] @@ -260,7 +263,7 @@ def num_from_1_qubit_clifford_single_gate(inst, basis_gates): ) if(set(basis_gates).issubset(set(general_cliff_list))): num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22} - return num_dict[inst.name] + return num_dict[name] if (set(basis_gates).issubset(set(transpiled_cliff_list))): if name == "sx": @@ -281,7 +284,8 @@ def num_from_1_qubit_clifford_single_gate(inst, basis_gates): "Instruction {} could not be converted to Clifford gate".format(name) ) - def num_from_1_qubit_clifford(qc, basis_gates): + def num_from_1_qubit_clifford(qc: QuantumCircuit, + basis_gates: List[str]) -> int: composed_num = 0 for inst in qc: num = CliffordUtils.num_from_1_qubit_clifford_single_gate(inst[0], basis_gates) diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index b56c456a28..a713c71ca8 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -22,7 +22,9 @@ from qiskit.quantum_info import Clifford from qiskit.exceptions import QiskitError from qiskit.providers.backend import Backend +from qiskit.compiler import transpile +from .clifford_utils import CliffordUtils from .rb_experiment import StandardRB from .interleaved_rb_analysis import InterleavedRBAnalysis @@ -77,7 +79,7 @@ def __init__( sequences are constructed by appending additional Clifford samples to shorter sequences. """ - self._set_interleaved_element(interleaved_element) + super().__init__( qubits, lengths, @@ -87,6 +89,7 @@ def __init__( full_sampling=full_sampling, transpiled_rb=transpiled_rb ) + self._set_interleaved_element(interleaved_element) self.analysis = InterleavedRBAnalysis() self.analysis.set_options(outcome="0" * self.num_qubits) @@ -98,12 +101,12 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] - for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: + self._set_transpiled_interleaved_element() std_circuits, int_circuits = self._build_rb_circuits(self.experiment_options.lengths, rng, is_interleaved=True, - interleaved_element=self._interleaved_element) + interleaved_element=self._transpiled_interleaved_elem) circuits += std_circuits circuits += int_circuits else: @@ -138,6 +141,7 @@ def _interleave(self, element_list: List) -> List: Returns: The new list with the element interleaved. """ + new_element_list = [] for element in element_list: new_element_list.append(element) @@ -163,3 +167,23 @@ def _set_interleaved_element(self, interleaved_element): interleaved_element.name ) ) from error + + def _set_transpiled_interleaved_element(self): + """ + Create the transpiled interleaved element. If it is a single gate, + create a circuit comprising this gate. + """ + if not isinstance(self._interleaved_element, QuantumCircuit): + qc_interleaved = QuantumCircuit(1) + qc_interleaved.append(self._interleaved_element[0], [0], []) + self._transpiled_interleaved_elem = self._interleaved_element + else: + qc_interleaved = self._interleaved_element + if hasattr(self.transpile_options, "basis_gates"): + basis_gates = self.transpile_options.basis_gates + else: + basis_gates = None + self._transpiled_interleaved_elem = CliffordUtils.transpile_single_clifford( + qc_interleaved, + basis_gates = basis_gates + ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 05e8665b47..62d46a3d22 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -96,7 +96,6 @@ def __init__( self._full_sampling = full_sampling self._transpiled_rb = transpiled_rb self._clifford_utils = CliffordUtils() - start = time.time() basis_gates = ["rz", "sx", "cx"] self._transpiled_cliff_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) @@ -243,9 +242,9 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, if is_interleaved: all_rb_interleaved_circuits = [] interleaved_elem_num = \ - CliffordUtils.num_from_1_qubit_clifford_single_gate( - interleaved_element[0], - self.transpile_options.__dict__["basis_gates"] + CliffordUtils.num_from_1_qubit_clifford( + interleaved_element, + self.transpile_options.basis_gates, ) else: all_rb_interleaved_circuits = None @@ -281,7 +280,7 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, interleaved_circ.compose(next_circ, inplace=True) composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, rand)] interleaved_circ.barrier(0) - interleaved_circ.append(interleaved_element[0], [0]) + interleaved_circ.compose(interleaved_element, inplace=True) composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, interleaved_elem_num)] interleaved_circ.barrier(0) @@ -325,9 +324,9 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, if is_interleaved: all_rb_interleaved_circuits = [] interleaved_elem_num = \ - CliffordUtils.num_from_1_qubit_clifford_single_gate( - interleaved_element[0], - self.transpile_options.__dict__["basis_gates"] + CliffordUtils.num_from_1_qubit_clifford( + interleaved_element, + self.transpile_options.basis_gates ) else: all_rb_interleaved_circuits = None @@ -359,7 +358,7 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, rb_interleaved_circ.compose(next_circ, inplace=True) composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, rand)] rb_interleaved_circ.barrier(0) - rb_interleaved_circ.append(interleaved_element[0], [0]) + rb_interleaved_circ.compose(interleaved_element, inplace=True) composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, interleaved_elem_num)] rb_interleaved_circ.barrier(0) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 52cd25e96d..ae7a444d00 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -15,6 +15,7 @@ from test.base import QiskitExperimentsTestCase import numpy as np +import random from ddt import ddt, data, unpack from qiskit.circuit import Delay, QuantumCircuit from qiskit.circuit.library import SXGate, CXGate, TGate, XGate, YGate, ZGate, HGate, SGate @@ -24,6 +25,7 @@ from qiskit.quantum_info import Clifford, Operator from qiskit_experiments.library import randomized_benchmarking as rb +from qiskit_experiments.library.randomized_benchmarking import CliffordUtils from qiskit_experiments.database_service.exceptions import DbExperimentEntryNotFound from qiskit_experiments.framework.composite import ParallelExperiment @@ -313,7 +315,7 @@ def test_single_qubit_parallel(self): class TestInterleavedRB(RBTestCase): """Test for interleaved RB.""" - @data([XGate(), [3], 4], [CXGate(), [4, 7], 5]) + @data([SXGate(), [3], 4], [CXGate(), [4, 7], 5]) @unpack def test_interleaved_structure(self, interleaved_element, qubits, length): """Verifies that when generating an interleaved circuit, it will be @@ -326,7 +328,8 @@ def test_interleaved_structure(self, interleaved_element, qubits, length): interleaved_element=interleaved_element, qubits=qubits, lengths=[length], num_samples=1, full_sampling=val, transpiled_rb=True ) - + exp.set_transpile_options(**self.transpiler_options) + exp.set_transpile_options(basis_gates=self.basis_gates) circuits = exp.circuits() c_std = circuits[0] c_int = circuits[1] @@ -353,25 +356,42 @@ def test_interleaved_structure(self, interleaved_element, qubits, length): int_idx += 1 def test_single_qubit(self): - """Test single qubit IRB.""" - exp = rb.InterleavedRB( - interleaved_element=SXGate(), - qubits=(0,), - lengths=list(range(1, 300, 30)), - seed=123, - backend=self.backend, - transpiled_rb=True, - ) - exp.set_transpile_options(**self.transpiler_options) - self.assertAllIdentity(exp.circuits()) + """Test single qubit IRB, once with an interleaved gate, once with an interleaved + Clifford circuit. + """ + interleaved_gate = SXGate() + utils = CliffordUtils() + random.seed(123) + num = random.randint(0, 23) + interleaved_clifford = utils.clifford_1_qubit_circuit(num) + # The circuit created for interleaved_clifford is: + # qc = QuantumCircuit(1) + # qc.rz(np.pi/2, 0) + # qc.sx(0) + # qc.rz(np.pi/2, 0) + # Since there is a single sx per interleaved_element, + # therefore epc_expected is the same as for when interleaved_element = SXGate() + for interleaved_element in [interleaved_gate, interleaved_clifford]: + exp = rb.InterleavedRB( + interleaved_element=interleaved_element, + qubits=(0,), + lengths=list(range(1, 300, 30)), + seed=123, + backend=self.backend, + transpiled_rb=True, + ) + exp.set_transpile_options(**self.transpiler_options) + exp.set_transpile_options(basis_gates=self.basis_gates) - expdata = exp.run() - self.assertExperimentDone(expdata) + self.assertAllIdentity(exp.circuits()) + + expdata = exp.run() + self.assertExperimentDone(expdata) # Since this is interleaved, we can directly compare values, i.e. n_gpc = 1 - epc = expdata.analysis_results("EPC") - epc_expected = 1 / 2 * self.p1q - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + epc = expdata.analysis_results("EPC") + epc_expected = 1 / 2 * self.p1q + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) def test_two_qubit(self): """Test two qubit IRB.""" From 7f9778f664eb6829d87df4668028db1f5c167c03 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 28 Jun 2022 12:03:22 +0300 Subject: [PATCH 27/39] Fixed incorrect parameter 'qubits' in test_non_clifford_interleaved_element --- test/randomized_benchmarking/test_randomized_benchmarking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index ae7a444d00..497ee99982 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -415,7 +415,7 @@ def test_two_qubit(self): def test_non_clifford_interleaved_element(self): """Verifies trying to run interleaved RB with non Clifford element throws an exception""" - qubits = 1 + qubits = [0] lengths = [1, 4, 6, 9, 13, 16] interleaved_element = TGate() # T gate is not Clifford, this should fail self.assertRaises( From af423864bf1a9b2ad9afdc83972163aa3d8c696d Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 28 Jun 2022 15:49:19 +0300 Subject: [PATCH 28/39] Added support for 'delay' as interleaved element --- .../randomized_benchmarking/clifford_utils.py | 8 ++++++-- .../test_randomized_benchmarking.py | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 85a63c20ab..ae77a6a352 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -257,17 +257,21 @@ def num_from_1_qubit_clifford_single_gate(inst, basis_gates): general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "y", "z"] transpiled_cliff_list = ["sx", "rz", "cx"] - if not name in basis_gates: + gates_with_delay = basis_gates.copy() + gates_with_delay.append("delay") + if not name in gates_with_delay: raise QiskitError( "Instruction {} is not in the basis gates".format(inst.name) ) if(set(basis_gates).issubset(set(general_cliff_list))): - num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22} + num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22, "delay":0} return num_dict[name] if (set(basis_gates).issubset(set(transpiled_cliff_list))): if name == "sx": return 8 + if name == "delay": + return 0 if name == "rz": # The next two are identical up to a phase, which makes no difference # for the associated Cliffords diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 497ee99982..662cdb08c6 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -435,13 +435,21 @@ def test_interleaving_delay(self): qubits=[0], lengths=[1], num_samples=1, + seed=1234, # This seed gives a 2-gate clifford transpiled_rb=True ) - # Not raises an error - _, int_circ = exp.circuits() + exp.set_transpile_options(**self.transpiler_options) + exp.set_transpile_options(basis_gates=self.basis_gates) + # Does not raise an error + _, int_circs = exp.circuits() + + # barrier, 2-gate clifford, barrier, "delay", barrier, ... + self.assertEqual(int_circs.data[4][0].name, interleaved_element.name) - # barrier, clifford, barrier, "delay", barrier, ... - self.assertEqual(int_circ.data[3][0], interleaved_element) + # Transpiled delay duration is represented in seconds, so must convert from us + self.assertEqual(int_circs.data[4][0].unit, "s") + self.assertAlmostEqual(int_circs.data[4][0].params[0], interleaved_element.params[0] * 1e-6) + self.assertAllIdentity([int_circs]) def test_interleaving_circuit_with_delay(self): """Test circuit with delay can be interleaved.""" @@ -450,7 +458,7 @@ def test_interleaving_circuit_with_delay(self): delay_qc.x(1) exp = rb.InterleavedRB( - interleaved_element=delay_qc, qubits=[1, 2], lengths=[1], seed=123, num_samples=1, transpiled_rb=True + interleaved_element=delay_qc, qubits=[1, 2], lengths=[1], seed=123, num_samples=1, transpiled_rb=False ) _, int_circ = exp.circuits() From 95125ed6715c93912c4fb95cd9440aa0c800ff67 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 28 Jun 2022 18:12:58 +0300 Subject: [PATCH 29/39] Moved setting of basis gates to circuits(), because in __init__ the transpile_options are not available yet --- .../randomized_benchmarking/rb_experiment.py | 6 ++++-- .../test_randomized_benchmarking.py | 15 +++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 62d46a3d22..dcb5c96ccf 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -96,8 +96,7 @@ def __init__( self._full_sampling = full_sampling self._transpiled_rb = transpiled_rb self._clifford_utils = CliffordUtils() - basis_gates = ["rz", "sx", "cx"] - self._transpiled_cliff_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=basis_gates) + self._transpiled_cliff_circuits = None def _verify_parameters(self, lengths, num_samples): """Verify input correctness, raise QiskitError if needed""" @@ -140,6 +139,9 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] + if self._transpiled_rb and self._transpiled_cliff_circuits == None: + self._transpiled_cliff_circuits = \ + CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 662cdb08c6..0b5b32fa8d 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -424,6 +424,7 @@ def test_non_clifford_interleaved_element(self): interleaved_element=interleaved_element, qubits=qubits, lengths=lengths, + transpiled_rb=True ) def test_interleaving_delay(self): @@ -458,7 +459,12 @@ def test_interleaving_circuit_with_delay(self): delay_qc.x(1) exp = rb.InterleavedRB( - interleaved_element=delay_qc, qubits=[1, 2], lengths=[1], seed=123, num_samples=1, transpiled_rb=False + interleaved_element=delay_qc, + qubits=[1, 2], + lengths=[1], + seed=123, + num_samples=1, + transpiled_rb=True ) _, int_circ = exp.circuits() @@ -509,9 +515,9 @@ def test_expdata_serialization(self): class TestEPGAnalysis(QiskitExperimentsTestCase): - """Test case for EPG colculation from EPC. + """Test case for EPG calculation from EPC. - EPG and depplarizing probability p are assumed to have following relationship + EPG and depolarizing probability p are assumed to have following relationship EPG = (2^n - 1) / 2^n · p @@ -551,15 +557,16 @@ def setUp(self): lengths=[1, 10, 30, 50, 80, 120, 150, 200], seed=123, backend=backend, + transpiled_rb=True ) exp_1qrb_q0.set_transpile_options(**transpiler_options) expdata_1qrb_q0 = exp_1qrb_q0.run(analysis=None).block_for_results(timeout=300) - exp_1qrb_q1 = rb.StandardRB( qubits=(1,), lengths=[1, 10, 30, 50, 80, 120, 150, 200], seed=123, backend=backend, + transpiled_rb=True ) exp_1qrb_q1.set_transpile_options(**transpiler_options) expdata_1qrb_q1 = exp_1qrb_q1.run(analysis=None).block_for_results(timeout=300) From d5949f47caaf22f5bc9d85c16db5abddd23b72eb Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Wed, 29 Jun 2022 18:32:51 +0300 Subject: [PATCH 30/39] Cleaned up setting of tranpile_options in the test. Added call to generate_1q_transpiled_clifford_circuits in InterleavedRB.circuits() --- .../randomized_benchmarking/clifford_utils.py | 18 ++++++------------ .../interleaved_rb_experiment.py | 6 +++++- .../randomized_benchmarking/rb_experiment.py | 3 ++- .../test_randomized_benchmarking.py | 9 ++++----- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index ae77a6a352..053d0ff2e4 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -226,21 +226,15 @@ def _unpack_num_multi_sigs(self, num, sigs): num -= sig_size return None - def transpile_single_clifford(cliff_circ, basis_gates : List[str]): + def transpile_single_clifford(self, cliff_circ : QuantumCircuit, basis_gates : List[str]): backend = AerSimulator() return transpile(cliff_circ, backend, optimization_level=1, basis_gates=basis_gates) - def generate_1q_transpiled_clifford_circuits(basis_gates : List[str]): - utils = CliffordUtils() - circs = [] - for num in range(0, 24): - circ = utils.clifford_1_qubit_circuit(num=num) - circs.append(circ) - backend = AerSimulator() + def generate_1q_transpiled_clifford_circuits(self, basis_gates : List[str]): transpiled_circs = [] - - for i, circ in enumerate(circs): - transpiled_circ = transpile(circ, backend, optimization_level=1, basis_gates=basis_gates) + for num in range(0, 24): + circ = self.clifford_1_qubit_circuit(num=num) + transpiled_circ = self.transpile_single_clifford(circ, basis_gates) transpiled_circs.append(transpiled_circ) return transpiled_circs @@ -254,7 +248,7 @@ def num_from_1_qubit_clifford_single_gate(inst, basis_gates): one of these sets. """ name = inst.name - general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "y", "z"] + general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z"] transpiled_cliff_list = ["sx", "rz", "cx"] gates_with_delay = basis_gates.copy() diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index a713c71ca8..e791937081 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -101,6 +101,10 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] + if self._transpiled_rb and self._transpiled_cliff_circuits == None: + utils = CliffordUtils() + self._transpiled_cliff_circuits = \ + utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: self._set_transpiled_interleaved_element() @@ -183,7 +187,7 @@ def _set_transpiled_interleaved_element(self): basis_gates = self.transpile_options.basis_gates else: basis_gates = None - self._transpiled_interleaved_elem = CliffordUtils.transpile_single_clifford( + self._transpiled_interleaved_elem = CliffordUtils().transpile_single_clifford( qc_interleaved, basis_gates = basis_gates ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index dcb5c96ccf..f6c0678a24 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -139,9 +139,10 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] + utils = CliffordUtils() if self._transpiled_rb and self._transpiled_cliff_circuits == None: self._transpiled_cliff_circuits = \ - CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) + utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 0b5b32fa8d..a8301189be 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -196,6 +196,7 @@ def test_full_sampling_single_qubit(self): full_sampling=False, transpiled_rb=True ) + exp1.set_transpile_options(**self.transpiler_options) exp2 = rb.StandardRB( qubits=(0,), lengths=[10, 20, 30], @@ -204,6 +205,7 @@ def test_full_sampling_single_qubit(self): full_sampling=True, transpiled_rb=True ) + exp2.set_transpile_options(**self.transpiler_options) circs1 = exp1.circuits() circs2 = exp2.circuits() @@ -302,7 +304,7 @@ def test_single_qubit_parallel(self): exps.append(exp) par_exp = ParallelExperiment(exps) - par_exp.set_transpile_options(optimization_level=1) + par_exp.set_transpile_options(**self.transpiler_options) par_expdata = par_exp.run(backend=self.backend) self.assertExperimentDone(par_expdata) @@ -329,7 +331,6 @@ def test_interleaved_structure(self, interleaved_element, qubits, length): num_samples=1, full_sampling=val, transpiled_rb=True ) exp.set_transpile_options(**self.transpiler_options) - exp.set_transpile_options(basis_gates=self.basis_gates) circuits = exp.circuits() c_std = circuits[0] c_int = circuits[1] @@ -381,7 +382,6 @@ def test_single_qubit(self): transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) - exp.set_transpile_options(basis_gates=self.basis_gates) self.assertAllIdentity(exp.circuits()) @@ -440,7 +440,7 @@ def test_interleaving_delay(self): transpiled_rb=True ) exp.set_transpile_options(**self.transpiler_options) - exp.set_transpile_options(basis_gates=self.basis_gates) + # Does not raise an error _, int_circs = exp.circuits() @@ -464,7 +464,6 @@ def test_interleaving_circuit_with_delay(self): lengths=[1], seed=123, num_samples=1, - transpiled_rb=True ) _, int_circ = exp.circuits() From a9e314685bebd03d8a72195e6bd9648e281002d8 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Thu, 30 Jun 2022 11:33:53 +0300 Subject: [PATCH 31/39] Changed the clifford compose mapping so that the rhs includes only single-gate cliffords. The purpose is to reduce the size of the mapping table --- .../randomized_benchmarking/clifford_data.py | 848 +++++------------- .../randomized_benchmarking/clifford_utils.py | 21 +- .../create_clifford_map.py | 23 +- .../interleaved_rb_experiment.py | 6 +- .../randomized_benchmarking/rb_experiment.py | 49 +- 5 files changed, 294 insertions(+), 653 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py index f4ddc1330e..1e03f89aa4 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py @@ -13,609 +13,251 @@ This file contains the Clifford group represented as integers. """ #In CLIFF_COMPOSE_DATA, (i, j): k represents Clifford(i).compose(clifford(j)) = Clifford(k) + CLIFF_COMPOSE_DATA = { - (0, 0): 0, - (0, 1): 1, - (0, 2): 2, - (0, 3): 3, - (0, 4): 4, - (0, 5): 5, - (0, 6): 6, - (0, 7): 7, - (0, 8): 8, - (0, 9): 9, - (0, 10): 10, - (0, 11): 11, - (0, 12): 12, - (0, 13): 13, - (0, 14): 14, - (0, 15): 15, - (0, 16): 16, - (0, 17): 17, - (0, 18): 18, - (0, 19): 19, - (0, 20): 20, - (0, 21): 21, - (0, 22): 22, - (0, 23): 23, - (1, 0): 1, - (1, 1): 0, - (1, 2): 3, - (1, 3): 2, - (1, 4): 5, - (1, 5): 4, - (1, 6): 7, - (1, 7): 6, - (1, 8): 9, - (1, 9): 8, - (1, 10): 11, - (1, 11): 10, - (1, 12): 13, - (1, 13): 12, - (1, 14): 15, - (1, 15): 14, - (1, 16): 17, - (1, 17): 16, - (1, 18): 19, - (1, 19): 18, - (1, 20): 21, - (1, 21): 20, - (1, 22): 23, - (1, 23): 22, - (2, 0): 2, - (2, 1): 23, - (2, 2): 6, - (2, 3): 4, - (2, 4): 15, - (2, 5): 1, - (2, 6): 8, - (2, 7): 17, - (2, 8): 0, - (2, 9): 10, - (2, 10): 21, - (2, 11): 7, - (2, 12): 14, - (2, 13): 11, - (2, 14): 18, - (2, 15): 16, - (2, 16): 3, - (2, 17): 13, - (2, 18): 20, - (2, 19): 5, - (2, 20): 12, - (2, 21): 22, - (2, 22): 9, - (2, 23): 19, - (3, 0): 3, - (3, 1): 22, - (3, 2): 7, - (3, 3): 5, - (3, 4): 14, - (3, 5): 0, - (3, 6): 9, - (3, 7): 16, - (3, 8): 1, - (3, 9): 11, - (3, 10): 20, - (3, 11): 6, - (3, 12): 15, - (3, 13): 10, - (3, 14): 19, - (3, 15): 17, - (3, 16): 2, - (3, 17): 12, - (3, 18): 21, - (3, 19): 4, - (3, 20): 13, - (3, 21): 23, - (3, 22): 8, - (3, 23): 18, - (4, 0): 4, - (4, 1): 9, - (4, 2): 17, - (4, 3): 1, - (4, 4): 18, - (4, 5): 2, - (4, 6): 10, - (4, 7): 3, - (4, 8): 23, - (4, 9): 7, - (4, 10): 12, - (4, 11): 8, - (4, 12): 16, - (4, 13): 21, - (4, 14): 5, - (4, 15): 13, - (4, 16): 6, - (4, 17): 14, - (4, 18): 22, - (4, 19): 15, - (4, 20): 11, - (4, 21): 19, - (4, 22): 0, - (4, 23): 20, - (5, 0): 5, - (5, 1): 8, - (5, 2): 16, - (5, 3): 0, - (5, 4): 19, - (5, 5): 3, - (5, 6): 11, - (5, 7): 2, - (5, 8): 22, - (5, 9): 6, - (5, 10): 13, - (5, 11): 9, - (5, 12): 17, - (5, 13): 20, - (5, 14): 4, - (5, 15): 12, - (5, 16): 7, - (5, 17): 15, - (5, 18): 23, - (5, 19): 14, - (5, 20): 10, - (5, 21): 18, - (5, 22): 1, - (5, 23): 21, - (6, 0): 6, - (6, 1): 19, - (6, 2): 8, - (6, 3): 15, - (6, 4): 16, - (6, 5): 23, - (6, 6): 0, - (6, 7): 13, - (6, 8): 2, - (6, 9): 21, - (6, 10): 22, - (6, 11): 17, - (6, 12): 18, - (6, 13): 7, - (6, 14): 20, - (6, 15): 3, - (6, 16): 4, - (6, 17): 11, - (6, 18): 12, - (6, 19): 1, - (6, 20): 14, - (6, 21): 9, - (6, 22): 10, - (6, 23): 5, - (7, 0): 7, - (7, 1): 18, - (7, 2): 9, - (7, 3): 14, - (7, 4): 17, - (7, 5): 22, - (7, 6): 1, - (7, 7): 12, - (7, 8): 3, - (7, 9): 20, - (7, 10): 23, - (7, 11): 16, - (7, 12): 19, - (7, 13): 6, - (7, 14): 21, - (7, 15): 2, - (7, 16): 5, - (7, 17): 10, - (7, 18): 13, - (7, 19): 0, - (7, 20): 15, - (7, 21): 8, - (7, 22): 11, - (7, 23): 4, - (8, 0): 8, - (8, 1): 5, - (8, 2): 0, - (8, 3): 16, - (8, 4): 3, - (8, 5): 19, - (8, 6): 2, - (8, 7): 11, - (8, 8): 6, - (8, 9): 22, - (8, 10): 9, - (8, 11): 13, - (8, 12): 20, - (8, 13): 17, - (8, 14): 12, - (8, 15): 4, - (8, 16): 15, - (8, 17): 7, - (8, 18): 14, - (8, 19): 23, - (8, 20): 18, - (8, 21): 10, - (8, 22): 21, - (8, 23): 1, - (9, 0): 9, - (9, 1): 4, - (9, 2): 1, - (9, 3): 17, - (9, 4): 2, - (9, 5): 18, - (9, 6): 3, - (9, 7): 10, - (9, 8): 7, - (9, 9): 23, - (9, 10): 8, - (9, 11): 12, - (9, 12): 21, - (9, 13): 16, - (9, 14): 13, - (9, 15): 5, - (9, 16): 14, - (9, 17): 6, - (9, 18): 15, - (9, 19): 22, - (9, 20): 19, - (9, 21): 11, - (9, 22): 20, - (9, 23): 0, - (10, 0): 10, - (10, 1): 15, - (10, 2): 23, - (10, 3): 13, - (10, 4): 6, - (10, 5): 20, - (10, 6): 4, - (10, 7): 21, - (10, 8): 17, - (10, 9): 19, - (10, 10): 0, - (10, 11): 14, - (10, 12): 22, - (10, 13): 3, - (10, 14): 11, - (10, 15): 1, - (10, 16): 18, - (10, 17): 8, - (10, 18): 16, - (10, 19): 9, - (10, 20): 5, - (10, 21): 7, - (10, 22): 12, - (10, 23): 2, - (11, 0): 11, - (11, 1): 14, - (11, 2): 22, - (11, 3): 12, - (11, 4): 7, - (11, 5): 21, - (11, 6): 5, - (11, 7): 20, - (11, 8): 16, - (11, 9): 18, - (11, 10): 1, - (11, 11): 15, - (11, 12): 23, - (11, 13): 2, - (11, 14): 10, - (11, 15): 0, - (11, 16): 19, - (11, 17): 9, - (11, 18): 17, - (11, 19): 8, - (11, 20): 4, - (11, 21): 6, - (11, 22): 13, - (11, 23): 3, - (12, 0): 12, - (12, 1): 13, - (12, 2): 20, - (12, 3): 21, - (12, 4): 10, - (12, 5): 11, - (12, 6): 18, - (12, 7): 19, - (12, 8): 14, - (12, 9): 15, - (12, 10): 4, - (12, 11): 5, - (12, 12): 0, - (12, 13): 1, - (12, 14): 8, - (12, 15): 9, - (12, 16): 22, - (12, 17): 23, - (12, 18): 6, - (12, 19): 7, - (12, 20): 2, - (12, 21): 3, - (12, 22): 16, - (12, 23): 17, - (13, 0): 13, - (13, 1): 12, - (13, 2): 21, - (13, 3): 20, - (13, 4): 11, - (13, 5): 10, - (13, 6): 19, - (13, 7): 18, - (13, 8): 15, - (13, 9): 14, - (13, 10): 5, - (13, 11): 4, - (13, 12): 1, - (13, 13): 0, - (13, 14): 9, - (13, 15): 8, - (13, 16): 23, - (13, 17): 22, - (13, 18): 7, - (13, 19): 6, - (13, 20): 3, - (13, 21): 2, - (13, 22): 17, - (13, 23): 16, - (14, 0): 14, - (14, 1): 11, - (14, 2): 12, - (14, 3): 22, - (14, 4): 21, - (14, 5): 7, - (14, 6): 20, - (14, 7): 5, - (14, 8): 18, - (14, 9): 16, - (14, 10): 15, - (14, 11): 1, - (14, 12): 2, - (14, 13): 23, - (14, 14): 0, - (14, 15): 10, - (14, 16): 9, - (14, 17): 19, - (14, 18): 8, - (14, 19): 17, - (14, 20): 6, - (14, 21): 4, - (14, 22): 3, - (14, 23): 13, - (15, 0): 15, - (15, 1): 10, - (15, 2): 13, - (15, 3): 23, - (15, 4): 20, - (15, 5): 6, - (15, 6): 21, - (15, 7): 4, - (15, 8): 19, - (15, 9): 17, - (15, 10): 14, - (15, 11): 0, - (15, 12): 3, - (15, 13): 22, - (15, 14): 1, - (15, 15): 11, - (15, 16): 8, - (15, 17): 18, - (15, 18): 9, - (15, 19): 16, - (15, 20): 7, - (15, 21): 5, - (15, 22): 2, - (15, 23): 12, - (16, 0): 16, - (16, 1): 21, - (16, 2): 11, - (16, 3): 19, - (16, 4): 12, - (16, 5): 8, - (16, 6): 22, - (16, 7): 15, - (16, 8): 5, - (16, 9): 13, - (16, 10): 18, - (16, 11): 2, - (16, 12): 4, - (16, 13): 9, - (16, 14): 23, - (16, 15): 7, - (16, 16): 0, - (16, 17): 20, - (16, 18): 10, - (16, 19): 3, - (16, 20): 17, - (16, 21): 1, - (16, 22): 6, - (16, 23): 14, - (17, 0): 17, - (17, 1): 20, - (17, 2): 10, - (17, 3): 18, - (17, 4): 13, - (17, 5): 9, - (17, 6): 23, - (17, 7): 14, - (17, 8): 4, - (17, 9): 12, - (17, 10): 19, - (17, 11): 3, - (17, 12): 5, - (17, 13): 8, - (17, 14): 22, - (17, 15): 6, - (17, 16): 1, - (17, 17): 21, - (17, 18): 11, - (17, 19): 2, - (17, 20): 16, - (17, 21): 0, - (17, 22): 7, - (17, 23): 15, - (18, 0): 18, - (18, 1): 7, - (18, 2): 14, - (18, 3): 9, - (18, 4): 22, - (18, 5): 17, - (18, 6): 12, - (18, 7): 1, - (18, 8): 20, - (18, 9): 3, - (18, 10): 16, - (18, 11): 23, - (18, 12): 6, - (18, 13): 19, - (18, 14): 2, - (18, 15): 21, - (18, 16): 10, - (18, 17): 5, - (18, 18): 0, - (18, 19): 13, - (18, 20): 8, - (18, 21): 15, - (18, 22): 4, - (18, 23): 11, - (19, 0): 19, - (19, 1): 6, - (19, 2): 15, - (19, 3): 8, - (19, 4): 23, - (19, 5): 16, - (19, 6): 13, - (19, 7): 0, - (19, 8): 21, - (19, 9): 2, - (19, 10): 17, - (19, 11): 22, - (19, 12): 7, - (19, 13): 18, - (19, 14): 3, - (19, 15): 20, - (19, 16): 11, - (19, 17): 4, - (19, 18): 1, - (19, 19): 12, - (19, 20): 9, - (19, 21): 14, - (19, 22): 5, - (19, 23): 10, - (20, 0): 20, - (20, 1): 17, - (20, 2): 18, - (20, 3): 10, - (20, 4): 9, - (20, 5): 13, - (20, 6): 14, - (20, 7): 23, - (20, 8): 12, - (20, 9): 4, - (20, 10): 3, - (20, 11): 19, - (20, 12): 8, - (20, 13): 5, - (20, 14): 6, - (20, 15): 22, - (20, 16): 21, - (20, 17): 1, - (20, 18): 2, - (20, 19): 11, - (20, 20): 0, - (20, 21): 16, - (20, 22): 15, - (20, 23): 7, - (21, 0): 21, - (21, 1): 16, - (21, 2): 19, - (21, 3): 11, - (21, 4): 8, - (21, 5): 12, - (21, 6): 15, - (21, 7): 22, - (21, 8): 13, - (21, 9): 5, - (21, 10): 2, - (21, 11): 18, - (21, 12): 9, - (21, 13): 4, - (21, 14): 7, - (21, 15): 23, - (21, 16): 20, - (21, 17): 0, - (21, 18): 3, - (21, 19): 10, - (21, 20): 1, - (21, 21): 17, - (21, 22): 14, - (21, 23): 6, - (22, 0): 22, - (22, 1): 3, - (22, 2): 5, - (22, 3): 7, - (22, 4): 0, - (22, 5): 14, - (22, 6): 16, - (22, 7): 9, - (22, 8): 11, - (22, 9): 1, - (22, 10): 6, - (22, 11): 20, - (22, 12): 10, - (22, 13): 15, - (22, 14): 17, - (22, 15): 19, - (22, 16): 12, - (22, 17): 2, - (22, 18): 4, - (22, 19): 21, - (22, 20): 23, - (22, 21): 13, - (22, 22): 18, - (22, 23): 8, - (23, 0): 23, - (23, 1): 2, - (23, 2): 4, - (23, 3): 6, - (23, 4): 1, - (23, 5): 15, - (23, 6): 17, - (23, 7): 8, - (23, 8): 10, - (23, 9): 0, - (23, 10): 7, - (23, 11): 21, - (23, 12): 11, - (23, 13): 14, - (23, 14): 16, - (23, 15): 18, - (23, 16): 13, - (23, 17): 3, - (23, 18): 5, - (23, 19): 20, - (23, 20): 22, - (23, 21): 12, - (23, 22): 19, - (23, 23): 9, -} + (0, 0):0, + (0, 1):1, + (0, 2):2, + (0, 4):4, + (0, 6):6, + (0, 8):8, + (0, 12):12, + (0, 18):18, + (0, 22):22, + (1, 0):1, + (1, 1):0, + (1, 2):3, + (1, 4):5, + (1, 6):7, + (1, 8):9, + (1, 12):13, + (1, 18):19, + (1, 22):23, + (2, 0):2, + (2, 1):23, + (2, 2):6, + (2, 4):15, + (2, 6):8, + (2, 8):0, + (2, 12):14, + (2, 18):20, + (2, 22):9, + (3, 0):3, + (3, 1):22, + (3, 2):7, + (3, 4):14, + (3, 6):9, + (3, 8):1, + (3, 12):15, + (3, 18):21, + (3, 22):8, + (4, 0):4, + (4, 1):9, + (4, 2):17, + (4, 4):18, + (4, 6):10, + (4, 8):23, + (4, 12):16, + (4, 18):22, + (4, 22):0, + (5, 0):5, + (5, 1):8, + (5, 2):16, + (5, 4):19, + (5, 6):11, + (5, 8):22, + (5, 12):17, + (5, 18):23, + (5, 22):1, + (6, 0):6, + (6, 1):19, + (6, 2):8, + (6, 4):16, + (6, 6):0, + (6, 8):2, + (6, 12):18, + (6, 18):12, + (6, 22):10, + (7, 0):7, + (7, 1):18, + (7, 2):9, + (7, 4):17, + (7, 6):1, + (7, 8):3, + (7, 12):19, + (7, 18):13, + (7, 22):11, + (8, 0):8, + (8, 1):5, + (8, 2):0, + (8, 4):3, + (8, 6):2, + (8, 8):6, + (8, 12):20, + (8, 18):14, + (8, 22):21, + (9, 0):9, + (9, 1):4, + (9, 2):1, + (9, 4):2, + (9, 6):3, + (9, 8):7, + (9, 12):21, + (9, 18):15, + (9, 22):20, + (10, 0):10, + (10, 1):15, + (10, 2):23, + (10, 4):6, + (10, 6):4, + (10, 8):17, + (10, 12):22, + (10, 18):16, + (10, 22):12, + (11, 0):11, + (11, 1):14, + (11, 2):22, + (11, 4):7, + (11, 6):5, + (11, 8):16, + (11, 12):23, + (11, 18):17, + (11, 22):13, + (12, 0):12, + (12, 1):13, + (12, 2):20, + (12, 4):10, + (12, 6):18, + (12, 8):14, + (12, 12):0, + (12, 18):6, + (12, 22):16, + (13, 0):13, + (13, 1):12, + (13, 2):21, + (13, 4):11, + (13, 6):19, + (13, 8):15, + (13, 12):1, + (13, 18):7, + (13, 22):17, + (14, 0):14, + (14, 1):11, + (14, 2):12, + (14, 4):21, + (14, 6):20, + (14, 8):18, + (14, 12):2, + (14, 18):8, + (14, 22):3, + (15, 0):15, + (15, 1):10, + (15, 2):13, + (15, 4):20, + (15, 6):21, + (15, 8):19, + (15, 12):3, + (15, 18):9, + (15, 22):2, + (16, 0):16, + (16, 1):21, + (16, 2):11, + (16, 4):12, + (16, 6):22, + (16, 8):5, + (16, 12):4, + (16, 18):10, + (16, 22):6, + (17, 0):17, + (17, 1):20, + (17, 2):10, + (17, 4):13, + (17, 6):23, + (17, 8):4, + (17, 12):5, + (17, 18):11, + (17, 22):7, + (18, 0):18, + (18, 1):7, + (18, 2):14, + (18, 4):22, + (18, 6):12, + (18, 8):20, + (18, 12):6, + (18, 18):0, + (18, 22):4, + (19, 0):19, + (19, 1):6, + (19, 2):15, + (19, 4):23, + (19, 6):13, + (19, 8):21, + (19, 12):7, + (19, 18):1, + (19, 22):5, + (20, 0):20, + (20, 1):17, + (20, 2):18, + (20, 4):9, + (20, 6):14, + (20, 8):12, + (20, 12):8, + (20, 18):2, + (20, 22):15, + (21, 0):21, + (21, 1):16, + (21, 2):19, + (21, 4):8, + (21, 6):15, + (21, 8):13, + (21, 12):9, + (21, 18):3, + (21, 22):14, + (22, 0):22, + (22, 1):3, + (22, 2):5, + (22, 4):0, + (22, 6):16, + (22, 8):11, + (22, 12):10, + (22, 18):4, + (22, 22):18, + (23, 0):23, + (23, 1):2, + (23, 2):4, + (23, 4):1, + (23, 6):17, + (23, 8):10, + (23, 12):11, + (23, 18):5, + (23, 22):19, + } # In CLIFF_INVERSE_DATA, i: j represents Clifford(i).inverse = Clifford(j) -CLIFF_INVERSE_DATA = { - 0: 0, - 1: 1, - 2: 8, - 3: 5, - 4: 22, - 5: 3, - 6: 6, - 7: 19, - 8: 2, - 9: 23, - 10: 10, - 11: 15, - 12: 12, - 13: 13, - 14: 14, - 15: 11, - 16: 16, - 17: 21, - 18: 18, - 19: 7, - 20: 20, - 21: 17, - 22: 4, - 23: 9, -} +CLIFF_INVERSE_DATA = [ + 0, + 1, + 8, + 5, + 22, + 3, + 6, + 19, + 2, + 23, + 10, + 15, + 12, + 13, + 14, + 11, + 16, + 21, + 18, + 7, + 20, + 17, + 4, + 9, + ] + diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 053d0ff2e4..b0230413a0 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -70,6 +70,8 @@ class CliffordUtils: (2, 2, 3, 3, 3, 3, 4, 4), (2, 2, 3, 3, 4, 4), ] + general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z", "cx"] + transpiled_cliff_list = ["sx", "rz", "cx"] def clifford_1_qubit(self, num): """Return the 1-qubit clifford element corresponding to `num` @@ -238,7 +240,7 @@ def generate_1q_transpiled_clifford_circuits(self, basis_gates : List[str]): transpiled_circs.append(transpiled_circ) return transpiled_circs - def num_from_1_qubit_clifford_single_gate(inst, basis_gates): + def num_from_1_qubit_clifford_single_gate(self, inst, basis_gates): """ This method does the reverse of clifford_1_qubit_circuit - given a clifford, it returns the corresponding integer, with the mapping @@ -248,8 +250,8 @@ def num_from_1_qubit_clifford_single_gate(inst, basis_gates): one of these sets. """ name = inst.name - general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z"] - transpiled_cliff_list = ["sx", "rz", "cx"] + #general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z"] + #transpiled_cliff_list = ["sx", "rz", "cx"] gates_with_delay = basis_gates.copy() gates_with_delay.append("delay") @@ -257,11 +259,11 @@ def num_from_1_qubit_clifford_single_gate(inst, basis_gates): raise QiskitError( "Instruction {} is not in the basis gates".format(inst.name) ) - if(set(basis_gates).issubset(set(general_cliff_list))): + if(set(basis_gates).issubset(set(self.general_cliff_list))): num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22, "delay":0} return num_dict[name] - if (set(basis_gates).issubset(set(transpiled_cliff_list))): + if (set(basis_gates).issubset(set(self.transpiled_cliff_list))): if name == "sx": return 8 if name == "delay": @@ -282,10 +284,9 @@ def num_from_1_qubit_clifford_single_gate(inst, basis_gates): "Instruction {} could not be converted to Clifford gate".format(name) ) - def num_from_1_qubit_clifford(qc: QuantumCircuit, - basis_gates: List[str]) -> int: - composed_num = 0 + def compose_num_with_clifford(self, composed_num, qc, + basis_gates) -> int: for inst in qc: - num = CliffordUtils.num_from_1_qubit_clifford_single_gate(inst[0], basis_gates) - composed_num = CLIFF_COMPOSE_DATA[(composed_num, num)] + num = CliffordUtils().num_from_1_qubit_clifford_single_gate(inst=inst[0], basis_gates=basis_gates) + composed_num = CLIFF_COMPOSE_DATA[composed_num, num] return composed_num diff --git a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py index d24fd1c972..ef1ce8aa54 100644 --- a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py +++ b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py @@ -12,14 +12,15 @@ def create_compose_map(): num_to_cliff[i] = cliff cliff_to_num[cliff.__repr__()] = i - prods = {} + products = {} + single_gate_clifford_mapping = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22} for i in range(24): cliff1 = num_to_cliff[i] - for j in range(24): - cliff2 = num_to_cliff[j] + for gate in single_gate_clifford_mapping.keys(): + cliff2 = num_to_cliff[single_gate_clifford_mapping[gate]] cliff = cliff1.compose(cliff2) - prods[i, j] = cliff_to_num[cliff.__repr__()] + products[i, single_gate_clifford_mapping[gate]] = cliff_to_num[cliff.__repr__()] invs = {} for i in range(24): @@ -28,15 +29,15 @@ def create_compose_map(): invs[i] = cliff_to_num[cliff.__repr__()] print("CLIFF_COMPOSE_DATA = {") - for i in prods: - print(f" {i}: {prods[i]},") - #print(prods) + for i in products: + print(f" {i}:{products[i]},") print(" }") + print() - print("CLIFF_INVERSE_DATA = {") - #print(invs) + print("CLIFF_INVERSE_DATA = [") for i in invs: - print(f" {i}: {invs[i]},") - print(" }") + print(f" {invs[i]},") + print(" ]") + print() create_compose_map() diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index e791937081..09677803a7 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -102,14 +102,12 @@ def circuits(self) -> List[QuantumCircuit]: rng = default_rng(seed=self.experiment_options.seed) circuits = [] if self._transpiled_rb and self._transpiled_cliff_circuits == None: - utils = CliffordUtils() self._transpiled_cliff_circuits = \ - utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) + self._clifford_utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: self._set_transpiled_interleaved_element() std_circuits, int_circuits = self._build_rb_circuits(self.experiment_options.lengths, rng, - is_interleaved=True, interleaved_element=self._transpiled_interleaved_elem) circuits += std_circuits circuits += int_circuits @@ -187,7 +185,7 @@ def _set_transpiled_interleaved_element(self): basis_gates = self.transpile_options.basis_gates else: basis_gates = None - self._transpiled_interleaved_elem = CliffordUtils().transpile_single_clifford( + self._transpiled_interleaved_elem = self._clifford_utils.transpile_single_clifford( qc_interleaved, basis_gates = basis_gates ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index f6c0678a24..cca253cd43 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -139,10 +139,9 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] - utils = CliffordUtils() if self._transpiled_rb and self._transpiled_cliff_circuits == None: self._transpiled_cliff_circuits = \ - utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) + self._clifford_utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng) @@ -223,8 +222,7 @@ def _generate_circuit( circuits.append(rb_circ) return circuits - def _build_rb_circuits(self, lengths, rng, is_interleaved=False, - interleaved_element=None): + def _build_rb_circuits(self, lengths, rng, interleaved_element=None): """ build_rb_circuits Args: @@ -237,18 +235,13 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, when performed on the integers rather than on the Cliffords themselves. """ if self._full_sampling: - return self._build_rb_circuits_full_sampling(lengths, rng, is_interleaved, - interleaved_element) - + return self._build_rb_circuits_full_sampling(lengths, rng, interleaved_element) + is_interleaved = interleaved_element != None max_qubit = max(self.physical_qubits) + 1 all_rb_circuits = [] + if is_interleaved: all_rb_interleaved_circuits = [] - interleaved_elem_num = \ - CliffordUtils.num_from_1_qubit_clifford( - interleaved_element, - self.transpile_options.basis_gates, - ) else: all_rb_interleaved_circuits = None @@ -277,14 +270,18 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, # choose random clifford next_circ = self._transpiled_cliff_circuits[rand] circ.compose(next_circ, inplace=True) - composed_cliff_num = CLIFF_COMPOSE_DATA[(composed_cliff_num, rand)] + composed_cliff_num = self._clifford_utils.compose_num_with_clifford(composed_cliff_num, next_circ, + self.transpile_options.basis_gates) circ.barrier(0) if is_interleaved: interleaved_circ.compose(next_circ, inplace=True) - composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, rand)] + composed_interleaved_num = self._clifford_utils.compose_num_with_clifford(composed_interleaved_num, next_circ, + self.transpile_options.basis_gates) interleaved_circ.barrier(0) interleaved_circ.compose(interleaved_element, inplace=True) - composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, interleaved_elem_num)] + composed_interleaved_num = self._clifford_utils.compose_num_with_clifford(composed_interleaved_num, + interleaved_element, + self.transpile_options.basis_gates) interleaved_circ.barrier(0) if i == length-1: @@ -321,16 +318,11 @@ def _build_rb_circuits(self, lengths, rng, is_interleaved=False, prev_length = i + 1 return all_rb_circuits, all_rb_interleaved_circuits - def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, - interleaved_element=None): + def _build_rb_circuits_full_sampling(self, lengths, rng, interleaved_element=None): + is_interleaved = interleaved_element != None all_rb_circuits = [] if is_interleaved: all_rb_interleaved_circuits = [] - interleaved_elem_num = \ - CliffordUtils.num_from_1_qubit_clifford( - interleaved_element, - self.transpile_options.basis_gates - ) else: all_rb_interleaved_circuits = None @@ -355,14 +347,21 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, is_interleaved=False, rand = random_samples[i] next_circ = self._transpiled_cliff_circuits[rand].copy() rb_circ.compose(next_circ, inplace=True) - composed_cliff_num = CLIFF_COMPOSE_DATA[(composed_cliff_num, rand)] + + composed_cliff_num = \ + self._clifford_utils.compose_num_with_clifford(composed_num=composed_cliff_num, qc=next_circ, + basis_gates=self.transpile_options.basis_gates) rb_circ.barrier(0) if is_interleaved: rb_interleaved_circ.compose(next_circ, inplace=True) - composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, rand)] + composed_interleaved_num = \ + self._clifford_utils.compose_num_with_clifford(composed_num=composed_interleaved_num, qc=next_circ, + basis_gates=self.transpile_options.basis_gates) rb_interleaved_circ.barrier(0) rb_interleaved_circ.compose(interleaved_element, inplace=True) - composed_interleaved_num = CLIFF_COMPOSE_DATA[(composed_interleaved_num, interleaved_elem_num)] + composed_interleaved_num = \ + self._clifford_utils.compose_num_with_clifford(composed_interleaved_num, interleaved_element, + self.transpile_options.basis_gates) rb_interleaved_circ.barrier(0) inverse_clifford_num = CLIFF_INVERSE_DATA[composed_cliff_num] From de1d6ff3c19467746fc8ddee6f2308655872aca8 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Thu, 30 Jun 2022 12:30:33 +0300 Subject: [PATCH 32/39] Changed all methods in CliffordUtils to be classmethod --- .../randomized_benchmarking/clifford_utils.py | 68 +++++++++++-------- .../create_clifford_map.py | 4 +- .../interleaved_rb_experiment.py | 6 +- .../randomized_benchmarking/rb_experiment.py | 17 +++-- .../test_randomized_benchmarking.py | 3 +- 5 files changed, 53 insertions(+), 45 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index b0230413a0..8b9809bf01 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -73,20 +73,23 @@ class CliffordUtils: general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z", "cx"] transpiled_cliff_list = ["sx", "rz", "cx"] - def clifford_1_qubit(self, num): + @classmethod + def clifford_1_qubit(cls, num): """Return the 1-qubit clifford element corresponding to `num` where `num` is between 0 and 23. """ - return Clifford(self.clifford_1_qubit_circuit(num), validate=False) + return Clifford(cls.clifford_1_qubit_circuit(num), validate=False) - def clifford_2_qubit(self, num): + @classmethod + def clifford_2_qubit(cls, num): """Return the 2-qubit clifford element corresponding to `num` where `num` is between 0 and 11519. """ - return Clifford(self.clifford_2_qubit_circuit(num), validate=False) + return Clifford(cls.clifford_2_qubit_circuit(num), validate=False) + @classmethod def random_cliffords( - self, num_qubits: int, size: int = 1, rng: Optional[Union[int, Generator]] = None + cls, num_qubits: int, size: int = 1, rng: Optional[Union[int, Generator]] = None ): """Generate a list of random clifford elements""" if num_qubits > 2: @@ -100,13 +103,14 @@ def random_cliffords( if num_qubits == 1: samples = rng.integers(24, size=size) - return [Clifford(self.clifford_1_qubit_circuit(i), validate=False) for i in samples] + return [Clifford(cls.clifford_1_qubit_circuit(i), validate=False) for i in samples] else: samples = rng.integers(11520, size=size) - return [Clifford(self.clifford_2_qubit_circuit(i), validate=False) for i in samples] + return [Clifford(cls.clifford_2_qubit_circuit(i), validate=False) for i in samples] + @classmethod def random_clifford_circuits( - self, num_qubits: int, size: int = 1, rng: Optional[Union[int, Generator]] = None + cls, num_qubits: int, size: int = 1, rng: Optional[Union[int, Generator]] = None ): """Generate a list of random clifford circuits""" if num_qubits > 2: @@ -120,19 +124,20 @@ def random_clifford_circuits( if num_qubits == 1: samples = rng.integers(24, size=size) - return [self.clifford_1_qubit_circuit(i) for i in samples] + return [cls.clifford_1_qubit_circuit(i) for i in samples] else: samples = rng.integers(11520, size=size) - return [self.clifford_2_qubit_circuit(i) for i in samples] + return [cls.clifford_2_qubit_circuit(i) for i in samples] + @classmethod @lru_cache(maxsize=24) - def clifford_1_qubit_circuit(self, num): + def clifford_1_qubit_circuit(cls, num): """Return the 1-qubit clifford circuit corresponding to `num` where `num` is between 0 and 23. """ # pylint: disable=unbalanced-tuple-unpacking # This is safe since `_unpack_num` returns list the size of the sig - (i, j, p) = self._unpack_num(num, self.CLIFFORD_1_QUBIT_SIG) + (i, j, p) = cls._unpack_num(num, cls.CLIFFORD_1_QUBIT_SIG) qr = QuantumRegister(1) qc = QuantumCircuit(qr) if i == 1: @@ -149,12 +154,13 @@ def clifford_1_qubit_circuit(self, num): qc.z(0) return qc + @classmethod @lru_cache(maxsize=11520) - def clifford_2_qubit_circuit(self, num): + def clifford_2_qubit_circuit(cls, num): """Return the 2-qubit clifford circuit corresponding to `num` where `num` is between 0 and 11519. """ - vals = self._unpack_num_multi_sigs(num, self.CLIFFORD_2_QUBIT_SIGS) + vals = cls._unpack_num_multi_sigs(num, cls.CLIFFORD_2_QUBIT_SIGS) qr = QuantumRegister(2) qc = QuantumCircuit(qr) if vals[0] == 0 or vals[0] == 3: @@ -203,7 +209,8 @@ def clifford_2_qubit_circuit(self, num): qc.z(1) return qc - def _unpack_num(self, num, sig): + @classmethod + def _unpack_num(cls, num, sig): r"""Returns a tuple :math:`(a_1, \ldots, a_n)` where :math:`0 \le a_i \le \sigma_i` where sig=:math:`(\sigma_1, \ldots, \sigma_n)` and num is the sequential @@ -215,7 +222,8 @@ def _unpack_num(self, num, sig): num //= k return res - def _unpack_num_multi_sigs(self, num, sigs): + @classmethod + def _unpack_num_multi_sigs(cls, num, sigs): """Returns the result of `_unpack_num` on one of the signatures in `sigs` """ @@ -224,23 +232,26 @@ def _unpack_num_multi_sigs(self, num, sigs): for k in sig: sig_size *= k if num < sig_size: - return [i] + self._unpack_num(num, sig) + return [i] + cls._unpack_num(num, sig) num -= sig_size return None - def transpile_single_clifford(self, cliff_circ : QuantumCircuit, basis_gates : List[str]): + @classmethod + def transpile_single_clifford(cls, cliff_circ : QuantumCircuit, basis_gates : List[str]): backend = AerSimulator() return transpile(cliff_circ, backend, optimization_level=1, basis_gates=basis_gates) - def generate_1q_transpiled_clifford_circuits(self, basis_gates : List[str]): + @classmethod + def generate_1q_transpiled_clifford_circuits(cls, basis_gates : List[str]): transpiled_circs = [] for num in range(0, 24): - circ = self.clifford_1_qubit_circuit(num=num) - transpiled_circ = self.transpile_single_clifford(circ, basis_gates) + circ = cls.clifford_1_qubit_circuit(num=num) + transpiled_circ = cls.transpile_single_clifford(circ, basis_gates) transpiled_circs.append(transpiled_circ) return transpiled_circs - def num_from_1_qubit_clifford_single_gate(self, inst, basis_gates): + @classmethod + def num_from_1_qubit_clifford_single_gate(cls, inst, basis_gates): """ This method does the reverse of clifford_1_qubit_circuit - given a clifford, it returns the corresponding integer, with the mapping @@ -250,8 +261,6 @@ def num_from_1_qubit_clifford_single_gate(self, inst, basis_gates): one of these sets. """ name = inst.name - #general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z"] - #transpiled_cliff_list = ["sx", "rz", "cx"] gates_with_delay = basis_gates.copy() gates_with_delay.append("delay") @@ -259,11 +268,11 @@ def num_from_1_qubit_clifford_single_gate(self, inst, basis_gates): raise QiskitError( "Instruction {} is not in the basis gates".format(inst.name) ) - if(set(basis_gates).issubset(set(self.general_cliff_list))): + if(set(basis_gates).issubset(set(cls.general_cliff_list))): num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22, "delay":0} return num_dict[name] - if (set(basis_gates).issubset(set(self.transpiled_cliff_list))): + if (set(basis_gates).issubset(set(cls.transpiled_cliff_list))): if name == "sx": return 8 if name == "delay": @@ -284,9 +293,12 @@ def num_from_1_qubit_clifford_single_gate(self, inst, basis_gates): "Instruction {} could not be converted to Clifford gate".format(name) ) - def compose_num_with_clifford(self, composed_num, qc, + @classmethod + def compose_num_with_clifford(cls, composed_num, qc, basis_gates) -> int: + # MAP_CLIFFORD_NUM_TO_ARRAY_INDEX = {0:0, 1:1, 2:2, 4:3, 6:4, 8:5, 12:6, 18:7, 22:8} for inst in qc: - num = CliffordUtils().num_from_1_qubit_clifford_single_gate(inst=inst[0], basis_gates=basis_gates) + num = cls.num_from_1_qubit_clifford_single_gate(inst=inst[0], basis_gates=basis_gates) composed_num = CLIFF_COMPOSE_DATA[composed_num, num] return composed_num + diff --git a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py index ef1ce8aa54..afc003ddbe 100644 --- a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py +++ b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py @@ -2,13 +2,11 @@ from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils def create_compose_map(): - utils = CliffordUtils() - num_to_cliff = {} cliff_to_num = {} for i in range(24): - cliff = utils.clifford_1_qubit(i) + cliff = CliffordUtils.clifford_1_qubit(i) num_to_cliff[i] = cliff cliff_to_num[cliff.__repr__()] = i diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index 09677803a7..12264c4ac3 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -103,7 +103,7 @@ def circuits(self) -> List[QuantumCircuit]: circuits = [] if self._transpiled_rb and self._transpiled_cliff_circuits == None: self._transpiled_cliff_circuits = \ - self._clifford_utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) + CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: self._set_transpiled_interleaved_element() @@ -118,7 +118,7 @@ def circuits(self) -> List[QuantumCircuit]: def _sample_circuits(self, lengths, rng): circuits = [] for length in lengths if self._full_sampling else [lengths[-1]]: - elements = self._clifford_utils.random_clifford_circuits(self.num_qubits, length, rng) + elements = CliffordUtils.random_clifford_circuits(self.num_qubits, length, rng) element_lengths = [len(elements)] if self._full_sampling else lengths std_circuits = self._generate_circuit(elements, element_lengths) for circuit in std_circuits: @@ -185,7 +185,7 @@ def _set_transpiled_interleaved_element(self): basis_gates = self.transpile_options.basis_gates else: basis_gates = None - self._transpiled_interleaved_elem = self._clifford_utils.transpile_single_clifford( + self._transpiled_interleaved_elem = CliffordUtils.transpile_single_clifford( qc_interleaved, basis_gates = basis_gates ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index cca253cd43..2d2f780673 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -95,7 +95,6 @@ def __init__( # Set fixed options self._full_sampling = full_sampling self._transpiled_rb = transpiled_rb - self._clifford_utils = CliffordUtils() self._transpiled_cliff_circuits = None def _verify_parameters(self, lengths, num_samples): @@ -141,7 +140,7 @@ def circuits(self) -> List[QuantumCircuit]: circuits = [] if self._transpiled_rb and self._transpiled_cliff_circuits == None: self._transpiled_cliff_circuits = \ - self._clifford_utils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) + CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng) @@ -163,7 +162,7 @@ def _sample_circuits(self, lengths: Iterable[int], rng: Generator) -> List[Quant """ circuits = [] for length in lengths if self._full_sampling else [lengths[-1]]: - elements = self._clifford_utils.random_clifford_circuits(self.num_qubits, length, rng) + elements = CliffordUtils.random_clifford_circuits(self.num_qubits, length, rng) element_lengths = [len(elements)] if self._full_sampling else lengths circuits += self._generate_circuit(elements, element_lengths) return circuits @@ -270,16 +269,16 @@ def _build_rb_circuits(self, lengths, rng, interleaved_element=None): # choose random clifford next_circ = self._transpiled_cliff_circuits[rand] circ.compose(next_circ, inplace=True) - composed_cliff_num = self._clifford_utils.compose_num_with_clifford(composed_cliff_num, next_circ, + composed_cliff_num = CliffordUtils.compose_num_with_clifford(composed_cliff_num, next_circ, self.transpile_options.basis_gates) circ.barrier(0) if is_interleaved: interleaved_circ.compose(next_circ, inplace=True) - composed_interleaved_num = self._clifford_utils.compose_num_with_clifford(composed_interleaved_num, next_circ, + composed_interleaved_num = CliffordUtils.compose_num_with_clifford(composed_interleaved_num, next_circ, self.transpile_options.basis_gates) interleaved_circ.barrier(0) interleaved_circ.compose(interleaved_element, inplace=True) - composed_interleaved_num = self._clifford_utils.compose_num_with_clifford(composed_interleaved_num, + composed_interleaved_num = CliffordUtils.compose_num_with_clifford(composed_interleaved_num, interleaved_element, self.transpile_options.basis_gates) interleaved_circ.barrier(0) @@ -349,18 +348,18 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, interleaved_element=Non rb_circ.compose(next_circ, inplace=True) composed_cliff_num = \ - self._clifford_utils.compose_num_with_clifford(composed_num=composed_cliff_num, qc=next_circ, + CliffordUtils.compose_num_with_clifford(composed_num=composed_cliff_num, qc=next_circ, basis_gates=self.transpile_options.basis_gates) rb_circ.barrier(0) if is_interleaved: rb_interleaved_circ.compose(next_circ, inplace=True) composed_interleaved_num = \ - self._clifford_utils.compose_num_with_clifford(composed_num=composed_interleaved_num, qc=next_circ, + CliffordUtils.compose_num_with_clifford(composed_num=composed_interleaved_num, qc=next_circ, basis_gates=self.transpile_options.basis_gates) rb_interleaved_circ.barrier(0) rb_interleaved_circ.compose(interleaved_element, inplace=True) composed_interleaved_num = \ - self._clifford_utils.compose_num_with_clifford(composed_interleaved_num, interleaved_element, + CliffordUtils.compose_num_with_clifford(composed_interleaved_num, interleaved_element, self.transpile_options.basis_gates) rb_interleaved_circ.barrier(0) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index a8301189be..27ec612080 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -361,10 +361,9 @@ def test_single_qubit(self): Clifford circuit. """ interleaved_gate = SXGate() - utils = CliffordUtils() random.seed(123) num = random.randint(0, 23) - interleaved_clifford = utils.clifford_1_qubit_circuit(num) + interleaved_clifford = CliffordUtils.clifford_1_qubit_circuit(num) # The circuit created for interleaved_clifford is: # qc = QuantumCircuit(1) # qc.rz(np.pi/2, 0) From b79b5bf01b2962e1128fdd491f53f4d0da24f157 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Thu, 30 Jun 2022 12:45:54 +0300 Subject: [PATCH 33/39] Fixes following changes in CliffordUtils --- test/randomized_benchmarking/test_rb_utils.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/randomized_benchmarking/test_rb_utils.py b/test/randomized_benchmarking/test_rb_utils.py index 9b2c83694c..89ee167966 100644 --- a/test/randomized_benchmarking/test_rb_utils.py +++ b/test/randomized_benchmarking/test_rb_utils.py @@ -208,14 +208,12 @@ def test_clifford_1_qubit_generation(self): {"stabilizer": ["-Y"], "destabilizer": ["+Z"]}, ] cliffords = [Clifford.from_dict(i) for i in clifford_dicts] - utils = rb.CliffordUtils() for n in range(24): - clifford = utils.clifford_1_qubit(n) + clifford = CliffordUtils.clifford_1_qubit(n) self.assertEqual(clifford, cliffords[n]) def test_clifford_2_qubit_generation(self): """Verify 2-qubit clifford indeed generates the correct group""" - utils = rb.CliffordUtils() pauli_free_elements = [ 0, 1, @@ -940,7 +938,7 @@ def test_clifford_2_qubit_generation(self): ] cliffords = [] for n in pauli_free_elements: - clifford = utils.clifford_2_qubit(n) + clifford = CliffordUtils.clifford_2_qubit(n) phase = clifford.table.phase for i in range(4): self.assertFalse(phase[i]) @@ -1009,7 +1007,7 @@ def test_clifford_2_qubit_generation(self): phases = [] table = None for n in pauli_check_elements: - clifford = utils.clifford_2_qubit(n) + clifford = CliffordUtils.clifford_2_qubit(n) if table is None: table = clifford.table.array else: @@ -1020,7 +1018,7 @@ def test_clifford_2_qubit_generation(self): phases.append(phase) def test_number_to_clifford_mapping_single_gate(self): - """ Testing that the methods num_from_1_qubit_clifford and + """ Testing that the methods num_from_1_qubit_clifford_single_gate and clifford_1_qubit_circuit perform the reverse operations from each other""" transpiled_cliff_list = [SXGate(), RZGate(np.pi), RZGate(-np.pi), @@ -1037,7 +1035,7 @@ def test_number_to_clifford_mapping_single_gate(self): general_cliff_list = [IGate(), HGate(), SdgGate(), SGate(), XGate(), SXGate(), YGate(), ZGate()] general_cliff_names = [gate.name for gate in general_cliff_list] for inst in general_cliff_list: - num = CliffordUtils.num_from_1_qubit_clifford(inst, general_cliff_names) + num = CliffordUtils.num_from_1_qubit_clifford_single_gate(inst, general_cliff_names) qc_from_num = CliffordUtils.clifford_1_qubit_circuit(num=num) qr = QuantumRegister(1) qc_from_inst = QuantumCircuit(qr) @@ -1050,5 +1048,5 @@ def test_number_to_clifford_mapping(self): transpiled_cliff_names = [gate.name for gate in transpiled_cliff_list] all_transpiled_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(transpiled_cliff_names) for index, qc in enumerate(all_transpiled_circuits): - num = CliffordUtils.num_from_1_qubit_clifford(qc, transpiled_cliff_names) + num = CliffordUtils.compose_num_with_clifford(0, qc, transpiled_cliff_names) assert(num == index) From 96046a5a47d308c8c768cb916d476a729d00ab69 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Thu, 30 Jun 2022 14:32:15 +0300 Subject: [PATCH 34/39] Changed structure of CLIFF_COMPOSE_DATA to be an array instead of a dict, for performance reasons. The index in the array is computed in compose_num_with_clifford --- .../randomized_benchmarking/clifford_data.py | 443 +++++++++--------- .../randomized_benchmarking/clifford_utils.py | 14 +- .../create_clifford_map.py | 6 +- 3 files changed, 235 insertions(+), 228 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py index 1e03f89aa4..7aa8131716 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py @@ -11,227 +11,232 @@ # that they have been altered from the originals. """ This file contains the Clifford group represented as integers. +In CLIFF_COMPOSE_DATA, (i, j): k represents Clifford(i).compose(clifford(j)) = Clifford(k). +Since retrieving a value from an array is more efficient than from a dict, therefore +we store only the results in an array. The index is computed in c +CliffordUtils.compose_num_with_clifford(). +Note that for the pairs (i, j), i can be any clifford, j represents only the +1-gate cliffords, as listed in CliffordUtils.general_cliff_list """ -#In CLIFF_COMPOSE_DATA, (i, j): k represents Clifford(i).compose(clifford(j)) = Clifford(k) -CLIFF_COMPOSE_DATA = { - (0, 0):0, - (0, 1):1, - (0, 2):2, - (0, 4):4, - (0, 6):6, - (0, 8):8, - (0, 12):12, - (0, 18):18, - (0, 22):22, - (1, 0):1, - (1, 1):0, - (1, 2):3, - (1, 4):5, - (1, 6):7, - (1, 8):9, - (1, 12):13, - (1, 18):19, - (1, 22):23, - (2, 0):2, - (2, 1):23, - (2, 2):6, - (2, 4):15, - (2, 6):8, - (2, 8):0, - (2, 12):14, - (2, 18):20, - (2, 22):9, - (3, 0):3, - (3, 1):22, - (3, 2):7, - (3, 4):14, - (3, 6):9, - (3, 8):1, - (3, 12):15, - (3, 18):21, - (3, 22):8, - (4, 0):4, - (4, 1):9, - (4, 2):17, - (4, 4):18, - (4, 6):10, - (4, 8):23, - (4, 12):16, - (4, 18):22, - (4, 22):0, - (5, 0):5, - (5, 1):8, - (5, 2):16, - (5, 4):19, - (5, 6):11, - (5, 8):22, - (5, 12):17, - (5, 18):23, - (5, 22):1, - (6, 0):6, - (6, 1):19, - (6, 2):8, - (6, 4):16, - (6, 6):0, - (6, 8):2, - (6, 12):18, - (6, 18):12, - (6, 22):10, - (7, 0):7, - (7, 1):18, - (7, 2):9, - (7, 4):17, - (7, 6):1, - (7, 8):3, - (7, 12):19, - (7, 18):13, - (7, 22):11, - (8, 0):8, - (8, 1):5, - (8, 2):0, - (8, 4):3, - (8, 6):2, - (8, 8):6, - (8, 12):20, - (8, 18):14, - (8, 22):21, - (9, 0):9, - (9, 1):4, - (9, 2):1, - (9, 4):2, - (9, 6):3, - (9, 8):7, - (9, 12):21, - (9, 18):15, - (9, 22):20, - (10, 0):10, - (10, 1):15, - (10, 2):23, - (10, 4):6, - (10, 6):4, - (10, 8):17, - (10, 12):22, - (10, 18):16, - (10, 22):12, - (11, 0):11, - (11, 1):14, - (11, 2):22, - (11, 4):7, - (11, 6):5, - (11, 8):16, - (11, 12):23, - (11, 18):17, - (11, 22):13, - (12, 0):12, - (12, 1):13, - (12, 2):20, - (12, 4):10, - (12, 6):18, - (12, 8):14, - (12, 12):0, - (12, 18):6, - (12, 22):16, - (13, 0):13, - (13, 1):12, - (13, 2):21, - (13, 4):11, - (13, 6):19, - (13, 8):15, - (13, 12):1, - (13, 18):7, - (13, 22):17, - (14, 0):14, - (14, 1):11, - (14, 2):12, - (14, 4):21, - (14, 6):20, - (14, 8):18, - (14, 12):2, - (14, 18):8, - (14, 22):3, - (15, 0):15, - (15, 1):10, - (15, 2):13, - (15, 4):20, - (15, 6):21, - (15, 8):19, - (15, 12):3, - (15, 18):9, - (15, 22):2, - (16, 0):16, - (16, 1):21, - (16, 2):11, - (16, 4):12, - (16, 6):22, - (16, 8):5, - (16, 12):4, - (16, 18):10, - (16, 22):6, - (17, 0):17, - (17, 1):20, - (17, 2):10, - (17, 4):13, - (17, 6):23, - (17, 8):4, - (17, 12):5, - (17, 18):11, - (17, 22):7, - (18, 0):18, - (18, 1):7, - (18, 2):14, - (18, 4):22, - (18, 6):12, - (18, 8):20, - (18, 12):6, - (18, 18):0, - (18, 22):4, - (19, 0):19, - (19, 1):6, - (19, 2):15, - (19, 4):23, - (19, 6):13, - (19, 8):21, - (19, 12):7, - (19, 18):1, - (19, 22):5, - (20, 0):20, - (20, 1):17, - (20, 2):18, - (20, 4):9, - (20, 6):14, - (20, 8):12, - (20, 12):8, - (20, 18):2, - (20, 22):15, - (21, 0):21, - (21, 1):16, - (21, 2):19, - (21, 4):8, - (21, 6):15, - (21, 8):13, - (21, 12):9, - (21, 18):3, - (21, 22):14, - (22, 0):22, - (22, 1):3, - (22, 2):5, - (22, 4):0, - (22, 6):16, - (22, 8):11, - (22, 12):10, - (22, 18):4, - (22, 22):18, - (23, 0):23, - (23, 1):2, - (23, 2):4, - (23, 4):1, - (23, 6):17, - (23, 8):10, - (23, 12):11, - (23, 18):5, - (23, 22):19, - } +CLIFF_COMPOSE_DATA = [ + 0, + 1, + 2, + 4, + 6, + 8, + 12, + 18, + 22, + 1, + 0, + 3, + 5, + 7, + 9, + 13, + 19, + 23, + 2, + 23, + 6, + 15, + 8, + 0, + 14, + 20, + 9, + 3, + 22, + 7, + 14, + 9, + 1, + 15, + 21, + 8, + 4, + 9, + 17, + 18, + 10, + 23, + 16, + 22, + 0, + 5, + 8, + 16, + 19, + 11, + 22, + 17, + 23, + 1, + 6, + 19, + 8, + 16, + 0, + 2, + 18, + 12, + 10, + 7, + 18, + 9, + 17, + 1, + 3, + 19, + 13, + 11, + 8, + 5, + 0, + 3, + 2, + 6, + 20, + 14, + 21, + 9, + 4, + 1, + 2, + 3, + 7, + 21, + 15, + 20, + 10, + 15, + 23, + 6, + 4, + 17, + 22, + 16, + 12, + 11, + 14, + 22, + 7, + 5, + 16, + 23, + 17, + 13, + 12, + 13, + 20, + 10, + 18, + 14, + 0, + 6, + 16, + 13, + 12, + 21, + 11, + 19, + 15, + 1, + 7, + 17, + 14, + 11, + 12, + 21, + 20, + 18, + 2, + 8, + 3, + 15, + 10, + 13, + 20, + 21, + 19, + 3, + 9, + 2, + 16, + 21, + 11, + 12, + 22, + 5, + 4, + 10, + 6, + 17, + 20, + 10, + 13, + 23, + 4, + 5, + 11, + 7, + 18, + 7, + 14, + 22, + 12, + 20, + 6, + 0, + 4, + 19, + 6, + 15, + 23, + 13, + 21, + 7, + 1, + 5, + 20, + 17, + 18, + 9, + 14, + 12, + 8, + 2, + 15, + 21, + 16, + 19, + 8, + 15, + 13, + 9, + 3, + 14, + 22, + 3, + 5, + 0, + 16, + 11, + 10, + 4, + 18, + 23, + 2, + 4, + 1, + 17, + 10, + 11, + 5, + 19, + ] # In CLIFF_INVERSE_DATA, i: j represents Clifford(i).inverse = Clifford(j) CLIFF_INVERSE_DATA = [ diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 8b9809bf01..cf5ce87430 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -70,8 +70,9 @@ class CliffordUtils: (2, 2, 3, 3, 3, 3, 4, 4), (2, 2, 3, 3, 4, 4), ] - general_cliff_list = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z", "cx"] - transpiled_cliff_list = ["sx", "rz", "cx"] + GENERAL_CLIFF_LIST = ["id", "h", "sdg", "s", "x", "sx", "sxdg", "y", "z", "cx"] + TRANSPILED_CLIFF_LIST = ["sx", "rz", "cx"] + NUM_SINGLE_GATE_1_QUBIT_CLIFF = 9 @classmethod def clifford_1_qubit(cls, num): @@ -268,11 +269,11 @@ def num_from_1_qubit_clifford_single_gate(cls, inst, basis_gates): raise QiskitError( "Instruction {} is not in the basis gates".format(inst.name) ) - if(set(basis_gates).issubset(set(cls.general_cliff_list))): + if(set(basis_gates).issubset(set(cls.GENERAL_CLIFF_LIST))): num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22, "delay":0} return num_dict[name] - if (set(basis_gates).issubset(set(cls.transpiled_cliff_list))): + if (set(basis_gates).issubset(set(cls.TRANSPILED_CLIFF_LIST))): if name == "sx": return 8 if name == "delay": @@ -296,9 +297,10 @@ def num_from_1_qubit_clifford_single_gate(cls, inst, basis_gates): @classmethod def compose_num_with_clifford(cls, composed_num, qc, basis_gates) -> int: - # MAP_CLIFFORD_NUM_TO_ARRAY_INDEX = {0:0, 1:1, 2:2, 4:3, 6:4, 8:5, 12:6, 18:7, 22:8} + MAP_CLIFFORD_NUM_TO_ARRAY_INDEX = {0:0, 1:1, 2:2, 4:3, 6:4, 8:5, 12:6, 18:7, 22:8} for inst in qc: num = cls.num_from_1_qubit_clifford_single_gate(inst=inst[0], basis_gates=basis_gates) - composed_num = CLIFF_COMPOSE_DATA[composed_num, num] + index = cls.NUM_SINGLE_GATE_1_QUBIT_CLIFF * composed_num + MAP_CLIFFORD_NUM_TO_ARRAY_INDEX[num] + composed_num = CLIFF_COMPOSE_DATA[index] return composed_num diff --git a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py index afc003ddbe..23c95bc019 100644 --- a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py +++ b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py @@ -26,10 +26,10 @@ def create_compose_map(): cliff = cliff1.adjoint() invs[i] = cliff_to_num[cliff.__repr__()] - print("CLIFF_COMPOSE_DATA = {") + print("CLIFF_COMPOSE_DATA = [") for i in products: - print(f" {i}:{products[i]},") - print(" }") + print(f" {products[i]},") + print(" ]") print() print("CLIFF_INVERSE_DATA = [") From 352539eb0971dee28195a7c27f56f7abea9831fc Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 3 Jul 2022 12:13:17 +0300 Subject: [PATCH 35/39] Improved _layout_for_rb_single_qubit to be more robust --- .../randomized_benchmarking/rb_experiment.py | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 2d2f780673..9563d39bdc 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -21,8 +21,8 @@ from numpy.random.bit_generator import BitGenerator, SeedSequence import time -from qiskit import QuantumCircuit, QuantumRegister, QiskitError -from qiskit.circuit import Instruction +from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, QiskitError +from qiskit.circuit import Instruction, Clbit from qiskit.circuit.quantumregister import Qubit from qiskit.quantum_info import Clifford from qiskit.providers.backend import Backend @@ -395,24 +395,39 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, interleaved_element=Non # We simply copy the circuit to a new circuit where we define the mapping # of the qubit to the single physical qubit that was requested by the user # This is a hack, and would be better if transpile() implemented it. + # Something similar is done in ParallelExperiment._combined_circuits def _layout_for_rb_single_qubit(self): - circuits = self.circuits() transpiled = [] - for c in circuits: - qr = QuantumRegister(c.num_qubits, name='q') + qargs_map = {0: self.physical_qubits[0]} + for circ in self.circuits(): + qr = QuantumRegister(circ.num_qubits, name='q') qubit = Qubit(qr, self.physical_qubits[0]) - c_new = QuantumCircuit( - *c.qregs, - *c.cregs, - name=c.name, - global_phase=c.global_phase, - metadata=c.metadata + new_circ = QuantumCircuit( + *circ.qregs, + name=circ.name, + global_phase=circ.global_phase, + metadata=circ.metadata.copy() ) - new_data = [] - for inst, qargs, cargs in c.data: - new_data.append((inst, [qubit], cargs)) - c_new.data = new_data - transpiled.append(c_new) + clbits = circ.num_clbits + if clbits: + creg = ClassicalRegister(clbits) + new_cargs = [Clbit(creg, i) for i in range(clbits)] + new_circ.add_register(creg) + else: + cargs = [] + + for inst, qargs, cargs in circ.data: + mapped_cargs = [new_cargs[circ.find_bit(clbit).index] for clbit in cargs] + mapped_qargs = [ + circ.qubits[qargs_map[circ.find_bit(i).index]] for i in qargs + ] + new_circ.data.append((inst, mapped_qargs, mapped_cargs)) + # Add the calibrations + for gate, cals in circ.calibrations.items(): + for key, sched in cals.items(): + new_circ.add_calibration(gate, qubits=key[0], schedule=sched, params=key[1]) + + transpiled.append(new_circ) return transpiled def _transpiled_circuits(self) -> List[QuantumCircuit]: From b10b1c68a694bf8f39003579c7b3a0a33615c340 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 3 Jul 2022 14:58:59 +0300 Subject: [PATCH 36/39] Documentation, black, pylint --- .../randomized_benchmarking/clifford_data.py | 486 +++++++++--------- .../randomized_benchmarking/clifford_utils.py | 57 +- .../create_clifford_map.py | 42 +- .../interleaved_rb_experiment.py | 25 +- .../randomized_benchmarking/rb_experiment.py | 163 ++++-- .../test_randomized_benchmarking.py | 51 +- test/randomized_benchmarking/test_rb_utils.py | 49 +- 7 files changed, 504 insertions(+), 369 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py index 7aa8131716..fdb298ef64 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py @@ -9,6 +9,7 @@ # Any modifications or derivative works of this code must retain this # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. + """ This file contains the Clifford group represented as integers. In CLIFF_COMPOSE_DATA, (i, j): k represents Clifford(i).compose(clifford(j)) = Clifford(k). @@ -20,249 +21,248 @@ """ CLIFF_COMPOSE_DATA = [ - 0, - 1, - 2, - 4, - 6, - 8, - 12, - 18, - 22, - 1, - 0, - 3, - 5, - 7, - 9, - 13, - 19, - 23, - 2, - 23, - 6, - 15, - 8, - 0, - 14, - 20, - 9, - 3, - 22, - 7, - 14, - 9, - 1, - 15, - 21, - 8, - 4, - 9, - 17, - 18, - 10, - 23, - 16, - 22, - 0, - 5, - 8, - 16, - 19, - 11, - 22, - 17, - 23, - 1, - 6, - 19, - 8, - 16, - 0, - 2, - 18, - 12, - 10, - 7, - 18, - 9, - 17, - 1, - 3, - 19, - 13, - 11, - 8, - 5, - 0, - 3, - 2, - 6, - 20, - 14, - 21, - 9, - 4, - 1, - 2, - 3, - 7, - 21, - 15, - 20, - 10, - 15, - 23, - 6, - 4, - 17, - 22, - 16, - 12, - 11, - 14, - 22, - 7, - 5, - 16, - 23, - 17, - 13, - 12, - 13, - 20, - 10, - 18, - 14, - 0, - 6, - 16, - 13, - 12, - 21, - 11, - 19, - 15, - 1, - 7, - 17, - 14, - 11, - 12, - 21, - 20, - 18, - 2, - 8, - 3, - 15, - 10, - 13, - 20, - 21, - 19, - 3, - 9, - 2, - 16, - 21, - 11, - 12, - 22, - 5, - 4, - 10, - 6, - 17, - 20, - 10, - 13, - 23, - 4, - 5, - 11, - 7, - 18, - 7, - 14, - 22, - 12, - 20, - 6, - 0, - 4, - 19, - 6, - 15, - 23, - 13, - 21, - 7, - 1, - 5, - 20, - 17, - 18, - 9, - 14, - 12, - 8, - 2, - 15, - 21, - 16, - 19, - 8, - 15, - 13, - 9, - 3, - 14, - 22, - 3, - 5, - 0, - 16, - 11, - 10, - 4, - 18, - 23, - 2, - 4, - 1, - 17, - 10, - 11, - 5, - 19, - ] + 0, + 1, + 2, + 4, + 6, + 8, + 12, + 18, + 22, + 1, + 0, + 3, + 5, + 7, + 9, + 13, + 19, + 23, + 2, + 23, + 6, + 15, + 8, + 0, + 14, + 20, + 9, + 3, + 22, + 7, + 14, + 9, + 1, + 15, + 21, + 8, + 4, + 9, + 17, + 18, + 10, + 23, + 16, + 22, + 0, + 5, + 8, + 16, + 19, + 11, + 22, + 17, + 23, + 1, + 6, + 19, + 8, + 16, + 0, + 2, + 18, + 12, + 10, + 7, + 18, + 9, + 17, + 1, + 3, + 19, + 13, + 11, + 8, + 5, + 0, + 3, + 2, + 6, + 20, + 14, + 21, + 9, + 4, + 1, + 2, + 3, + 7, + 21, + 15, + 20, + 10, + 15, + 23, + 6, + 4, + 17, + 22, + 16, + 12, + 11, + 14, + 22, + 7, + 5, + 16, + 23, + 17, + 13, + 12, + 13, + 20, + 10, + 18, + 14, + 0, + 6, + 16, + 13, + 12, + 21, + 11, + 19, + 15, + 1, + 7, + 17, + 14, + 11, + 12, + 21, + 20, + 18, + 2, + 8, + 3, + 15, + 10, + 13, + 20, + 21, + 19, + 3, + 9, + 2, + 16, + 21, + 11, + 12, + 22, + 5, + 4, + 10, + 6, + 17, + 20, + 10, + 13, + 23, + 4, + 5, + 11, + 7, + 18, + 7, + 14, + 22, + 12, + 20, + 6, + 0, + 4, + 19, + 6, + 15, + 23, + 13, + 21, + 7, + 1, + 5, + 20, + 17, + 18, + 9, + 14, + 12, + 8, + 2, + 15, + 21, + 16, + 19, + 8, + 15, + 13, + 9, + 3, + 14, + 22, + 3, + 5, + 0, + 16, + 11, + 10, + 4, + 18, + 23, + 2, + 4, + 1, + 17, + 10, + 11, + 5, + 19, +] # In CLIFF_INVERSE_DATA, i: j represents Clifford(i).inverse = Clifford(j) CLIFF_INVERSE_DATA = [ - 0, - 1, - 8, - 5, - 22, - 3, - 6, - 19, - 2, - 23, - 10, - 15, - 12, - 13, - 14, - 11, - 16, - 21, - 18, - 7, - 20, - 17, - 4, - 9, - ] - + 0, + 1, + 8, + 5, + 22, + 3, + 6, + 19, + 2, + 23, + 10, + 15, + 12, + 13, + 14, + 11, + 16, + 21, + 18, + 7, + 20, + 17, + 4, + 9, +] diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index cf5ce87430..ab6b48e1b1 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -15,17 +15,18 @@ from typing import Optional, Union, List from functools import lru_cache +from math import isclose import numpy as np from numpy.random import Generator, default_rng -from math import isclose + from qiskit import QuantumCircuit, QuantumRegister -from qiskit.circuit import Gate, Instruction +from qiskit.circuit import Gate from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate from qiskit.quantum_info import Clifford, random_clifford from qiskit.compiler import transpile from qiskit.providers.aer import AerSimulator -from .clifford_data import CLIFF_COMPOSE_DATA, CLIFF_INVERSE_DATA from qiskit.exceptions import QiskitError +from .clifford_data import CLIFF_COMPOSE_DATA class VGate(Gate): @@ -238,12 +239,14 @@ def _unpack_num_multi_sigs(cls, num, sigs): return None @classmethod - def transpile_single_clifford(cls, cliff_circ : QuantumCircuit, basis_gates : List[str]): + def transpile_single_clifford(cls, cliff_circ: QuantumCircuit, basis_gates: List[str]): + """Transpile a single clifford circuit using basis_gates.""" backend = AerSimulator() return transpile(cliff_circ, backend, optimization_level=1, basis_gates=basis_gates) @classmethod - def generate_1q_transpiled_clifford_circuits(cls, basis_gates : List[str]): + def generate_1q_transpiled_clifford_circuits(cls, basis_gates: List[str]): + """Generate all transpiled clifford circuits""" transpiled_circs = [] for num in range(0, 24): circ = cls.clifford_1_qubit_circuit(num=num) @@ -266,14 +269,23 @@ def num_from_1_qubit_clifford_single_gate(cls, inst, basis_gates): gates_with_delay = basis_gates.copy() gates_with_delay.append("delay") if not name in gates_with_delay: - raise QiskitError( - "Instruction {} is not in the basis gates".format(inst.name) - ) - if(set(basis_gates).issubset(set(cls.GENERAL_CLIFF_LIST))): - num_dict = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22, "delay":0} + raise QiskitError("Instruction {} is not in the basis gates".format(inst.name)) + if set(basis_gates).issubset(set(cls.GENERAL_CLIFF_LIST)): + num_dict = { + "id": 0, + "h": 1, + "sxdg": 2, + "s": 4, + "x": 6, + "sx": 8, + "y": 12, + "z": 18, + "sdg": 22, + "delay": 0, + } return num_dict[name] - if (set(basis_gates).issubset(set(cls.TRANSPILED_CLIFF_LIST))): + if set(basis_gates).issubset(set(cls.TRANSPILED_CLIFF_LIST)): if name == "sx": return 8 if name == "delay": @@ -290,17 +302,24 @@ def num_from_1_qubit_clifford_single_gate(cls, inst, basis_gates): else: raise QiskitError("wrong param {} for rz in clifford".format(inst.params[0])) - raise QiskitError( - "Instruction {} could not be converted to Clifford gate".format(name) - ) + raise QiskitError("Instruction {} could not be converted to Clifford gate".format(name)) @classmethod - def compose_num_with_clifford(cls, composed_num, qc, - basis_gates) -> int: - MAP_CLIFFORD_NUM_TO_ARRAY_INDEX = {0:0, 1:1, 2:2, 4:3, 6:4, 8:5, 12:6, 18:7, 22:8} + def compose_num_with_clifford( + cls, composed_num: int, qc: QuantumCircuit, basis_gates: List[str] + ) -> int: + """Compose a number that represents a Clifford, with a single-gate Clifford, and return the + number that represents the resulting Clifford.""" + + # The numbers corresponding to single gate Cliffords are not in sequence - + # see num_from_1_qubit_clifford_single_gate. In order to compute the index in + # the array CLIFF_COMPOSE_DATA, we map the numbers to [0, 8]. + map_clifford_num_to_array_index = {0: 0, 1: 1, 2: 2, 4: 3, 6: 4, 8: 5, 12: 6, 18: 7, 22: 8} for inst in qc: num = cls.num_from_1_qubit_clifford_single_gate(inst=inst[0], basis_gates=basis_gates) - index = cls.NUM_SINGLE_GATE_1_QUBIT_CLIFF * composed_num + MAP_CLIFFORD_NUM_TO_ARRAY_INDEX[num] + index = ( + cls.NUM_SINGLE_GATE_1_QUBIT_CLIFF * composed_num + + map_clifford_num_to_array_index[num] + ) composed_num = CLIFF_COMPOSE_DATA[index] return composed_num - diff --git a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py index 23c95bc019..c5f02b1276 100644 --- a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py +++ b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py @@ -1,7 +1,22 @@ -# Written by Sasha +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +This is a script used to create the data in clifford_data.py. +""" from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils + def create_compose_map(): + """Creates the data in CLIFF_COMPOSE_DATA and CLIFF_INVERSE_DATA""" num_to_cliff = {} cliff_to_num = {} @@ -12,10 +27,22 @@ def create_compose_map(): products = {} - single_gate_clifford_mapping = {"id":0, "h":1, "sxdg":2, "s":4, "x":6, "sx":8, "y":12, "z":18, "sdg":22} + single_gate_clifford_mapping = { + "id": 0, + "h": 1, + "sxdg": 2, + "s": 4, + "x": 6, + "sx": 8, + "y": 12, + "z": 18, + "sdg": 22, + } + for i in range(24): cliff1 = num_to_cliff[i] - for gate in single_gate_clifford_mapping.keys(): + # for gate in single_gate_clifford_mapping.keys(): + for gate in single_gate_clifford_mapping: cliff2 = num_to_cliff[single_gate_clifford_mapping[gate]] cliff = cliff1.compose(cliff2) products[i, single_gate_clifford_mapping[gate]] = cliff_to_num[cliff.__repr__()] @@ -28,14 +55,15 @@ def create_compose_map(): print("CLIFF_COMPOSE_DATA = [") for i in products: - print(f" {products[i]},") - print(" ]") + print(f" {products[i]},") + print("]") print() print("CLIFF_INVERSE_DATA = [") for i in invs: - print(f" {invs[i]},") - print(" ]") + print(f" {invs[i]},") + print("]") print() + create_compose_map() diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index 12264c4ac3..839b6835e1 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -22,7 +22,6 @@ from qiskit.quantum_info import Clifford from qiskit.exceptions import QiskitError from qiskit.providers.backend import Backend -from qiskit.compiler import transpile from .clifford_utils import CliffordUtils from .rb_experiment import StandardRB @@ -59,7 +58,7 @@ def __init__( num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: bool = False, - transpiled_rb = False + transpiled_rb=False, ): """Initialize an interleaved randomized benchmarking experiment. @@ -87,9 +86,10 @@ def __init__( num_samples=num_samples, seed=seed, full_sampling=full_sampling, - transpiled_rb=transpiled_rb + transpiled_rb=transpiled_rb, ) self._set_interleaved_element(interleaved_element) + self._transpiled_interleaved_elem = None self.analysis = InterleavedRBAnalysis() self.analysis.set_options(outcome="0" * self.num_qubits) @@ -101,14 +101,20 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] - if self._transpiled_rb and self._transpiled_cliff_circuits == None: - self._transpiled_cliff_circuits = \ - CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) + if self._transpiled_rb and self._transpiled_cliff_circuits is None: + self._transpiled_cliff_circuits = ( + CliffordUtils.generate_1q_transpiled_clifford_circuits( + basis_gates=self.transpile_options.basis_gates + ) + ) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: self._set_transpiled_interleaved_element() - std_circuits, int_circuits = self._build_rb_circuits(self.experiment_options.lengths, rng, - interleaved_element=self._transpiled_interleaved_elem) + std_circuits, int_circuits = self._build_rb_circuits( + self.experiment_options.lengths, + rng, + interleaved_element=self._transpiled_interleaved_elem, + ) circuits += std_circuits circuits += int_circuits else: @@ -186,6 +192,5 @@ def _set_transpiled_interleaved_element(self): else: basis_gates = None self._transpiled_interleaved_elem = CliffordUtils.transpile_single_clifford( - qc_interleaved, - basis_gates = basis_gates + qc_interleaved, basis_gates=basis_gates ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 9563d39bdc..f07ee9b5f6 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -19,11 +19,9 @@ import numpy as np from numpy.random import Generator, default_rng from numpy.random.bit_generator import BitGenerator, SeedSequence -import time -from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, QiskitError +from qiskit import QuantumCircuit, ClassicalRegister, QiskitError from qiskit.circuit import Instruction, Clbit -from qiskit.circuit.quantumregister import Qubit from qiskit.quantum_info import Clifford from qiskit.providers.backend import Backend @@ -31,10 +29,11 @@ from qiskit_experiments.framework.restless_mixin import RestlessMixin from .rb_analysis import RBAnalysis from .clifford_utils import CliffordUtils -from .clifford_data import CLIFF_COMPOSE_DATA, CLIFF_INVERSE_DATA +from .clifford_data import CLIFF_INVERSE_DATA LOG = logging.getLogger(__name__) + class StandardRB(BaseExperiment, RestlessMixin): """Standard randomized benchmarking experiment. @@ -68,7 +67,7 @@ def __init__( num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, - transpiled_rb: Optional[bool] = False + transpiled_rb: Optional[bool] = False, ): """Initialize a standard randomized benchmarking experiment. @@ -135,12 +134,21 @@ def circuits(self) -> List[QuantumCircuit]: Returns: A list of :class:`QuantumCircuit`. + + Raises: + QiskitError: if basis_gates is not set in transpile_options. """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] - if self._transpiled_rb and self._transpiled_cliff_circuits == None: - self._transpiled_cliff_circuits = \ - CliffordUtils.generate_1q_transpiled_clifford_circuits(basis_gates=self.transpile_options.basis_gates) + if self._transpiled_rb: + if not hasattr(self.transpile_options, "basis_gates"): + raise QiskitError("transpile_options.basis_gates must be set for rb_experiment") + if self._transpiled_cliff_circuits is None: + self._transpiled_cliff_circuits = ( + CliffordUtils.generate_1q_transpiled_clifford_circuits( + basis_gates=self.transpile_options.basis_gates + ) + ) for _ in range(self.experiment_options.num_samples): if self.num_qubits == 1 and self._transpiled_rb: rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng) @@ -221,21 +229,29 @@ def _generate_circuit( circuits.append(rb_circ) return circuits - def _build_rb_circuits(self, lengths, rng, interleaved_element=None): + def _build_rb_circuits( + self, lengths: List[int], rng: Generator, interleaved_element: QuantumCircuit = None + ) -> List[QuantumCircuit]: """ - build_rb_circuits - Args: - lengths: A list of RB sequence lengths. We create random circuits - where the number of cliffords in each is defined in lengths. - rng: Generator object for random number generation. - If None, default_rng will be used. + build_rb_circuits + Args: + lengths: A list of RB sequence lengths. We create random circuits + where the number of cliffords in each is defined in lengths. + rng: Generator object for random number generation. + If None, default_rng will be used. + interleaved_element: the interleaved element as a QuantumCircuit, if it exists. + + Returns: + The transpiled RB circuits. + + Additional information: To create the RB circuit, we use a mapping between Cliffords and integers - defined in the file clifford_data.py. The operations compose and inverse are much faster + defined in the file clifford_data.py. The operations compose and inverse are much faster when performed on the integers rather than on the Cliffords themselves. - """ + """ if self._full_sampling: return self._build_rb_circuits_full_sampling(lengths, rng, interleaved_element) - is_interleaved = interleaved_element != None + is_interleaved = interleaved_element is not None max_qubit = max(self.physical_qubits) + 1 all_rb_circuits = [] @@ -245,7 +261,8 @@ def _build_rb_circuits(self, lengths, rng, interleaved_element=None): all_rb_interleaved_circuits = None # When full_sampling==False, each circuit is the prefix of the next circuit (without the - # inverse Clifford at the end of the circuit. The variable 'circ' will contain the growing circuit. + # inverse Clifford at the end of the circuit. The variable 'circ' will contain + # the growing circuit. # When each circuit reaches its length, we copy it to rb_circ, append the inverse, # and add it to the list of circuits. @@ -259,7 +276,9 @@ def _build_rb_circuits(self, lengths, rng, interleaved_element=None): circ = QuantumCircuit(max_qubit, 1) circ.barrier(0) - composed_cliff_num = 0 # 0 is the Clifford that is Id + # composed_cliff_num is the number representing the composition of all the Cliffords up to now + # composed_interleaved_num is the same for an interleaved circuit + composed_cliff_num = 0 # 0 is the Clifford that is Id composed_interleaved_num = 0 prev_length = 0 @@ -269,25 +288,33 @@ def _build_rb_circuits(self, lengths, rng, interleaved_element=None): # choose random clifford next_circ = self._transpiled_cliff_circuits[rand] circ.compose(next_circ, inplace=True) - composed_cliff_num = CliffordUtils.compose_num_with_clifford(composed_cliff_num, next_circ, - self.transpile_options.basis_gates) + composed_cliff_num = CliffordUtils.compose_num_with_clifford( + composed_cliff_num, next_circ, self.transpile_options.basis_gates + ) + circ.barrier(0) if is_interleaved: interleaved_circ.compose(next_circ, inplace=True) - composed_interleaved_num = CliffordUtils.compose_num_with_clifford(composed_interleaved_num, next_circ, - self.transpile_options.basis_gates) + composed_interleaved_num = CliffordUtils.compose_num_with_clifford( + composed_interleaved_num, next_circ, self.transpile_options.basis_gates + ) interleaved_circ.barrier(0) + # The interleaved element is appended after every Clifford and its barrier interleaved_circ.compose(interleaved_element, inplace=True) - composed_interleaved_num = CliffordUtils.compose_num_with_clifford(composed_interleaved_num, - interleaved_element, - self.transpile_options.basis_gates) + composed_interleaved_num = CliffordUtils.compose_num_with_clifford( + composed_interleaved_num, + interleaved_element, + self.transpile_options.basis_gates, + ) interleaved_circ.barrier(0) - if i == length-1: - rb_circ = circ.copy() # circ is used as the prefix of the next circuit + if i == length - 1: + rb_circ = circ.copy() # circ is used as the prefix of the next circuit inverse_clifford_num = CLIFF_INVERSE_DATA[composed_cliff_num] # append the inverse - rb_circ.compose(self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True) + rb_circ.compose( + self._transpiled_cliff_circuits[inverse_clifford_num], inplace=True + ) rb_circ.measure(0, 0) rb_circ.metadata = { @@ -295,14 +322,17 @@ def _build_rb_circuits(self, lengths, rng, interleaved_element=None): "xval": length, "group": "Clifford", "physical_qubits": self.physical_qubits, - "interleaved" : False + "interleaved": False, } all_rb_circuits.append(rb_circ) if is_interleaved: - rb_interleaved_circ = interleaved_circ.copy() # interleaved_circ is used as the prefix of the next circuit + # interleaved_circ is used as the prefix of the next circuit + rb_interleaved_circ = interleaved_circ.copy() # append the inverse inverse_interleaved_num = CLIFF_INVERSE_DATA[composed_interleaved_num] - rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True) + rb_interleaved_circ.compose( + self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True + ) rb_interleaved_circ.measure(0, 0) rb_interleaved_circ.metadata = { @@ -317,8 +347,25 @@ def _build_rb_circuits(self, lengths, rng, interleaved_element=None): prev_length = i + 1 return all_rb_circuits, all_rb_interleaved_circuits - def _build_rb_circuits_full_sampling(self, lengths, rng, interleaved_element=None): - is_interleaved = interleaved_element != None + def _build_rb_circuits_full_sampling( + self, lengths: List[int], rng: Generator, interleaved_element: QuantumCircuit = None + ) -> List[QuantumCircuit]: + """ + _build_rb_circuits_full_sampling + Args: + lengths: A list of RB sequence lengths. We create random circuits + where the number of cliffords in each is defined in lengths. + rng: Generator object for random number generation. + If None, default_rng will be used. + interleaved_element: the interleaved element as a QuantumCircuit, if it exists. + + Returns: + The transpiled RB circuits. + + Additional information: + This is similar to _build_rb_circuits for the case of full_sampling. + """ + is_interleaved = interleaved_element is not None all_rb_circuits = [] if is_interleaved: all_rb_interleaved_circuits = [] @@ -338,29 +385,38 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, interleaved_element=Non rb_interleaved_circ = None random_samples = rng.integers(24, size=length) - # For full_sampling, we create each circuit independently. + # composed_cliff_num is the number representing the composition of + # all the Cliffords up to now + # composed_interleaved_num is the same for an interleaved circuit composed_cliff_num = 0 composed_interleaved_num = 0 + # For full_sampling, we create each circuit independently. for i in range(length): # choose random clifford rand = random_samples[i] next_circ = self._transpiled_cliff_circuits[rand].copy() rb_circ.compose(next_circ, inplace=True) - composed_cliff_num = \ - CliffordUtils.compose_num_with_clifford(composed_num=composed_cliff_num, qc=next_circ, - basis_gates=self.transpile_options.basis_gates) + composed_cliff_num = CliffordUtils.compose_num_with_clifford( + composed_num=composed_cliff_num, + qc=next_circ, + basis_gates=self.transpile_options.basis_gates, + ) rb_circ.barrier(0) if is_interleaved: rb_interleaved_circ.compose(next_circ, inplace=True) - composed_interleaved_num = \ - CliffordUtils.compose_num_with_clifford(composed_num=composed_interleaved_num, qc=next_circ, - basis_gates=self.transpile_options.basis_gates) + composed_interleaved_num = CliffordUtils.compose_num_with_clifford( + composed_num=composed_interleaved_num, + qc=next_circ, + basis_gates=self.transpile_options.basis_gates, + ) rb_interleaved_circ.barrier(0) rb_interleaved_circ.compose(interleaved_element, inplace=True) - composed_interleaved_num = \ - CliffordUtils.compose_num_with_clifford(composed_interleaved_num, interleaved_element, - self.transpile_options.basis_gates) + composed_interleaved_num = CliffordUtils.compose_num_with_clifford( + composed_interleaved_num, + interleaved_element, + self.transpile_options.basis_gates, + ) rb_interleaved_circ.barrier(0) inverse_clifford_num = CLIFF_INVERSE_DATA[composed_cliff_num] @@ -376,14 +432,16 @@ def _build_rb_circuits_full_sampling(self, lengths, rng, interleaved_element=Non } if is_interleaved: inverse_interleaved_num = CLIFF_INVERSE_DATA[composed_interleaved_num] - rb_interleaved_circ.compose(self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True) + rb_interleaved_circ.compose( + self._transpiled_cliff_circuits[inverse_interleaved_num], inplace=True + ) rb_interleaved_circ.measure(0, 0) rb_interleaved_circ.metadata = { "experiment_type": "rb", "xval": length, "group": "Clifford", "physical_qubits": self.physical_qubits, - "interleaved" : True, + "interleaved": True, } all_rb_circuits.append(rb_circ) if is_interleaved: @@ -400,13 +458,11 @@ def _layout_for_rb_single_qubit(self): transpiled = [] qargs_map = {0: self.physical_qubits[0]} for circ in self.circuits(): - qr = QuantumRegister(circ.num_qubits, name='q') - qubit = Qubit(qr, self.physical_qubits[0]) new_circ = QuantumCircuit( *circ.qregs, name=circ.name, global_phase=circ.global_phase, - metadata=circ.metadata.copy() + metadata=circ.metadata.copy(), ) clbits = circ.num_clbits if clbits: @@ -418,9 +474,7 @@ def _layout_for_rb_single_qubit(self): for inst, qargs, cargs in circ.data: mapped_cargs = [new_cargs[circ.find_bit(clbit).index] for clbit in cargs] - mapped_qargs = [ - circ.qubits[qargs_map[circ.find_bit(i).index]] for i in qargs - ] + mapped_qargs = [circ.qubits[qargs_map[circ.find_bit(i).index]] for i in qargs] new_circ.data.append((inst, mapped_qargs, mapped_cargs)) # Add the calibrations for gate, cals in circ.calibrations.items(): @@ -432,7 +486,7 @@ def _layout_for_rb_single_qubit(self): def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" - if self.num_qubits==1 and self._transpiled_rb: + if self.num_qubits == 1 and self._transpiled_rb: transpiled = self._layout_for_rb_single_qubit() else: transpiled = super()._transpiled_circuits() @@ -469,4 +523,3 @@ def _metadata(self): metadata[run_opt] = getattr(self.run_options, run_opt) return metadata - diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 27ec612080..d05f4ef79b 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -14,11 +14,10 @@ from test.base import QiskitExperimentsTestCase -import numpy as np import random from ddt import ddt, data, unpack from qiskit.circuit import Delay, QuantumCircuit -from qiskit.circuit.library import SXGate, CXGate, TGate, XGate, YGate, ZGate, HGate, SGate +from qiskit.circuit.library import SXGate, CXGate, TGate from qiskit.exceptions import QiskitError from qiskit.providers.aer import AerSimulator from qiskit.providers.aer.noise import NoiseModel, depolarizing_error @@ -72,7 +71,8 @@ def assertAllIdentity(self, circuits): num_qubits = circ.num_qubits qc_iden = QuantumCircuit(num_qubits) circ.remove_final_measurements() - assert (Operator(circ).equiv(Operator(qc_iden))) + assert Operator(circ).equiv(Operator(qc_iden)) + @ddt class TestStandardRB(RBTestCase): @@ -85,7 +85,7 @@ def test_single_qubit(self): lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, - transpiled_rb=True + transpiled_rb=True, ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) @@ -194,7 +194,7 @@ def test_full_sampling_single_qubit(self): seed=123, backend=self.backend, full_sampling=False, - transpiled_rb=True + transpiled_rb=True, ) exp1.set_transpile_options(**self.transpiler_options) exp2 = rb.StandardRB( @@ -203,7 +203,7 @@ def test_full_sampling_single_qubit(self): seed=123, backend=self.backend, full_sampling=True, - transpiled_rb=True + transpiled_rb=True, ) exp2.set_transpile_options(**self.transpiler_options) circs1 = exp1.circuits() @@ -279,7 +279,7 @@ def test_expdata_serialization(self): lengths=list(range(1, 200, 50)), seed=123, backend=self.backend, - transpiled_rb=True + transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) expdata = exp.run() @@ -294,11 +294,7 @@ def test_single_qubit_parallel(self): exps = [] for qubit in qubits: exp = rb.StandardRB( - qubits=[qubit], - lengths=lengths, - seed=123, - backend=self.backend, - transpiled_rb=True + qubits=[qubit], lengths=lengths, seed=123, backend=self.backend, transpiled_rb=True ) exp.analysis.set_options(gate_error_ratio=None, plot_raw_data=False) exps.append(exp) @@ -313,6 +309,7 @@ def test_single_qubit_parallel(self): epc = par_expdata.child_data(i).analysis_results("EPC") self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + @ddt class TestInterleavedRB(RBTestCase): """Test for interleaved RB.""" @@ -324,11 +321,15 @@ def test_interleaved_structure(self, interleaved_element, qubits, length): identical to the original circuit up to additions of barrier and interleaved element between any two Cliffords. """ - full_sampling =[True, False] + full_sampling = [True, False] for val in full_sampling: exp = rb.InterleavedRB( - interleaved_element=interleaved_element, qubits=qubits, lengths=[length], - num_samples=1, full_sampling=val, transpiled_rb=True + interleaved_element=interleaved_element, + qubits=qubits, + lengths=[length], + num_samples=1, + full_sampling=val, + transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) circuits = exp.circuits() @@ -387,7 +388,7 @@ def test_single_qubit(self): expdata = exp.run() self.assertExperimentDone(expdata) - # Since this is interleaved, we can directly compare values, i.e. n_gpc = 1 + # Since this is interleaved, we can directly compare values, i.e. n_gpc = 1 epc = expdata.analysis_results("EPC") epc_expected = 1 / 2 * self.p1q self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) @@ -423,7 +424,7 @@ def test_non_clifford_interleaved_element(self): interleaved_element=interleaved_element, qubits=qubits, lengths=lengths, - transpiled_rb=True + transpiled_rb=True, ) def test_interleaving_delay(self): @@ -435,8 +436,8 @@ def test_interleaving_delay(self): qubits=[0], lengths=[1], num_samples=1, - seed=1234, # This seed gives a 2-gate clifford - transpiled_rb=True + seed=1234, # This seed gives a 2-gate clifford + transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) @@ -475,7 +476,11 @@ def test_interleaving_circuit_with_delay(self): def test_experiment_config(self): """Test converting to and from config works""" exp = rb.InterleavedRB( - interleaved_element=SXGate(), qubits=(0,), lengths=[10, 20, 30], seed=123, transpiled_rb=True + interleaved_element=SXGate(), + qubits=(0,), + lengths=[10, 20, 30], + seed=123, + transpiled_rb=True, ) loaded_exp = rb.InterleavedRB.from_config(exp.config()) self.assertNotEqual(exp, loaded_exp) @@ -503,7 +508,7 @@ def test_expdata_serialization(self): lengths=list(range(1, 200, 50)), seed=123, backend=self.backend, - transpiled_rb=True + transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) expdata = exp.run() @@ -555,7 +560,7 @@ def setUp(self): lengths=[1, 10, 30, 50, 80, 120, 150, 200], seed=123, backend=backend, - transpiled_rb=True + transpiled_rb=True, ) exp_1qrb_q0.set_transpile_options(**transpiler_options) expdata_1qrb_q0 = exp_1qrb_q0.run(analysis=None).block_for_results(timeout=300) @@ -564,7 +569,7 @@ def setUp(self): lengths=[1, 10, 30, 50, 80, 120, 150, 200], seed=123, backend=backend, - transpiled_rb=True + transpiled_rb=True, ) exp_1qrb_q1.set_transpile_options(**transpiler_options) expdata_1qrb_q1 = exp_1qrb_q1.run(analysis=None).block_for_results(timeout=300) diff --git a/test/randomized_benchmarking/test_rb_utils.py b/test/randomized_benchmarking/test_rb_utils.py index 89ee167966..f48abb48a7 100644 --- a/test/randomized_benchmarking/test_rb_utils.py +++ b/test/randomized_benchmarking/test_rb_utils.py @@ -1018,11 +1018,16 @@ def test_clifford_2_qubit_generation(self): phases.append(phase) def test_number_to_clifford_mapping_single_gate(self): - """ Testing that the methods num_from_1_qubit_clifford_single_gate and - clifford_1_qubit_circuit perform the reverse operations from - each other""" - transpiled_cliff_list = [SXGate(), RZGate(np.pi), RZGate(-np.pi), - RZGate(np.pi/2), RZGate(-np.pi/2)] + """Testing that the methods num_from_1_qubit_clifford_single_gate and + clifford_1_qubit_circuit perform the reverse operations from + each other""" + transpiled_cliff_list = [ + SXGate(), + RZGate(np.pi), + RZGate(-np.pi), + RZGate(np.pi / 2), + RZGate(-np.pi / 2), + ] transpiled_cliff_names = [gate.name for gate in transpiled_cliff_list] for inst in transpiled_cliff_list: num = CliffordUtils.num_from_1_qubit_clifford_single_gate(inst, transpiled_cliff_names) @@ -1030,9 +1035,18 @@ def test_number_to_clifford_mapping_single_gate(self): qr = QuantumRegister(1) qc_from_inst = QuantumCircuit(qr) qc_from_inst._append(inst, [qr[0]], []) - assert (Operator(qc_from_num).equiv(Operator(qc_from_inst))) + assert Operator(qc_from_num).equiv(Operator(qc_from_inst)) - general_cliff_list = [IGate(), HGate(), SdgGate(), SGate(), XGate(), SXGate(), YGate(), ZGate()] + general_cliff_list = [ + IGate(), + HGate(), + SdgGate(), + SGate(), + XGate(), + SXGate(), + YGate(), + ZGate(), + ] general_cliff_names = [gate.name for gate in general_cliff_list] for inst in general_cliff_list: num = CliffordUtils.num_from_1_qubit_clifford_single_gate(inst, general_cliff_names) @@ -1040,13 +1054,24 @@ def test_number_to_clifford_mapping_single_gate(self): qr = QuantumRegister(1) qc_from_inst = QuantumCircuit(qr) qc_from_inst._append(inst, [qr[0]], []) - assert (Operator(qc_from_num).equiv(Operator(qc_from_inst))) + assert Operator(qc_from_num).equiv(Operator(qc_from_inst)) def test_number_to_clifford_mapping(self): - transpiled_cliff_list = [SXGate(), RZGate(np.pi), RZGate(-np.pi), - RZGate(np.pi / 2), RZGate(-np.pi / 2)] + """ Test that the number generated by compose_num_with_clifford on qc + corresponds to the index of the circuit qc. + + """ + transpiled_cliff_list = [ + SXGate(), + RZGate(np.pi), + RZGate(-np.pi), + RZGate(np.pi / 2), + RZGate(-np.pi / 2), + ] transpiled_cliff_names = [gate.name for gate in transpiled_cliff_list] - all_transpiled_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits(transpiled_cliff_names) + all_transpiled_circuits = CliffordUtils.generate_1q_transpiled_clifford_circuits( + transpiled_cliff_names + ) for index, qc in enumerate(all_transpiled_circuits): num = CliffordUtils.compose_num_with_clifford(0, qc, transpiled_cliff_names) - assert(num == index) + assert num == index From eab49ecc38cf2316bab13d9bfcbc5c29a37a1c51 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Sun, 3 Jul 2022 15:37:39 +0300 Subject: [PATCH 37/39] black --- test/randomized_benchmarking/test_rb_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/randomized_benchmarking/test_rb_utils.py b/test/randomized_benchmarking/test_rb_utils.py index f48abb48a7..e60daaa529 100644 --- a/test/randomized_benchmarking/test_rb_utils.py +++ b/test/randomized_benchmarking/test_rb_utils.py @@ -1057,7 +1057,7 @@ def test_number_to_clifford_mapping_single_gate(self): assert Operator(qc_from_num).equiv(Operator(qc_from_inst)) def test_number_to_clifford_mapping(self): - """ Test that the number generated by compose_num_with_clifford on qc + """Test that the number generated by compose_num_with_clifford on qc corresponds to the index of the circuit qc. """ From 16fe2e107c24cbd5c930f807ba9c9a9b22613a5a Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 5 Jul 2022 15:51:36 +0300 Subject: [PATCH 38/39] Removed the parameter transpiled_rb used for choosing whether to use old algorithm or new one. --- .../interleaved_rb_experiment.py | 6 ++---- .../randomized_benchmarking/rb_experiment.py | 8 +++----- .../test_randomized_benchmarking.py | 18 +++--------------- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index 839b6835e1..e8a10d59ca 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -58,7 +58,6 @@ def __init__( num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: bool = False, - transpiled_rb=False, ): """Initialize an interleaved randomized benchmarking experiment. @@ -86,7 +85,6 @@ def __init__( num_samples=num_samples, seed=seed, full_sampling=full_sampling, - transpiled_rb=transpiled_rb, ) self._set_interleaved_element(interleaved_element) self._transpiled_interleaved_elem = None @@ -101,14 +99,14 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] - if self._transpiled_rb and self._transpiled_cliff_circuits is None: + if self.num_qubits == 1 and self._transpiled_cliff_circuits is None: self._transpiled_cliff_circuits = ( CliffordUtils.generate_1q_transpiled_clifford_circuits( basis_gates=self.transpile_options.basis_gates ) ) for _ in range(self.experiment_options.num_samples): - if self.num_qubits == 1 and self._transpiled_rb: + if self.num_qubits == 1: self._set_transpiled_interleaved_element() std_circuits, int_circuits = self._build_rb_circuits( self.experiment_options.lengths, diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index f07ee9b5f6..c86e056ed9 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -67,7 +67,6 @@ def __init__( num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: Optional[bool] = False, - transpiled_rb: Optional[bool] = False, ): """Initialize a standard randomized benchmarking experiment. @@ -93,7 +92,6 @@ def __init__( # Set fixed options self._full_sampling = full_sampling - self._transpiled_rb = transpiled_rb self._transpiled_cliff_circuits = None def _verify_parameters(self, lengths, num_samples): @@ -140,7 +138,7 @@ def circuits(self) -> List[QuantumCircuit]: """ rng = default_rng(seed=self.experiment_options.seed) circuits = [] - if self._transpiled_rb: + if self.num_qubits == 1: if not hasattr(self.transpile_options, "basis_gates"): raise QiskitError("transpile_options.basis_gates must be set for rb_experiment") if self._transpiled_cliff_circuits is None: @@ -150,7 +148,7 @@ def circuits(self) -> List[QuantumCircuit]: ) ) for _ in range(self.experiment_options.num_samples): - if self.num_qubits == 1 and self._transpiled_rb: + if self.num_qubits == 1: rb_circuits, _ = self._build_rb_circuits(self.experiment_options.lengths, rng) circuits += rb_circuits else: @@ -486,7 +484,7 @@ def _layout_for_rb_single_qubit(self): def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" - if self.num_qubits == 1 and self._transpiled_rb: + if self.num_qubits == 1: transpiled = self._layout_for_rb_single_qubit() else: transpiled = super()._transpiled_circuits() diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index d05f4ef79b..1b6ff8d297 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -85,7 +85,6 @@ def test_single_qubit(self): lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, - transpiled_rb=True, ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) @@ -194,7 +193,6 @@ def test_full_sampling_single_qubit(self): seed=123, backend=self.backend, full_sampling=False, - transpiled_rb=True, ) exp1.set_transpile_options(**self.transpiler_options) exp2 = rb.StandardRB( @@ -203,7 +201,6 @@ def test_full_sampling_single_qubit(self): seed=123, backend=self.backend, full_sampling=True, - transpiled_rb=True, ) exp2.set_transpile_options(**self.transpiler_options) circs1 = exp1.circuits() @@ -255,14 +252,14 @@ def test_invalid_configuration(self, configs): def test_experiment_config(self): """Test converting to and from config works""" - exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123, transpiled_rb=True) + exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123) loaded_exp = rb.StandardRB.from_config(exp.config()) self.assertNotEqual(exp, loaded_exp) self.assertTrue(self.json_equiv(exp, loaded_exp)) def test_roundtrip_serializable(self): """Test round trip JSON serialization""" - exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123, transpiled_rb=True) + exp = rb.StandardRB(qubits=(0,), lengths=[10, 20, 30], seed=123) self.assertRoundTripSerializable(exp, self.json_equiv) def test_analysis_config(self): @@ -279,7 +276,6 @@ def test_expdata_serialization(self): lengths=list(range(1, 200, 50)), seed=123, backend=self.backend, - transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) expdata = exp.run() @@ -294,7 +290,7 @@ def test_single_qubit_parallel(self): exps = [] for qubit in qubits: exp = rb.StandardRB( - qubits=[qubit], lengths=lengths, seed=123, backend=self.backend, transpiled_rb=True + qubits=[qubit], lengths=lengths, seed=123, backend=self.backend ) exp.analysis.set_options(gate_error_ratio=None, plot_raw_data=False) exps.append(exp) @@ -329,7 +325,6 @@ def test_interleaved_structure(self, interleaved_element, qubits, length): lengths=[length], num_samples=1, full_sampling=val, - transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) circuits = exp.circuits() @@ -379,7 +374,6 @@ def test_single_qubit(self): lengths=list(range(1, 300, 30)), seed=123, backend=self.backend, - transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) @@ -424,7 +418,6 @@ def test_non_clifford_interleaved_element(self): interleaved_element=interleaved_element, qubits=qubits, lengths=lengths, - transpiled_rb=True, ) def test_interleaving_delay(self): @@ -437,7 +430,6 @@ def test_interleaving_delay(self): lengths=[1], num_samples=1, seed=1234, # This seed gives a 2-gate clifford - transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) @@ -480,7 +472,6 @@ def test_experiment_config(self): qubits=(0,), lengths=[10, 20, 30], seed=123, - transpiled_rb=True, ) loaded_exp = rb.InterleavedRB.from_config(exp.config()) self.assertNotEqual(exp, loaded_exp) @@ -508,7 +499,6 @@ def test_expdata_serialization(self): lengths=list(range(1, 200, 50)), seed=123, backend=self.backend, - transpiled_rb=True, ) exp.set_transpile_options(**self.transpiler_options) expdata = exp.run() @@ -560,7 +550,6 @@ def setUp(self): lengths=[1, 10, 30, 50, 80, 120, 150, 200], seed=123, backend=backend, - transpiled_rb=True, ) exp_1qrb_q0.set_transpile_options(**transpiler_options) expdata_1qrb_q0 = exp_1qrb_q0.run(analysis=None).block_for_results(timeout=300) @@ -569,7 +558,6 @@ def setUp(self): lengths=[1, 10, 30, 50, 80, 120, 150, 200], seed=123, backend=backend, - transpiled_rb=True, ) exp_1qrb_q1.set_transpile_options(**transpiler_options) expdata_1qrb_q1 = exp_1qrb_q1.run(analysis=None).block_for_results(timeout=300) From e2fe641544eeb91e45b49125cc7b7bd1d7a55b46 Mon Sep 17 00:00:00 2001 From: Merav Aharoni Date: Tue, 5 Jul 2022 16:50:58 +0300 Subject: [PATCH 39/39] Cleaning up --- .../randomized_benchmarking/clifford_data.py | 11 ++++++----- .../randomized_benchmarking/clifford_utils.py | 14 +++++++------- .../randomized_benchmarking/create_clifford_map.py | 8 +++----- .../interleaved_rb_experiment.py | 1 - .../test_randomized_benchmarking.py | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py index fdb298ef64..295b1234c5 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_data.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_data.py @@ -14,10 +14,10 @@ This file contains the Clifford group represented as integers. In CLIFF_COMPOSE_DATA, (i, j): k represents Clifford(i).compose(clifford(j)) = Clifford(k). Since retrieving a value from an array is more efficient than from a dict, therefore -we store only the results in an array. The index is computed in c -CliffordUtils.compose_num_with_clifford(). -Note that for the pairs (i, j), i can be any clifford, j represents only the -1-gate cliffords, as listed in CliffordUtils.general_cliff_list +we store only the results (k) in the array CLIFF_COMPOSE_DATA. +The index is computed in CliffordUtils.compose_num_with_clifford(). +Note that for the pairs (i, j), i can be any clifford, and j represents only the +1-gate Cliffords, as listed in CliffordUtils.general_cliff_list """ CLIFF_COMPOSE_DATA = [ @@ -239,7 +239,8 @@ 19, ] -# In CLIFF_INVERSE_DATA, i: j represents Clifford(i).inverse = Clifford(j) +# In CLIFF_INVERSE_DATA, i: j represents Clifford(i).inverse = Clifford(j). +# Here too, we store only the inverse (j) in the array CLIFF_INVERSE_DATA. CLIFF_INVERSE_DATA = [ 0, 1, diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index ab6b48e1b1..7757f8c517 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -20,7 +20,7 @@ from numpy.random import Generator, default_rng from qiskit import QuantumCircuit, QuantumRegister -from qiskit.circuit import Gate +from qiskit.circuit import Gate, Instruction from qiskit.circuit.library import SdgGate, HGate, SGate, SXdgGate from qiskit.quantum_info import Clifford, random_clifford from qiskit.compiler import transpile @@ -28,7 +28,6 @@ from qiskit.exceptions import QiskitError from .clifford_data import CLIFF_COMPOSE_DATA - class VGate(Gate): """V Gate used in Clifford synthesis.""" @@ -104,7 +103,7 @@ def random_cliffords( rng = default_rng(rng) if num_qubits == 1: - samples = rng.integers(24, size=size) + samples = rng.integers(cls.NUM_CLIFFORD_1_QUBIT, size=size) return [Clifford(cls.clifford_1_qubit_circuit(i), validate=False) for i in samples] else: samples = rng.integers(11520, size=size) @@ -125,7 +124,7 @@ def random_clifford_circuits( rng = default_rng(rng) if num_qubits == 1: - samples = rng.integers(24, size=size) + samples = rng.integers(cls.NUM_CLIFFORD_1_QUBIT, size=size) return [cls.clifford_1_qubit_circuit(i) for i in samples] else: samples = rng.integers(11520, size=size) @@ -248,14 +247,15 @@ def transpile_single_clifford(cls, cliff_circ: QuantumCircuit, basis_gates: List def generate_1q_transpiled_clifford_circuits(cls, basis_gates: List[str]): """Generate all transpiled clifford circuits""" transpiled_circs = [] - for num in range(0, 24): + for num in range(0, cls.NUM_CLIFFORD_1_QUBIT): circ = cls.clifford_1_qubit_circuit(num=num) transpiled_circ = cls.transpile_single_clifford(circ, basis_gates) transpiled_circs.append(transpiled_circ) return transpiled_circs @classmethod - def num_from_1_qubit_clifford_single_gate(cls, inst, basis_gates): + def num_from_1_qubit_clifford_single_gate(cls, inst: Instruction, + basis_gates: List[str]) -> int: """ This method does the reverse of clifford_1_qubit_circuit - given a clifford, it returns the corresponding integer, with the mapping @@ -312,7 +312,7 @@ def compose_num_with_clifford( number that represents the resulting Clifford.""" # The numbers corresponding to single gate Cliffords are not in sequence - - # see num_from_1_qubit_clifford_single_gate. In order to compute the index in + # see num_from_1_qubit_clifford_single_gate. To compute the index in # the array CLIFF_COMPOSE_DATA, we map the numbers to [0, 8]. map_clifford_num_to_array_index = {0: 0, 1: 1, 2: 2, 4: 3, 6: 4, 8: 5, 12: 6, 18: 7, 22: 8} for inst in qc: diff --git a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py index c5f02b1276..61ee3d546b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py +++ b/qiskit_experiments/library/randomized_benchmarking/create_clifford_map.py @@ -14,13 +14,12 @@ """ from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils - def create_compose_map(): """Creates the data in CLIFF_COMPOSE_DATA and CLIFF_INVERSE_DATA""" num_to_cliff = {} cliff_to_num = {} - for i in range(24): + for i in range(CliffordUtils.NUM_CLIFFORD_1_QUBIT): cliff = CliffordUtils.clifford_1_qubit(i) num_to_cliff[i] = cliff cliff_to_num[cliff.__repr__()] = i @@ -39,7 +38,7 @@ def create_compose_map(): "sdg": 22, } - for i in range(24): + for i in range(CliffordUtils.NUM_CLIFFORD_1_QUBIT): cliff1 = num_to_cliff[i] # for gate in single_gate_clifford_mapping.keys(): for gate in single_gate_clifford_mapping: @@ -48,7 +47,7 @@ def create_compose_map(): products[i, single_gate_clifford_mapping[gate]] = cliff_to_num[cliff.__repr__()] invs = {} - for i in range(24): + for i in range(CliffordUtils.NUM_CLIFFORD_1_QUBIT): cliff1 = num_to_cliff[i] cliff = cliff1.adjoint() invs[i] = cliff_to_num[cliff.__repr__()] @@ -65,5 +64,4 @@ def create_compose_map(): print("]") print() - create_compose_map() diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index e8a10d59ca..c2f4dc627a 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -147,7 +147,6 @@ def _interleave(self, element_list: List) -> List: Returns: The new list with the element interleaved. """ - new_element_list = [] for element in element_list: new_element_list.append(element) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 1b6ff8d297..402128fd85 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -91,7 +91,6 @@ def test_single_qubit(self): self.assertAllIdentity(exp.circuits()) expdata = exp.run() - self.assertExperimentDone(expdata) # Given we have gate number per Clifford n_gpc, we can compute EPC as @@ -553,6 +552,7 @@ def setUp(self): ) exp_1qrb_q0.set_transpile_options(**transpiler_options) expdata_1qrb_q0 = exp_1qrb_q0.run(analysis=None).block_for_results(timeout=300) + exp_1qrb_q1 = rb.StandardRB( qubits=(1,), lengths=[1, 10, 30, 50, 80, 120, 150, 200],