From 921c18501c6a3aa189c37f0d714171885ab14714 Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Mon, 11 Jul 2022 14:26:29 -0400 Subject: [PATCH 01/56] add mirror RB experiment and analysis files --- .../mirror_rb_analysis.py | 679 ++++++++++++++++++ .../mirror_rb_experiment.py | 523 ++++++++++++++ 2 files changed, 1202 insertions(+) create mode 100644 qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py create mode 100644 qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py new file mode 100644 index 0000000000..cd4764acd7 --- /dev/null +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -0,0 +1,679 @@ +# 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. +""" +Mirror RB analysis class. +""" +from collections import defaultdict +from typing import Dict, List, Sequence, Tuple, Union, Optional, TYPE_CHECKING + +import lmfit +from qiskit.exceptions import QiskitError + +import numpy as np +from scipy.spatial.distance import hamming + +import qiskit_experiments.curve_analysis as curve +from qiskit_experiments.exceptions import AnalysisError +from qiskit_experiments.framework import AnalysisResultData, ExperimentData +from qiskit_experiments.database_service import DbAnalysisResultV1 +from qiskit_experiments.data_processing.exceptions import DataProcessorError +from uncertainties import unumpy as unp # pylint: disable=wrong-import-order + +if TYPE_CHECKING: + from uncertainties import UFloat + +# A dictionary key of qubit aware quantum instruction; type alias for better readability +QubitGateTuple = Tuple[Tuple[int, ...], str] + + +class MirrorRBAnalysis(curve.CurveAnalysis): + r"""A class to analyze mirror randomized benchmarking experiment. + + # section: overview + This analysis takes a series for Mirror RB curve fitting. + From the fit :math:`\alpha` value this analysis estimates the mean entanglement infidelity (EI) + and the error per Clifford (EPC), also known as the average gate infidelity (AGI). + + The EPC (AGI) estimate is obtained using the equation + + .. math:: + + EPC = \frac{2^n - 1}{2^n}\left(1 - \alpha\right) + + where :math:`n` is the number of qubits (width of the circuit). + + The EI is obtained using the equation + + .. math:: + + EI = \frac{4^n - 1}{4^n}\left(1 - \alpha\right) + + The fit :math:`\alpha` parameter can be fit using one of the following three quantities + plotted on the y-axis: + + Success Probabilities (:math:`p`): The proportion of shots that return the correct bitstring + + Adjusted Success Probabilities (:math:`p_0`): + + .. math:: + + p_0 = \sum_{k = 0}^n (-\frac{1}{2})^k h_k + + where :math:`h_k` is the probability of observing a bitstring of Hamming distance of k from the + correct bitstring + + Effective Polarizations (:math:`S`): + + .. math:: + + S = \frac{4^n}{4^n - 1}\sum_{k = 0}^n (-\frac{1}{2})^k h_k - \frac{1}{4^n - 1} + + # section: fit_model + The fit is based on the following decay functions: + + Fit model for mirror RB + + .. math:: + + F(x) = a \alpha^{x} + b + + # section: fit_parameters + defpar a: + desc: Height of decay curve. + init_guess: Determined by :math:`1 - b`. + bounds: [0, 1] + defpar b: + desc: Base line. + init_guess: Determined by :math:`(1/2)^n` (for success probability) or :math:`(1/4)^n` + (for adjusted success probability and effective polarization). + bounds: [0, 1] + defpar \alpha: + desc: Depolarizing parameter. + init_guess: Determined by :func:`~rb_decay` with standard RB curve. + bounds: [0, 1] + + # section: reference + .. ref_arxiv:: 1 2112.09853 + + """ + + def __init__(self): + super().__init__( + models=[ + lmfit.models.ExpressionModel( + expr="a * alpha ** x + b", name="mirror", data_sort_key={"mirror": True} + ) + ] + ) + self._gate_counts_per_clifford = None + self._physical_qubits = None + self._num_qubits = None + + # __series__ = [ + # curve.SeriesDef( + # name="Mirror", + # fit_func=lambda x, a, alpha, b: curve.fit_function.exponential_decay( + # x, amp=a, lamb=-1.0, base=alpha, baseline=b + # ), + # filter_kwargs={"mirror": True}, + # plot_color="blue", + # plot_symbol="^", + # model_description=r"a \alpha^{x} + b", + # ) + # ] + + @classmethod + def _default_options(cls): + """Default analysis options.""" + default_options = super()._default_options() + + # Set labels of axes + default_options.curve_drawer.set_options( + xlabel="Clifford Length", + ylabel="Effective Polarization", + ) + + # Plot all (adjusted) success probabilities + default_options.plot_raw_data = True + + # Exponential decay parameter + default_options.result_parameters = ["alpha"] + + # Default gate error ratio for calculating EPG + default_options.gate_error_ratio = "default" + + # By default, EPG for single qubits aren't set + default_options.epg_1_qubit = None + + # By default, effective polarization (see Tim Proctor paper) is plotted. We can + # also plot success probability or adjusted success probability (see PyGSTi). + # Do this by setting options to "Success Probability" or "Adjusted Success Probability" + default_options.y_axis = "Effective Polarization" + + return default_options + + def set_options(self, **fields): + if "y_axis" in fields: + if fields["y_axis"] not in [ + "Success Probability", + "Adjusted Success Probability", + "Effective Polarization", + ]: + raise QiskitError( + 'y_axis must be one of "Success Probability", "Adjusted Success Probability", ' + 'or "Effective Polarization"' + ) + super().set_options(**fields) + + def _generate_fit_guesses( + self, + user_opt: curve.FitOptions, + curve_data: curve.CurveData, + ) -> Union[curve.FitOptions, List[curve.FitOptions]]: + """Create algorithmic guess with analysis options and curve data. + + Args: + user_opt: Fit options filled with user provided guess and bounds. + curve_data: Formatted data collection to fit. + + Returns: + List of fit options that are passed to the fitter function. + """ + user_opt.bounds.set_if_empty(a=(0, 1), alpha=(0, 1), b=(0, 1)) + + # Initialize guess for baseline and amplitude based on infidelity type + b_guess = 1 / 4**self._num_qubits + if self.options.y_axis == "Success Probability": + b_guess = 1 / 2**self._num_qubits + + mirror_curve = curve_data.get_subset_of("mirror") + alpha_mirror = curve.guess.rb_decay(mirror_curve.x, mirror_curve.y, b=b_guess) + a_guess = (curve_data.y[0] - b_guess) / (alpha_mirror ** curve_data.x[0]) + + user_opt.p0.set_if_empty(b=b_guess, a=a_guess, alpha=alpha_mirror) + + return user_opt + + def _format_data( + self, + curve_data: curve.CurveData, + ) -> curve.CurveData: + """Postprocessing for the processed dataset. + + Args: + curve_data: Processed dataset created from experiment results. + + Returns: + Formatted data. + """ + # TODO Eventually move this to data processor, then create RB data processor. + + # take average over the same x value by keeping sigma + data_allocation, xdata, ydata, sigma, shots = curve.data_processing.multi_mean_xy_data( + series=curve_data.data_allocation, + xdata=curve_data.x, + ydata=curve_data.y, + sigma=curve_data.y_err, + shots=curve_data.shots, + method="sample", + ) + + # sort by x value in ascending order + data_allocation, xdata, ydata, sigma, shots = curve.data_processing.data_sort( + series=data_allocation, + xdata=xdata, + ydata=ydata, + sigma=sigma, + shots=shots, + ) + + return curve.CurveData( + x=xdata, + y=ydata, + y_err=sigma, + shots=shots, + data_allocation=data_allocation, + labels=curve_data.labels, + ) + + def _create_analysis_results( + self, + fit_data: curve.FitData, + quality: str, + **metadata, + ) -> List[AnalysisResultData]: + """Create analysis results for important fit parameters. + + Args: + fit_data: Fit outcome. + quality: Quality of fit outcome. + + Returns: + List of analysis result data. + """ + + outcomes = super()._create_analysis_results(fit_data, quality, **metadata) + num_qubits = len(self._physical_qubits) + + # nrb is calculated for both EPC and EI per the equations in the docstring + ei_nrb = 4**self._num_qubits + ei_scale = (ei_nrb - 1) / ei_nrb + epc_nrb = 2**self._num_qubits + epc_scale = (epc_nrb - 1) / epc_nrb + + alpha = fit_data.ufloat_params["alpha"] + + # Calculate EPC and EI per the equations in the docstring + epc = epc_scale * (1 - alpha) + ei = ei_scale * (1 - alpha) + + outcomes.append( + AnalysisResultData( + name="EPC", value=epc, chisq=fit_data.reduced_chisq, quality=quality, extra=metadata + ) + ) + outcomes.append( + AnalysisResultData( + name="EI", value=ei, chisq=fit_data.reduced_chisq, quality=quality, extra=metadata + ) + ) + + # Correction for 1Q depolarizing channel if EPGs are provided + if self.options.epg_1_qubit and num_qubits == 2: + epc = _exclude_1q_error( + epc=epc, + qubits=self._physical_qubits, + gate_counts_per_clifford=self._gate_counts_per_clifford, + extra_analyses=self.options.epg_1_qubit, + ) + outcomes.append( + AnalysisResultData( + name="EPC_corrected", + value=epc, + chisq=fit_data.reduced_chisq, + quality=quality, + extra=metadata, + ) + ) + + # Calculate EPG + if self._gate_counts_per_clifford is not None and self.options.gate_error_ratio: + epg_dict = _calculate_epg( + epc=epc, + qubits=self._physical_qubits, + gate_error_ratio=self.options.gate_error_ratio, + gate_counts_per_clifford=self._gate_counts_per_clifford, + ) + if epg_dict: + for gate, epg_val in epg_dict.items(): + outcomes.append( + AnalysisResultData( + name=f"EPG_{gate}", + value=epg_val, + chisq=fit_data.reduced_chisq, + quality=quality, + extra=metadata, + ) + ) + + return outcomes + + def _run_data_processing( + self, raw_data: List[Dict], models: List[lmfit.Model] + ) -> curve.CurveData: + """Manual data processing + + Args: + raw_data: Payload in the experiment data. + models: A list of LMFIT models that provide the model name and + optionally data sorting keys. + + Returns: + Processed data that will be sent to the formatter method. + + Raises: + DataProcessorError: When model is multi-objective function but + data sorting option is not provided. + DataProcessorError: When key for x values is not found in the metadata. + """ + x_key = self.options.x_key + + try: + xdata = np.asarray([datum["metadata"][x_key] for datum in raw_data], dtype=float) + except KeyError as ex: + raise DataProcessorError( + f"X value key {x_key} is not defined in circuit metadata." + ) from ex + + ydata = self._compute_polarizations_and_probabilities(raw_data) + shots = np.asarray([datum.get("shots", np.nan) for datum in raw_data]) + + def _matched(metadata, **filters): + try: + return all(metadata[key] == val for key, val in filters.items()) + except KeyError: + return False + + if len(models) == 1: + # all data belongs to the single model + data_allocation = np.full(xdata.size, 0, dtype=int) + else: + data_allocation = np.full(xdata.size, -1, dtype=int) + for idx, sub_model in enumerate(models): + try: + tags = sub_model.opts["data_sort_key"] + except KeyError as ex: + raise DataProcessorError( + f"Data sort options for model {sub_model.name} is not defined." + ) from ex + if tags is None: + continue + matched_inds = np.asarray( + [_matched(d["metadata"], **tags) for d in raw_data], dtype=bool + ) + data_allocation[matched_inds] = idx + + return curve.CurveData( + x=xdata, + y=unp.nominal_values(ydata), + y_err=unp.std_devs(ydata), + shots=shots, + data_allocation=data_allocation, + labels=[sub_model._name for sub_model in models], + ) + + def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp.uarray: + """Compute success probabilities, adjusted success probabilities, and + polarizations from raw results + + Args: + raw_data: List of raw results for each circuit + + Returns: + Unp array of either success probabiltiies, adjusted success probabilities, + or polarizations as specified by the user. + """ + + # Arrays to store the y-axis data and uncertainties + y_data = [] + y_data_unc = [] + target_bs = "0" * self._num_qubits + for circ_result in raw_data: + + # If there is no inverting Pauli layer at the end of the circuit, get the target bitstring + if not circ_result["metadata"]["inverting_pauli_layer"]: + target_bs = circ_result["metadata"]["target"] + + # h[k] = proportion of shots that are Hamming distance k away from target bitstring + hamming_dists = np.zeros(self._num_qubits + 1) + for bitstring, count in circ_result["counts"].items(): + # Compute success probability + success_prob = 0.0 + if bitstring == target_bs: + success_prob = count / circ_result.get( + "shots", sum(circ_result["counts"].values()) + ) + success_prob_unc = np.sqrt(success_prob * (1 - success_prob)) + if self.options.y_axis == "Success Probability": + y_data.append(success_prob) + y_data_unc.append(success_prob_unc) + circ_result["metadata"]["success_probability"] = success_prob + circ_result["metadata"]["success_probability_stddev"] = success_prob_unc + + # Compute hamming distance proportions + target_bs_to_list = [int(char) for char in target_bs] + actual_bs_to_list = [int(char) for char in bitstring] + k = round(hamming(target_bs_to_list, actual_bs_to_list) * self._num_qubits) + hamming_dists[k] += count / circ_result.get( + "shots", sum(circ_result["counts"].values()) + ) + + # Compute hamming distance uncertainties + hamming_dist_unc = np.sqrt(hamming_dists * (1 - hamming_dists)) + + # Compute adjusted success probability and standard deviation + adjusted_success_prob = 0.0 + adjusted_success_prob_unc = 0.0 + for k in range(self._num_qubits + 1): + adjusted_success_prob += (-0.5) ** k * hamming_dists[k] + adjusted_success_prob_unc += (0.5) ** k * hamming_dist_unc[k] ** 2 + adjusted_success_prob_unc = np.sqrt(adjusted_success_prob_unc) + circ_result["metadata"]["adjusted_success_probability"] = adjusted_success_prob + circ_result["metadata"][ + "adjusted_success_probability_stddev" + ] = adjusted_success_prob_unc + if self.options.y_axis == "Adjusted Success Probability": + y_data.append(adjusted_success_prob) + y_data_unc.append(adjusted_success_prob_unc) + + # Compute effective polarization and standard deviation (arXiv:2112.09853v1) + pol_factor = 4**self._num_qubits + pol = pol_factor / (pol_factor - 1) * adjusted_success_prob - 1 / (pol_factor - 1) + pol_unc = np.sqrt(pol_factor / (pol_factor - 1)) * adjusted_success_prob_unc + circ_result["metadata"]["polarization"] = pol + circ_result["metadata"]["polarization_uncertainty"] = pol_unc + if self.options.y_axis == "Effective Polarization": + y_data.append(pol) + y_data_unc.append(pol_unc) + + return unp.uarray(y_data, y_data_unc) + + def _initialize( + self, + experiment_data: ExperimentData, + ): + """Initialize curve analysis with experiment data. + + This method is called ahead of other processing. + + Args: + experiment_data: Experiment data to analyze. + + Raises: + AnalysisError: When circuit metadata for ops count is missing. + """ + super()._initialize(experiment_data) + + if self.options.gate_error_ratio is not None: + # If gate error ratio is not False, EPG analysis is enabled. + # Here analysis prepares gate error ratio and gate counts for EPC to EPG conversion. + + # If gate count dictionary is not set it will compute counts from circuit metadata. + avg_gpc = defaultdict(float) + n_circs = len(experiment_data.data()) + for circ_result in experiment_data.data(): + try: + count_ops = circ_result["metadata"]["count_ops"] + except KeyError as ex: + raise AnalysisError( + "'count_ops' key is not found in the circuit metadata. " + "This analysis cannot compute error per gates. " + "Please disable this with 'gate_error_ratio=False'." + ) from ex + nclif = circ_result["metadata"]["xval"] + for (qinds, gate), count in count_ops: + formatted_key = tuple(sorted(qinds)), gate + avg_gpc[formatted_key] += count / nclif / n_circs + self._gate_counts_per_clifford = dict(avg_gpc) + + if self.options.gate_error_ratio == "default": + # Gate error dict is computed for gates appearing in counts dictionary + # Error ratio among gates is determined based on the predefined lookup table. + # This is not always accurate for every quantum backends. + gate_error_ratio = {} + for qinds, gate in self._gate_counts_per_clifford.keys(): + if set(qinds) != set(experiment_data.metadata["physical_qubits"]): + continue + gate_error_ratio[gate] = _lookup_epg_ratio(gate, len(qinds)) + self.set_options(gate_error_ratio=gate_error_ratio) + + # Get qubit number + self._physical_qubits = experiment_data.metadata["physical_qubits"] + self._num_qubits = len(experiment_data.metadata["physical_qubits"]) + + +def _lookup_epg_ratio(gate: str, n_qubits: int) -> Union[None, int]: + """A helper method to look-up preset gate error ratio for given basis gate name. + + In the table the error ratio is defined based on the count of + typical assembly gate in the gate decomposition. + For example, "u3" gate can be decomposed into two "sx" gates. + In this case, the ratio of "u3" gate error becomes 2. + + .. note:: + + This table is not aware of the actual waveform played on the hardware, + and the returned error ratio is just a guess. + To be precise, user can always set "gate_error_ratio" option of the experiment. + + Args: + gate: Name of the gate. + n_qubits: Number of qubits measured in the RB experiments. + + Returns: + Corresponding error ratio. + + Raises: + QiskitError: When number of qubit is more than three. + """ + + # Gate count in (X, SX)-based decomposition. VZ gate contribution is ignored. + # Amplitude or duration modulated pulse implementation is not considered. + standard_1q_ratio = { + "u1": 0.0, + "u2": 1.0, + "u3": 2.0, + "u": 2.0, + "p": 0.0, + "x": 1.0, + "y": 1.0, + "z": 0.0, + "t": 0.0, + "tdg": 0.0, + "s": 0.0, + "sdg": 0.0, + "sx": 1.0, + "sxdg": 1.0, + "rx": 2.0, + "ry": 2.0, + "rz": 0.0, + "id": 0.0, + "h": 1.0, + } + + # Gate count in (CX, CSX)-based decomposition, 1q gate contribution is ignored. + # Amplitude or duration modulated pulse implementation is not considered. + standard_2q_ratio = { + "swap": 3.0, + "rxx": 2.0, + "rzz": 2.0, + "cx": 1.0, + "cy": 1.0, + "cz": 1.0, + "ch": 1.0, + "crx": 2.0, + "cry": 2.0, + "crz": 2.0, + "csx": 1.0, + "cu1": 2.0, + "cp": 2.0, + "cu": 2.0, + "cu3": 2.0, + } + + if n_qubits == 1: + return standard_1q_ratio.get(gate, None) + + if n_qubits == 2: + return standard_2q_ratio.get(gate, None) + + raise QiskitError( + f"Standard gate error ratio for {n_qubits} qubit RB is not provided. " + "Please explicitly set 'gate_error_ratio' option of the experiment." + ) + + +def _calculate_epg( + epc: Union[float, "UFloat"], + qubits: Sequence[int], + gate_error_ratio: Dict[str, float], + gate_counts_per_clifford: Dict[QubitGateTuple, float], +) -> Dict[str, Union[float, "UFloat"]]: + """A helper mehtod to compute EPGs of basis gates from fit EPC value. + + Args: + epc: Error per Clifford. + qubits: List of qubits used in the experiment. + gate_error_ratio: A dictionary of assumed ratio of errors among basis gates. + gate_counts_per_clifford: Basis gate counts per Clifford gate. + + Returns: + A dictionary of gate errors keyed on the gate name. + """ + norm = 0 + for gate, r_epg in gate_error_ratio.items(): + formatted_key = tuple(sorted(qubits)), gate + norm += r_epg * gate_counts_per_clifford.get(formatted_key, 0.0) + + epgs = {} + for gate, r_epg in gate_error_ratio.items(): + epgs[gate] = r_epg * epc / norm + return epgs + + +def _exclude_1q_error( + epc: Union[float, "UFloat"], + qubits: Tuple[int, int], + gate_counts_per_clifford: Dict[QubitGateTuple, float], + extra_analyses: Optional[List[DbAnalysisResultV1]], +) -> Union[float, "UFloat"]: + """A helper method to exclude contribution of single qubit gates from 2Q EPC. + + Args: + epc: EPC from 2Q RB experiment. + qubits: Index of two qubits used for 2Q RB experiment. + gate_counts_per_clifford: Basis gate counts per 2Q Clifford gate. + extra_analyses: Analysis results containing depolarizing parameters of 1Q RB experiments. + + Returns: + Corrected 2Q EPC. + """ + # Extract EPC of non-measured qubits from previous experiments + epg_1qs = {} + for analyis_data in extra_analyses: + if ( + not analyis_data.name.startswith("EPG_") + or len(analyis_data.device_components) > 1 + or not str(analyis_data.device_components[0]).startswith("Q") + ): + continue + qind = analyis_data.device_components[0]._index + gate = analyis_data.name[4:] + formatted_key = (qind,), gate + epg_1qs[formatted_key] = analyis_data.value + + if not epg_1qs: + return epc + + # Convert 2Q EPC into depolarizing parameter alpha + alpha_c_2q = 1 - 4 / 3 * epc + + # Estimate composite alpha of 1Q channels + alpha_i = [1.0, 1.0] + for q_gate_tup, epg in epg_1qs.items(): + n_gate = gate_counts_per_clifford.get(q_gate_tup, 0.0) + aind = qubits.index(q_gate_tup[0][0]) + alpha_i[aind] *= (1 - 2 * epg) ** n_gate + alpha_c_1q = 1 / 5 * (alpha_i[0] + alpha_i[1] + 3 * alpha_i[0] * alpha_i[1]) + + # Corrected 2Q channel EPC + return 3 / 4 * (1 - (alpha_c_2q / alpha_c_1q)) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py new file mode 100644 index 0000000000..de61554787 --- /dev/null +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -0,0 +1,523 @@ +# 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. +""" +Mirror RB Experiment class. +""" +from typing import Union, Iterable, Optional, List, Sequence +from numpy.random import Generator +from numpy.random.bit_generator import BitGenerator, SeedSequence + +import numpy as np + +try: + import pygsti + from pygsti.processors import QubitProcessorSpec as QPS + from pygsti.processors import CliffordCompilationRules as CCR + from pygsti.baseobjs import QubitGraph as QG + + HAS_PYGSTI = True +except ImportError: + HAS_PYGSTI = False + +from qiskit import QuantumCircuit, QiskitError +from qiskit.circuit import Instruction +from qiskit.quantum_info import Clifford, random_pauli, random_clifford +from qiskit.quantum_info.operators import Pauli +from qiskit.providers.backend import Backend + +from .rb_experiment import StandardRB +from .mirror_rb_analysis import MirrorRBAnalysis + + +class MirrorRB(StandardRB): + """Mirror randomized benchmarking experiment. + + # section: overview + Mirror Randomized Benchmarking (RB) is a method to estimate the average + error-rate of quantum gates that is more scalable than other RB methods + and can thus detect crosstalk errors. + + A mirror RB experiment generates circuits of layers of Cliffords interleaved + with layers of Pauli gates and capped at the start and end by a layer of + single-qubit Cliffords. The second half of the Clifford layers are the + inverses of the first half of Clifford layers. After running the circuits on + a backend, various quantities (success probability, adjusted success + probability, and effective polarization) are computed and used to fit an + exponential decay curve and calculate the EPC (error per Clifford, also + referred to as the average gate infidelity) and entanglement infidelity. Find + more on adjusted success probability, effective polarization, and + entanglement infidelity in Refs. [1, 2, 3]. + + # section: analysis_ref + :py:class:`MirrorRBAnalysis` + + # section: reference + .. ref_arxiv:: 1 2112.09853 + .. ref_arxiv:: 2 2008.11294 + .. ref_arxiv:: 3 2204.07568 + + """ + + def __init__( + self, + qubits: Sequence[int], + lengths: Iterable[int], + local_clifford: bool = True, + pauli_randomize: bool = True, + two_qubit_gate_density: float = 0.2, + backend: Optional[Backend] = None, + num_samples: int = 3, + seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, + full_sampling: bool = False, + inverting_pauli_layer: bool = False, + ): + """Initialize a mirror randomized benchmarking experiment. + + Args: + qubits: A list of physical qubits for the experiment. + lengths: A list of RB sequences lengths. + local_clifford: If True, begin the circuit with uniformly random 1-qubit + Cliffords and end the circuit with their inverses. + pauli_randomize: If True, surround each inner Clifford layer with + uniformly random Paulis. + two_qubit_gate_density: Expected proportion of qubits with CNOTs based on + the backend coupling map. + backend: The backend to run the experiment on. + num_samples: Number of samples to generate for each + sequence length. + seed: Optional, seed used to initialize ``numpy.random.default_rng``. + when generating circuits. The ``default_rng`` will be initialized + with this seed value everytime :meth:`circuits` is called. + full_sampling: If True all Cliffords are independently sampled for + all lengths. If False for sample of lengths longer + sequences are constructed by appending additional + Clifford samples to shorter sequences. + inverting_pauli_layer: If True, a layer of Pauli gates is appended at the + end of the circuit to set all qubits to 0 (with + possibly a global phase) + + Raises: + QiskitError: if an odd length or a negative two qubit gate density is + provided + """ + # All lengths must be even + if not all(length % 2 == 0 for length in lengths): + raise QiskitError("All lengths must be even") + + # Two-qubit density must be non-negative + if two_qubit_gate_density < 0: + raise QiskitError("Two-qubit gate density must be non-negative") + + super().__init__( + qubits, + lengths, + backend=backend, + num_samples=num_samples, + seed=seed, + full_sampling=full_sampling, + ) + + self._local_clifford = local_clifford + self._pauli_randomize = pauli_randomize + self._two_qubit_gate_density = two_qubit_gate_density + + # By default, the inverting Pauli layer at the end of the circuit is not added + self._inverting_pauli_layer = inverting_pauli_layer + + # Set analysis options + self.analysis = MirrorRBAnalysis() + self.analysis.set_options(outcome="0" * self.num_qubits) + + def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: + """Sample Mirror RB circuits. + + Steps: + 1. Sample length/2 layers of random Cliffords + 2. Compute inverse of each layer in the first half of the circuit and append to circuit + 3. Sample the random paulis and interleave them between the Clifford layers + 4. Sample the 1-qubit local Clifford and add them to the beginning and end of the circuit + + Args: + lengths: List of lengths to run Mirror RB + rng: Generator seed + + Returns: + List of QuantumCircuits + + Raises: + QiskitError: if backend without a coupling map is provided + """ + + # Backend must have a coupling map + if not self._backend or not self._backend.configuration().coupling_map: + raise QiskitError( + "Must provide a backend with a coupling map or provide " + + "coupling map if using a simulator" + ) + + circuits = [] + lengths_half = [length // 2 for length in lengths] + for length in lengths_half if self._full_sampling else [lengths_half[-1]]: + # Sample Clifford layer elements for first half of mirror circuit + coupling_map = self._backend.configuration().coupling_map + experiment_coupling_map = [] + for edge in coupling_map: + if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: + experiment_coupling_map.append(edge) + elements = self._clifford_utils.random_edgegrab_clifford_circuits( + self.physical_qubits, + experiment_coupling_map, + self._two_qubit_gate_density, + length, + rng, + ) + + # Copy Clifford layer elements in first half of circuit + elements_without_inv = elements[:] + + # Append inverses of Clifford elements to second half of circuit + for element in elements_without_inv[::-1]: + elements.append(element.inverse()) + element_lengths = [len(elements)] if self._full_sampling else lengths + + # Interleave random Paulis if set by user + if self._pauli_randomize: + elements = self._pauli_dress(elements, rng) + element_lengths = [length * 2 + 1 for length in element_lengths] + int_circuits = self._generate_mirror(elements, element_lengths) + for circuit in int_circuits: + circuit.metadata["mirror"] = True + circuit.metadata["xval"] = (circuit.metadata["xval"] - 1) // 2 + + # Add start and end local cliffords if set by user + if self._local_clifford: + element_lengths = [length + 2 for length in element_lengths] + elements = self._start_end_cliffords(elements, rng) + mirror_circuits = self._generate_mirror(elements, element_lengths) + for circuit in mirror_circuits: + # Use "boolean arithmetic" to calculate xval correctly for each circuit + pauli_scale = self._pauli_randomize + 1 + clifford_const = self._local_clifford * 2 + circuit.metadata["xval"] = ( + circuit.metadata["xval"] - self._pauli_randomize - clifford_const + ) // pauli_scale + circuit.metadata["mirror"] = True + circuits += mirror_circuits + + # Append inverting Pauli layer at end of circuit if set by user + if self._inverting_pauli_layer: + for circuit in circuits: + target = circuit.metadata["target"] + label = "".join(["X" if char == "1" else "I" for char in target]) + circuit.remove_final_measurements() + circuit.append(Pauli(label), list(range(self._num_qubits))) + circuit.measure_all() + + return circuits + + def _pauli_dress(self, element_list: List, rng: Optional[Union[int, Generator]]) -> List: + """Interleaving layers of random Paulis inside the element list. + + Args: + element_list: The list of elements we add the interleaved Paulis to. + rng: (Seed for) random number generator + + Returns: + The new list of elements with the Paulis interleaved. + """ + # Generate random Pauli + rand_pauli = random_pauli(self._num_qubits, seed=rng).to_instruction() + rand_pauli_op = Clifford(rand_pauli) + new_element_list = [(rand_pauli, rand_pauli_op)] + for element in element_list: + new_element_list.append(element) + rand_pauli = random_pauli(self._num_qubits, seed=rng).to_instruction() + rand_pauli_op = Clifford(rand_pauli) + new_element_list.append((rand_pauli, rand_pauli_op)) + return new_element_list + + def _start_end_cliffords( + self, elements: Iterable[Clifford], rng: Optional[Union[int, Generator]] + ) -> List[QuantumCircuit]: + """Add a layer of uniformly random 1-qubit Cliffords to the beginning of the list + and its inverse to the end of the list + + Args: + element_list: The list of elements we add the Clifford layers to + rng: (Seed for) random number generator + + Returns: + The new list of elements with the start and end local (1-qubit) Cliffords. + """ + rand_clifford = [ + self._clifford_utils.random_cliffords(num_qubits=1, rng=rng)[0] + for _ in self.physical_qubits + ] + tensor_op = rand_clifford[0] + for cliff in rand_clifford[1:]: + tensor_op = tensor_op ^ cliff + tensor_circ = tensor_op.to_circuit() + + rand_clifford = random_clifford(self.num_qubits, seed=rng).to_circuit() + return [tensor_circ] + elements + [tensor_circ.inverse()] + + def _generate_mirror( + self, elements: Iterable[Clifford], lengths: Iterable[int] + ) -> List[QuantumCircuit]: + """Return the RB circuits constructed from the given element list with the second + half as the inverse of the first half + + Args: + elements: A list of Clifford elements + lengths: A list of RB sequences lengths. + + Returns: + A list of :class:`QuantumCircuit`s. + + Additional information: + The circuits are constructed iteratively; each circuit is obtained + by extending the previous circuit (without the inversion and measurement gates) + """ + qubits = list(range(self.num_qubits)) + circuits = [] + + circs = [QuantumCircuit(self.num_qubits) for _ in range(len(lengths))] + + for current_length, group_elt_circ in enumerate(elements[: (len(elements) // 2)]): + if isinstance(group_elt_circ, tuple): + group_elt_gate = group_elt_circ[0] + else: + group_elt_gate = group_elt_circ + + if not isinstance(group_elt_gate, Instruction): + group_elt_gate = group_elt_gate.to_instruction() + for circ in circs: + circ.barrier(qubits) + circ.append(group_elt_gate, qubits) + + double_current_length = ( + (current_length + 1) * 2 + 1 if len(elements) % 2 == 1 else (current_length + 1) * 2 + ) + if double_current_length in lengths: + rb_circ = circs.pop() + inv_start = ( + (-(current_length + 1) - 1) if len(elements) % 2 == 1 else -(current_length + 1) + ) + for inv in elements[inv_start:]: + if isinstance(inv, tuple): + group_elt_gate = inv[0] + else: + group_elt_gate = inv + + if not isinstance(group_elt_gate, Instruction): + group_elt_gate = group_elt_gate.to_instruction() + rb_circ.barrier(qubits) + rb_circ.append(group_elt_gate, qubits) + rb_circ.metadata = { + "experiment_type": self._type, + "xval": double_current_length, + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "target": self._clifford_utils.compute_target_bitstring(rb_circ), + "inverting_pauli_layer": self._inverting_pauli_layer, + } + rb_circ.measure_all() + circuits.append(rb_circ) + return circuits + + +class MirrorRBPyGSTi(MirrorRB): + """Mirror RB experiment that uses pyGSTi's circuit generation. This subclass + is primarily used for testing.""" + + def __init__( + self, + qubits: Sequence[int], + lengths: Iterable[int], + local_clifford: bool = True, + pauli_randomize: bool = True, + two_qubit_gate_density: float = 0.2, + backend: Optional[Backend] = None, + num_samples: int = 3, + seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, + full_sampling: bool = False, + inverting_pauli_layer: bool = False, + ): + """Initialize a mirror randomized benchmarking experiment that uses + pyGSTi's circuit generation. + + Args: + qubits: A list of physical qubits for the experiment. + lengths: A list of RB sequences lengths. + local_clifford: If True, begin the circuit with uniformly random 1-qubit + Cliffords and end the circuit with their inverses. + pauli_randomize: If True, surround each inner Clifford layer with + uniformly random Paulis. + two_qubit_gate_density: Expected proportion of qubits with CNOTs based on + the backend coupling map. + backend: The backend to run the experiment on. + num_samples: Number of samples to generate for each + sequence length. + seed: Optional, seed used to initialize ``numpy.random.default_rng``. + when generating circuits. The ``default_rng`` will be initialized + with this seed value everytime :meth:`circuits` is called. + full_sampling: If True all Cliffords are independently sampled for + all lengths. If False for sample of lengths longer + sequences are constructed by appending additional + Clifford samples to shorter sequences. + inverting_pauli_layer: If True, a layer of Pauli gates is appended at the + end of the circuit to set all qubits to 0 (with + possibly a global phase) + + Raises: + ImportError: if user does not have pyGSTi installed + """ + if not HAS_PYGSTI: + raise ImportError("MirrorRBPyGSTi requires pyGSTi to generate circuits.") + + super().__init__( + qubits, + lengths, + local_clifford=local_clifford, + pauli_randomize=pauli_randomize, + two_qubit_gate_density=two_qubit_gate_density, + backend=backend, + num_samples=num_samples, + seed=seed, + full_sampling=full_sampling, + inverting_pauli_layer=inverting_pauli_layer, + ) + + self.analysis = MirrorRBAnalysis() + self._lengths = lengths + self._num_samples = num_samples + self._seed = seed + self.analysis.set_options(outcome="0" * self.num_qubits) + + def _transpiled_circuits(self) -> List[QuantumCircuit]: + """Return a list of experiment circuits, transpiled, with transpiled + circuits stored as metadata.""" + transpiled = super()._transpiled_circuits() + + # Store transpiled circuits in metadata + for circ in transpiled: + circ.metadata["transpiled_qiskit_circ"] = circ + + return transpiled + + def circuits(self) -> List[QuantumCircuit]: + """Return a list of RB circuits generated with PyGSTi. + + Returns: + A list of :class:`QuantumCircuit`. + """ + # Number of qubits to perform MRB on + n_qubits = self._num_qubits + + # Maximum number of qubits in device + max_qubits = self._backend.configuration().n_qubits + qubit_labels = ["Q" + str(i) for i in range(max_qubits)] + + # List of gates to construct circuits with (CNOT and the 24 one-qubit Cliffords) + gate_names = ["Gcnot"] + [f"Gc{i}" for i in range(24)] + + # Construct connectivity map of backend + backend_edge_list = [list(edge) for edge in self._backend.configuration().coupling_map] + connectivity = np.zeros((max_qubits, max_qubits)) + for edge in backend_edge_list: + connectivity[edge[0]][edge[1]] = 1 + connectivity = np.array(connectivity, dtype=bool) + + # Define CNOT availability in backend + availability = {"Gcnot": []} + for i in range(max_qubits): + for j in range(i + 1, max_qubits): + if connectivity[i][j]: + availability["Gcnot"].append(("Q" + str(i), "Q" + str(j))) + + # Initialize graph and quantum processor spec + graph = QG(qubit_labels=qubit_labels, initial_connectivity=connectivity) + pspec = QPS( + max_qubits, + gate_names, + availability=availability, + qubit_labels=qubit_labels, + geometry=graph, + ) + + # Compilation rules for how to combine (or not) random Pauli gates + compilations = { + "absolute": CCR.create_standard( + pspec, "absolute", ("paulis", "1Qcliffords"), verbosity=0 + ), + "paulieq": CCR.create_standard( + pspec, "paulieq", ("1Qcliffords", "allcnots"), verbosity=0 + ), + } + + # Depths to run MRB + depths = self._lengths + + # Number of samples at each depth + num_samples = self._num_samples + + # Random circuit sampler algorithm and the average density of 2Q gate per layer + sampler = "edgegrab" + samplerargs = [2 * self._two_qubit_gate_density] + + # Create pyGSTi experiment design + mrb_design = pygsti.protocols.MirrorRBDesign( + pspec, + depths, + num_samples, + qubit_labels=tuple(qubit_labels[:n_qubits]), + sampler=sampler, + clifford_compilations=compilations, + samplerargs=samplerargs, + seed=self._seed, + ) + + # Create list of circuits to run and analyze using Qiskit Experiments framework + circuits = [] + for idx, d in enumerate(depths): + for sample in range(num_samples): + # Convert PyGSTi circuits to qasm object and then to QuantumCircuit object + qasm = mrb_design.all_circuits_needing_data[ + idx * num_samples + sample + ].convert_to_openqasm() + rb_circ = QuantumCircuit.from_qasm_str(qasm) + + # Store metadata, such as target bitstring and experiment design, to the circuits + rb_circ.metadata = { + "experiment_type": self._type, + "xval": d, + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "target": mrb_design.idealout_lists[idx][sample][0][::-1], + "pygsti_circ": mrb_design, + "inverting_pauli_layer": self._inverting_pauli_layer, + "mirror": True, + } + + circuits.append(rb_circ) + + # Add final layer of inverting Pauli gates if specified by user + if self._inverting_pauli_layer: + for i, circuit in enumerate(circuits): + target = circuit.metadata["target"] + label = "".join(["X" if char == "1" else "I" for char in target]) + circuit.remove_final_measurements() + circuit.barrier(list(range(self._num_qubits))) + circuit.append(Pauli(label=label), list(range(n_qubits))) + circuit.measure_all() + + return circuits From 9cd707448b0a4617c23a1a47c6ce92a94813f48f Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Mon, 11 Jul 2022 14:32:59 -0400 Subject: [PATCH 02/56] edit appropriate mirrorRB-relevant files for PR --- docs/tutorials/randomized_benchmarking.rst | 208 ++- qiskit_experiments/library/__init__.py | 2 +- .../randomized_benchmarking/__init__.py | 2 + .../randomized_benchmarking/clifford_utils.py | 117 ++ ...domized_benchmarking-de55fda43765c34c.yaml | 9 + requirements-dev.txt | 3 +- .../test_randomized_benchmarking.py | 1204 +++++++++++++++++ 7 files changed, 1542 insertions(+), 3 deletions(-) create mode 100644 test/randomized_benchmarking/test_randomized_benchmarking.py diff --git a/docs/tutorials/randomized_benchmarking.rst b/docs/tutorials/randomized_benchmarking.rst index 492d65c68d..131ec0efd9 100644 --- a/docs/tutorials/randomized_benchmarking.rst +++ b/docs/tutorials/randomized_benchmarking.rst @@ -11,10 +11,15 @@ See `Qiskit Textbook `__ for an explanation on the RB method, which is based on Ref. [1, 2]. +.. jupyter-execute:: + :hide-code: + + %matplotlib inline + .. jupyter-execute:: import numpy as np - from qiskit_experiments.library import StandardRB, InterleavedRB + from qiskit_experiments.library import StandardRB, InterleavedRB, MirrorRB from qiskit_experiments.framework import ParallelExperiment, BatchExperiment import qiskit.circuit.library as circuits @@ -304,6 +309,199 @@ Running a 2-qubit interleaved RB experiment print(result) +Mirror RB experiment +-------------------- + +Mirror RB is a RB protocol that is more scalable to larger numbers of qubits, +and as such, it can be used to detect crosstalk errors in a quantum device. A +randomized Clifford mirror circuit consists of + +- random layers of one- and two-qubit Cliffords and their inverses sampled + according to some distribution :math:`\Omega` over a layer set + :math:`\mathbb{L}`, + +- uniformly random Paulis between these layers, and + +- a layer of uniformly random one-qubit Cliffords at the beginning and the end + of the circuit. + +Unlike other RB experiments in Qiskit Experiments, the backend must be specified +when the experiment is instantiated because :math:`\Omega` depends on the +backend's connectivity. Additionally, :math:`\mathbb{L}` + +In standard and interleaved RB, $n$-qubit circuits of varying lengths +:math:`\ell` that compose to the identity are run on a device, and the +**success probability** $P$, the probability that the circuit's output bit +string equals the input bit string, is estimated for each circuit length by +running several circuits at each length. The :math:`P`-versus-:math:`\ell` +curve is fit to the function :math:`A\alpha^\ell + b`, and the error per +Clifford (EPC) (the average infidelity) is estimated using + +.. math:: + + r = \frac{\left(2^n - 1\right)p}{2^n}. + +Our implementation of MRB computes additional values in addition to the +success probability that have been seen in the literature and ``pyGSTi``. +Specifically, we compute the **adjusted success probability** + +.. math:: + + P_0 = \sum_{k=0}^n \left(-\frac{1}{2}\right)^k h_k, + +where :math:`h_k` is the probability of the actual output bit string being +Hamming distance :math:`k` away from the expected output bit string (note +:math:`h_0 = P`). We also compute the **effective polarization** + +.. math:: + + S = \frac{4^n P_0}{4^n - 1} - \frac{1}{4^n - 1}. + +In [6], the function :math:`A\alpha^\ell` (without a baseline) is fit to the +effective polarizations to find entanglement infidelities. + +In Qiskit Experiments, mirror RB analysis results include the following: + +- ``alpha``: the depolarizing parameter. The user can select which of + :math:`P, P_0, S` to fit, and the corresponding :math:`\alpha` + will be provided. + +- ``EPC``: the expectation of the average gate infidelity of a layer sampled + according to :math:`\Omega`. + +- ``EI``: the expectation of the entanglement infidelity of a layer sampled + according to :math:`\Omega`. + +Note that the ``EPC`` :math:`\epsilon_a` and the ``EI`` :math:`\epsilon_e` are +related by + +.. math:: + + \epsilon_e = \left(1 + \frac{1}{2^n}\right) \epsilon_a, + +where :math:`n` is the number of qubits (see Ref. [7]). + + +Running a one-qubit mirror RB experiment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. jupyter-execute:: + + lengths = np.arange(2, 810, 200) + num_samples = 30 + seed = 1010 + qubits = (0,) + + # Run a MRB experiment on qubit 0 + exp_1q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) + expdata_1q = exp_1q.run(backend).block_for_results() + results_1q = expdata_1q.analysis_results() + +.. jupyter-execute:: + + # View result data + print("Gate error ratio: %s" % expdata_1q.experiment.analysis.options.gate_error_ratio) + display(expdata_1q.figure(0)) + for result in results_1q: + print(result) + + +Running a two-qubit mirror RB experiment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In MRB experiments with :math:`n > 1` qubits, intermediate Clifford layers +are sampled according to the **edge grab** algorithm [7]. The Clifford layers +in :math:`\mathbb{L}` are constructed from a gate set consisting of +one-qubit Clifford gates and a single two-qubit Clifford gate (e.g., +CX) that can be applied to any two connected qubits. The user can specify +an expected two-qubit gate density +:math:`\xi \in \left[0, \frac{1}{2}\right]`, and each intermediate Clifford +layer will have approximately :math:`n \xi` CXs on average. + +.. jupyter-execute:: + + # Two-qubit circuit example + exp_2q_circ = MirrorRB((0,1), lengths=[4], backend=backend, num_samples=1, seed=1010, two_qubit_gate_density=.4) + qc2 = exp_2q_circ.circuits()[0].decompose()#gates_to_decompose=['Clifford*','circuit*']) + qc2.draw() + +.. jupyter-execute:: + + lengths = np.arange(2, 810, 200) + num_samples = 30 + seed = 1011 + qubits = (0,1) + + # Run a MRB experiment on qubits 0, 1 + exp_2q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) + expdata_2q = exp_2q.run(backend).block_for_results() + results_2q = expdata_2q.analysis_results() + +.. jupyter-execute:: + + # View result data + print("Gate error ratio: %s" % expdata_2q.experiment.analysis.options.gate_error_ratio) + display(expdata_2q.figure(0)) + for result in results_2q: + print(result) + + +Selecting :math:`y`-axis values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. jupyter-execute:: + + lengths = [2, 52, 102, 152] + num_samples = 30 + seed = 42 + qubits = (0,) + + exp = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) + # select y-axis + exp.analysis.set_options(y_axis="Success Probability") # or "Adjusted Success Probability" or "Effective Polarization" + # y-axis label must be set separately + exp.analysis.options.curve_drawer.set_options( + # xlabel="Clifford Length", + ylabel="Success Probability", + ) + expdata = exp.run(backend).block_for_results() + results = expdata.analysis_results() + +.. jupyter-execute:: + + display(expdata.figure(0)) + for result in results: + print(result) + + +Mirror RB user options +~~~~~~~~~~~~~~~~~~~~~~ + +Circuit generation options can be specified when a ``MirrorRB`` experiment +object is instantiated: + +- ``local_clifford`` (default ``True``): if ``True``, begin the circuit with + uniformly random one-qubit Cliffords and end the circuit with their inverses + +- ``pauli_randomize`` (default ``True``): if ``True``, put layers of uniformly + random Paulis between the intermediate Clifford layers + +- ``two_qubit_gate_density`` (default ``0.2``): expected fraction of two-qubit + gates in each intermediate Clifford layer + +- ``inverting_pauli_layer`` (default ``False``): if ``True``, put a layer of + Paulis at the end of the circuit to set the output to + :math:`\left\vert0\right\rangle^{\otimes n}`, up to a global phase + + +Mirror RB implementation in ``pyGSTi`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``MirrorRBPyGSTi`` subclass of ``MirrorRB`` uses the circuit generation in +``pyGSTi`` but the circuit transpilation in Qiskit Experiments. It is primarily +used for testing and comparison, and an instance of such an experiment is +constructed in the same way as described above. + Running a simultaneous RB experiment ------------------------------------ @@ -369,6 +567,14 @@ A. Ohki, Mark B. Ketchen, and M. Steffen, *Characterization of addressability by simultaneous randomized benchmarking*, https://arxiv.org/pdf/1204.6308 +[6] Timothy Proctor, Stefan Seritan, Kenneth Rudinger, Erik Nielsen, Robin +Blume-Kohout, Kevin Young, *Scalable randomized benchmarking of quantum +computers using mirror circuits*, https://arxiv.org/pdf/2112.09853.pdf + +[7] Timothy Proctor, Kenneth Rudinger, Kevin Young, Erik Nielsen, and Robin +Blume-Kohout, *Measuring the Capabilities of Quantum Computers*, +https://arxiv.org/pdf/2008.11294.pdf + .. jupyter-execute:: import qiskit.tools.jupyter diff --git a/qiskit_experiments/library/__init__.py b/qiskit_experiments/library/__init__.py index 5f4b9cb000..c9ee968447 100644 --- a/qiskit_experiments/library/__init__.py +++ b/qiskit_experiments/library/__init__.py @@ -157,7 +157,7 @@ class instance to manage parameters and pulse schedules. ZZRamsey, MultiStateDiscrimination, ) -from .randomized_benchmarking import StandardRB, InterleavedRB +from .randomized_benchmarking import StandardRB, InterleavedRB, MirrorRB, MirrorRBPyGSTi from .tomography import ( StateTomography, ProcessTomography, diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index 2a90d1b424..14b0da5c05 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -44,7 +44,9 @@ """ from .rb_experiment import StandardRB from .interleaved_rb_experiment import InterleavedRB +from .mirror_rb_experiment import MirrorRB, MirrorRBPyGSTi from .rb_analysis import RBAnalysis from .interleaved_rb_analysis import InterleavedRBAnalysis +from .mirror_rb_analysis import MirrorRBAnalysis from .clifford_utils import CliffordUtils from .rb_utils import RBUtils diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 99a1edd9c7..f2467781ba 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -21,6 +21,7 @@ import numpy as np import scipy.sparse +import warnings from numpy.random import Generator, default_rng from qiskit.circuit import CircuitInstruction, Qubit @@ -243,6 +244,91 @@ def random_clifford_circuits( return [random_clifford(num_qubits, seed=rng).to_circuit() for _ in range(size)] @classmethod + def random_edgegrab_clifford_circuits( + self, + qubits: Sequence[int], + coupling_map: list, + two_qubit_gate_density: float = 0.25, + size: int = 1, + rng: Optional[Union[int, Generator]] = None, + ): + """Generate a list of random Clifford circuits sampled using the edgegrab algorithm + + Ref: arXiv:2008.11294v2 + """ + num_qubits = len(qubits) + # if circuit has one qubit, call random_clifford_circuits() + if num_qubits == 1: + return self.random_clifford_circuits(num_qubits, size, rng) + + if rng is None: + rng = default_rng() + + if isinstance(rng, int): + rng = default_rng(rng) + + qc_list = [] + for i in list(range(size)): + all_edges = coupling_map[:] # make copy of coupling map from which we pop edges + selected_edges = [] + while all_edges: + rand_edge = all_edges.pop(rng.integers(len(all_edges))) + selected_edges.append(rand_edge) # move random edge from B to A + old_all_edges = all_edges[:] + all_edges = [] + # only keep edges in B that do not share a vertex with rand_edge + for edge in old_all_edges: + if rand_edge[0] not in edge and rand_edge[1] not in edge: + all_edges.append(edge) + + # A is reduced version of coupling map where each vertex appears maximally once + qr = QuantumRegister(num_qubits) + qc = QuantumCircuit(qr) + two_qubit_prob = 0 + try: + two_qubit_prob = num_qubits * two_qubit_gate_density / len(selected_edges) + except ZeroDivisionError: + warnings.warn( + "Device has no connectivity. All cliffords will be single-qubit Cliffords" + ) + if two_qubit_prob > 1: + warnings.warn( + "Mean number of two-qubit gates is higher than number of selected edges for CNOTs. " + + "Actual density of two-qubit gates will likely be lower than input density" + ) + selected_edges_logical = [ + [np.where(q == np.asarray(qubits))[0][0] for q in edge] for edge in selected_edges + ] + # A_logical is A with logical qubit labels rather than physical ones: + # Example: qubits = (8,4,5,3,7), A = [[4,8],[7,5]] ==> A_logical = [[1,0],[4,2]] + put_1_qubit_clifford = np.arange(num_qubits) + # put_1_qubit_clifford is a list of qubits that aren't assigned to a 2-qubit Clifford + # 1-qubit Clifford will be assigned to these edges + for edge in selected_edges_logical: + if rng.random() < two_qubit_prob: + # with probability two_qubit_prob, place CNOT on edge in A + qc.cx(edge[0], edge[1]) + # remove these qubits from put_1_qubit_clifford + put_1_qubit_clifford = np.setdiff1d(put_1_qubit_clifford, edge) + for q in put_1_qubit_clifford: + # pylint: disable=unbalanced-tuple-unpacking + # copied from clifford_1_qubit_circuit() below + (i, j, p) = self._unpack_num(rng.integers(24), self.CLIFFORD_1_QUBIT_SIG) + if i == 1: + qc.h(q) + if j == 1: + qc._append(SXdgGate(), [qr[q]], []) + if j == 2: + qc._append(SGate(), [qr[q]], []) + if p == 1: + qc.x(q) + if p == 2: + qc.y(q) + if p == 3: + qc.z(q) + qc_list.append(qc) + return qc_list + @lru_cache(maxsize=24) def clifford_1_qubit_circuit(cls, num, basis_gates: Optional[Tuple[str, ...]] = None): """Return the 1-qubit clifford circuit corresponding to `num` @@ -584,3 +670,34 @@ def _layer_indices_from_num(num: Integral) -> Tuple[Integral, Integral, Integral idx1 = num % _NUM_LAYER_1 idx0 = num // _NUM_LAYER_1 return idx0, idx1, idx2 + + def _unpack_num_multi_sigs(self, num, sigs): + """Returns the result of `_unpack_num` on one of the + signatures in `sigs` + """ + for i, sig in enumerate(sigs): + sig_size = 1 + for k in sig: + sig_size *= k + if num < sig_size: + return [i] + self._unpack_num(num, sig) + num -= sig_size + return None + + def compute_target_bitstring(self, circuit: QuantumCircuit) -> str: + """For a Clifford circuit C, compute C|0>. + + Args: + circuit: A Clifford QuantumCircuit + + Returns: + Target bit string + """ + + # convert circuit to Boolean phase vector of stabilizer table + phase_vector = Clifford(circuit).table.phase + n = circuit.num_qubits + + # target string has a 1 for each True in the stabilizer half of the phase vector + target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) + return target diff --git a/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml b/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml index 2942065e4b..1589892e9e 100644 --- a/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml +++ b/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml @@ -1,4 +1,13 @@ --- +features: + - | + A new experiment class :class:`qiskit_experiments.library.MirrorRB` is + introduced. This class implements mirror randomized benchmarking (RB), a version + of RB that uses mirror circuits. It is more scalable than other RB protocols and + can consequently be used to detect crosstalk errors. A similar class + :class:`qiskit_experiments.library.MirrorRBPyGSTi` is also introduced that uses + ``pyGSTi`` circuit generation; it is primarily used for testing. + fixes: - | Initial guess function for the randomized benchmarking analysis :func:`.rb_decay` has been diff --git a/requirements-dev.txt b/requirements-dev.txt index d294ea041f..e2696d2048 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,4 +18,5 @@ cvxpy>=1.1.15 pylatexenc # Pin `importlib-metadata` because of a bug relating to version 5.0.0. See #931 for more. importlib-metadata==4.13.0;python_version<'3.8' -scikit-learn \ No newline at end of file +scikit-learn +pygsti diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py new file mode 100644 index 0000000000..e5b2458a9b --- /dev/null +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -0,0 +1,1204 @@ +# 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 +from qiskit.providers.fake_provider import FakeParis +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.transpiler.basepasses import TransformationPass +from qiskit.transpiler import Layout, PassManager, CouplingMap +from qiskit.transpiler.exceptions import TranspilerError + +from qiskit_experiments.library import randomized_benchmarking as rb +from qiskit_experiments.database_service.exceptions import DbExperimentEntryNotFound +from qiskit_experiments.library.randomized_benchmarking.rb_analysis import RBAnalysis + + +class RBTestCase(QiskitExperimentsTestCase): + """Base test case for randomized benchmarking defining a common noise model.""" + + def setUp(self): + """Setup the tests.""" + super().setUp() + + # depolarizing error + self.p1q = 0.02 + self.p2q = 0.10 + self.pvz = 0.0 + + # basis gates + self.basis_gates = ["sx", "rz", "cx"] + + # setup noise model + sx_error = depolarizing_error(self.p1q, 1) + rz_error = depolarizing_error(self.pvz, 1) + cx_error = depolarizing_error(self.p2q, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + + self.noise_model = noise_model + self.basis_gates = noise_model.basis_gates + + # Need level1 for consecutive gate cancellation for reference EPC value calculation + self.transpiler_options = { + "basis_gates": self.basis_gates, + "optimization_level": 1, + } + + # Aer simulator + self.backend = AerSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=AerSimulator.from_backend(FakeParis()).configuration().coupling_map, + ) + + 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)) + circ.remove_final_measurements() + # In case the final output is |0>^num_qubits up to a phase, we use .table.pauli + self.assertEqual( + Clifford(circ).table.pauli, + iden.table.pauli, + f"Circuit {circ.name} doesn't result in the identity matrix.", + ) + + +def decr_dep_param(q, q_1, q_2, coupling_map): + """Helper function to generate a one-qubit depolarizing channel whose + parameter depends on coupling map distance in a backend""" + d = min(coupling_map.distance(q, q_1), coupling_map.distance(q, q_2)) + return 0.0035 * 0.999**d + + +class NonlocalCXDepError(TransformationPass): + """Transpiler pass for simulating nonlocal errors in a quantum device""" + + def __init__(self, coupling_map, initial_layout=None): + """Maps a DAGCircuit onto a `coupling_map` using swap gates. + Args: + coupling_map (CouplingMap): Directed graph represented a coupling map. + initial_layout (Layout): initial layout of qubits in mapping + """ + super().__init__() + self.coupling_map = coupling_map + self.initial_layout = initial_layout + + def run(self, dag): + """Runs the NonlocalCXDepError pass on `dag` + + Args: + dag (DAGCircuit): DAG to map. + + Returns: + DAGCircuit: A mapped DAG. + + Raises: + TranspilerError: initial layout and coupling map do not have the + same size + """ + + if self.initial_layout is None: + if self.property_set["layout"]: + self.initial_layout = self.property_set["layout"] + else: + self.initial_layout = Layout.generate_trivial_layout(*dag.qregs.values()) + + if len(dag.qubits) != len(self.initial_layout): + raise TranspilerError("The layout does not match the amount of qubits in the DAG") + + if len(self.coupling_map.physical_qubits) != len(self.initial_layout): + raise TranspilerError( + "Mappers require to have the layout to be the same size as the coupling map" + ) + + canonical_register = dag.qregs["q"] + trivial_layout = Layout.generate_trivial_layout(canonical_register) + current_layout = trivial_layout.copy() + + subdags = [] + for layer in dag.layers(): + graph = layer["graph"] + cxs = graph.op_nodes(op=CXGate) + if len(cxs) > 0: + for cx in cxs: + qubit_1 = current_layout[cx.qargs[0]] + qubit_2 = current_layout[cx.qargs[1]] + for qubit in range(dag.num_qubits()): + dep_param = decr_dep_param(qubit, qubit_1, qubit_2, self.coupling_map) + graph.apply_operation_back( + depolarizing_error(dep_param, 1).to_instruction(), + qargs=[canonical_register[qubit]], + cargs=[], + ) + subdags.append(graph) + + err_dag = dag.copy_empty_like() + for subdag in subdags: + err_dag.compose(subdag) + + return err_dag + + +class NoiseSimulator(AerSimulator): + """Quantum device simulator that has nonlocal CX errors""" + + def run(self, circuits, validate=False, parameter_binds=None, **run_options): + """Applies transpiler pass NonlocalCXDepError to circuits run on this backend""" + pm = PassManager() + cm = CouplingMap(couplinglist=self.configuration().coupling_map) + pm.append([NonlocalCXDepError(cm)]) + noise_circuits = pm.run(circuits) + return super().run( + noise_circuits, validate=validate, parameter_binds=parameter_binds, **run_options + ) + + +@ddt +class TestMirrorRB(RBTestCase): + """Test for mirror RB.""" + + def test_single_qubit(self): + """Test single qubit mirror RB.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=list(range(2, 300, 20)), + seed=124, + backend=self.backend, + num_samples=30, + ) + # exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**self.transpiler_options) + self.assertAllIdentity(exp.circuits()) + + expdata = exp.run() + self.assertExperimentDone(expdata) + + # Given we have gate number per Clifford n_gpc, we can compute EPC as + # EPC = 1 - (1 - r)^n_gpc + # where r is gate error of SX gate, i.e. dep-parameter divided by 2. + # We let transpiler use SX and RZ. + # The number of physical gate per Clifford will distribute + # 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. + # But for mirror RB, we must also add the SX gate number per Pauli n_gpp, + # which is 2 for X and Y gates and 0 for I and Z gates (average = 1.0). So the + # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 + epc = expdata.analysis_results("EPC") + epg_sx = expdata.analysis_results("EPG_sx") + print(f"epg_sx: {epg_sx}") + + epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 + print(f"epc: {epc}, epc_expected: {epc_expected}") + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_two_qubit(self): + """Test two qubit RB.""" + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 300, 20)), + seed=123, + backend=self.backend, + num_samples=30, + two_qubit_gate_density=two_qubit_gate_density, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**self.transpiler_options) + self.assertAllIdentity(exp.circuits()) + + expdata = exp.run() + self.assertExperimentDone(expdata) + + # Given a two qubit gate density xi and an n qubit circuit, a Clifford + # layer has n*xi two-qubit gates. Obviously a Pauli has no two-qubit + # gates, so on aveage, a Clifford + Pauli layer has n*xi two-qubit gates + # and 2*n - 2*n*xi one-qubit gates (two layers have 2*n lattice sites, + # 2*n*xi of which are occupied by two-qubit gates). For two-qubit + # mirrored RB, the average infidelity is ((2^2 - 1)/2^2 = 3/4) times + # the two-qubit depolarizing parameter + epc = expdata.analysis_results("EPC") + cx_factor = (1 - 3 * self.p2q / 4) ** (2 * two_qubit_gate_density) + sx_factor = (1 - self.p1q / 2) ** (2 * 2 * (1 - two_qubit_gate_density)) + epc_expected = 1 - cx_factor * sx_factor + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_two_qubit_nonlocal_noise(self): + """Test for 2 qubit Mirrored RB with a nonlocal noise model""" + # depolarizing error + p1q = 0.0 + p2q = 0.01 + pvz = 0.0 + + # setup noise model + sx_error = depolarizing_error(p1q, 1) + rz_error = depolarizing_error(pvz, 1) + cx_error = depolarizing_error(p2q, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + + basis_gates = ["id", "sx", "rz", "cx"] + # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { + "basis_gates": basis_gates, + "optimization_level": 1, + } + # Coupling map is 3 x 3 lattice + noise_backend = NoiseSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=CouplingMap.from_grid(3, 3).get_edges(), + ) + + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 110, 20)), + seed=123, + backend=noise_backend, + num_samples=20, + two_qubit_gate_density=two_qubit_gate_density, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**transpiler_options) + self.assertAllIdentity(exp.circuits()) + expdata = exp.run(noise_backend) + self.assertExperimentDone(expdata) + + epc = expdata.analysis_results("EPC") + # Compared to expected EPC in two-qubit test without nonlocal noise above, + # we include an extra factor for the nonlocal CX error. This nonlocal + # error is modeled by a one-qubit depolarizing channel on each qubit after + # each CX, so the expected number of one-qubit depolarizing channels + # induced by CXs is (number of CXs) * (number of qubits) = (two qubit gate + # density) * (number of qubits) * (number of qubits). + num_q = 2 + cx_factor = (1 - 3 * p2q / 4) ** (num_q * two_qubit_gate_density) + sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) + cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) + epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_three_qubit_nonlocal_noise(self): + """Test three-qubit mirrored RB on a nonlocal noise model""" + # depolarizing error + p1q = 0.001 + p2q = 0.01 + pvz = 0.0 + + # setup noise modelle + sx_error = depolarizing_error(p1q, 1) + rz_error = depolarizing_error(pvz, 1) + cx_error = depolarizing_error(p2q, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + + basis_gates = ["id", "sx", "rz", "cx"] + # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { + "basis_gates": basis_gates, + "optimization_level": 1, + } + noise_backend = NoiseSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=CouplingMap.from_grid(3, 3).get_edges(), + ) + + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1, 2), + lengths=list(range(2, 110, 50)), + seed=123, + backend=noise_backend, + num_samples=20, + two_qubit_gate_density=two_qubit_gate_density, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**transpiler_options) + self.assertAllIdentity(exp.circuits()) + expdata = exp.run(noise_backend) + self.assertExperimentDone(expdata) + + epc = expdata.analysis_results("EPC") + # The expected EPC was computed in simulations not presented here. + # Method: + # 1. Sample N Clifford layers according to the edgegrab algorithm + # in clifford_utils. + # 2. Transpile these into SX, RZ, and CX gates. + # 3. Replace each SX and CX with one- and two-qubit depolarizing + # channels, respectively, and remove RZ gates. + # 4. Use qiskit.quantum_info.average_gate_fidelity on these N layers + # to compute 1 - EPC for each layer, and average over the N layers. + epc_expected = 0.0124 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + + def test_add_more_circuit_yields_lower_variance(self): + """Test variance reduction with larger number of sampling.""" + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 30, 4)), + seed=123, + backend=self.backend, + num_samples=3, + inverting_pauli_layer=False, + ) + exp1.analysis.set_options(gate_error_ratio=None) + exp1.set_transpile_options(**self.transpiler_options) + expdata1 = exp1.run() + self.assertExperimentDone(expdata1) + + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 30, 4)), + seed=456, + backend=self.backend, + num_samples=10, + inverting_pauli_layer=False, + ) + exp2.analysis.set_options(gate_error_ratio=None) + exp2.set_transpile_options(**self.transpiler_options) + expdata2 = exp2.run() + self.assertExperimentDone(expdata2) + + self.assertLess( + expdata2.analysis_results("EPC").value.s, + expdata1.analysis_results("EPC").value.s, + ) + + def test_return_same_circuit(self): + """Test if setting the same seed returns the same circuits.""" + lengths = [10, 20] + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=lengths, + seed=123, + backend=self.backend, + ) + + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=lengths, + seed=123, + backend=self.backend, + ) + + circs1 = exp1.circuits() + circs2 = exp2.circuits() + + for circ1, circ2 in zip(circs1, circs2): + self.assertEqual(circ1.decompose(), circ2.decompose()) + + def test_full_sampling(self): + """Test if full sampling generates different circuits.""" + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=[10, 20], + seed=123, + backend=self.backend, + num_samples=1, + full_sampling=True, + ) + + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=[10, 20], + seed=123, + backend=self.backend, + num_samples=1, + full_sampling=False, + ) + + circs1 = exp1.circuits() + circs2 = exp2.circuits() + + self.assertNotEqual(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()) + + def test_target_bitstring(self): + """Test if correct target bitstring is returned.""" + qc = QuantumCircuit(9) + qc.z(0) + qc.y(1) + qc.y(2) + qc.z(3) + qc.y(4) + qc.x(7) + qc.y(8) + exp = rb.MirrorRB(qubits=[0], lengths=[2], backend=self.backend) + expected_tb = exp._clifford_utils.compute_target_bitstring(qc) + actual_tb = "110010110" + self.assertEqual(expected_tb, actual_tb) + + def test_zero_2q_gate_density(self): + """Test that there are no two-qubit gates when the two-qubit gate + density is set to 0.""" + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=[40], + seed=124, + backend=self.backend, + num_samples=1, + two_qubit_gate_density=0, + ) + circ = exp.circuits()[0].decompose() + for datum in circ.data: + inst_name = datum[0].name + self.assertNotEqual("cx", inst_name) + + def test_max_2q_gate_density(self): + """Test that every intermediate Clifford layer is filled with two-qubit + gates when the two-qubit gate density is set to 0.5, its maximum value + (assuming an even number of qubits and a backend coupling map with full + connectivity).""" + backend = AerSimulator(coupling_map=CouplingMap.from_full(4).get_edges()) + exp = rb.MirrorRB( + qubits=(0, 1, 2, 3), + lengths=[40], + seed=125, + backend=backend, + num_samples=1, + two_qubit_gate_density=0.5, + ) + circ = exp.circuits()[0].decompose() + num_cxs = 0 + for datum in circ.data: + if datum[0].name == "cx": + num_cxs += 1 + self.assertEqual(80, num_cxs) + + def test_local_clifford(self): + """Test that the number of layers is correct depending on whether + local_clifford is set to True or False by counting the number of barriers.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=[2], + seed=126, + backend=self.backend, + num_samples=1, + local_clifford=True, + pauli_randomize=False, + two_qubit_gate_density=0.2, + inverting_pauli_layer=False, + ) + circ = exp.circuits()[0] + num_barriers = 0 + for datum in circ.data: + if datum[0].name == "barrier": + num_barriers += 1 + self.assertEqual(5, num_barriers) + + def test_pauli_randomize(self): + """Test that the number of layers is correct depending on whether + local_clifford is set to True or False by counting the number of barriers.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=[2], + seed=126, + backend=self.backend, + num_samples=1, + local_clifford=False, + pauli_randomize=True, + two_qubit_gate_density=0.2, + inverting_pauli_layer=False, + ) + circ = exp.circuits()[0] + num_barriers = 0 + for datum in circ.data: + if datum[0].name == "barrier": + num_barriers += 1 + self.assertEqual(6, num_barriers) + + def test_inverting_pauli_layer(self): + """Test that a circuit with an inverting Pauli layer at the end (i.e., + a layer of Paulis before the final measurement that restores the output + to |0>^num_qubits up to a global phase) composes to the identity (up to + a global phase)""" + exp = rb.MirrorRB( + qubits=(0, 1, 2), + lengths=[2], + seed=127, + backend=self.backend, + num_samples=3, + local_clifford=True, + pauli_randomize=True, + two_qubit_gate_density=0.2, + inverting_pauli_layer=True, + ) + self.assertAllIdentity(exp.circuits()) + + @data( + { + "qubits": [3, 3], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # repeated qubits + { + "qubits": [0, 1], + "lengths": [2, 4, 6, -8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative length + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": -4, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative number of samples + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 0, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # zero samples + { + "qubits": [0, 1], + "lengths": [2, 6, 6, 6, 10], + "num_samples": 2, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # repeated lengths + { + "qubits": [0, 1], + "lengths": [2, 4, 5, 8, 10], + "num_samples": 2, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # odd length + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "two_qubit_gate_density": -0.1, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative two-qubit gate density + ) + def test_invalid_configuration(self, configs): + """Test raise error when creating experiment with invalid configs.""" + self.assertRaises(QiskitError, rb.MirrorRB, **configs) + + @data( + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator(), + }, # no backend + ) + def test_no_backend(self, configs): + """Test raise error when no backend is provided for sampling circuits.""" + mirror_exp = rb.MirrorRB(**configs) + self.assertRaises(QiskitError, mirror_exp.run) + + @data( + { + "qubits": [0, 25], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator.from_backend(FakeParis()), + }, # Uncoupled qubits to test edgegrab algorithm warning + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "two_qubit_gate_density": 0.6, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # High two-qubit gate density warning + ) + def test_warnings(self, configs): + """Test raise warnings when creating experiment.""" + mirror_exp = rb.MirrorRB(**configs) + self.assertWarns(Warning, mirror_exp.run) + + def test_experiment_config(self): + """Test converting to and from config works""" + exp = rb.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123, backend=self.backend) + loaded_exp = rb.MirrorRB.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.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123) + self.assertRoundTripSerializable(exp, self.json_equiv) + + def test_analysis_config(self): + """ "Test converting analysis to and from config works""" + analysis = RBAnalysis() + loaded = RBAnalysis.from_config(analysis.config()) + self.assertNotEqual(analysis, loaded) + self.assertEqual(analysis.config(), loaded.config()) + + def test_expdata_serialization(self): + """Test serializing experiment data works.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=list(range(2, 200, 50)), + seed=123, + backend=self.backend, + inverting_pauli_layer=False, + ) + exp.set_transpile_options(**self.transpiler_options) + expdata = exp.run() + self.assertExperimentDone(expdata) + self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) + self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) + + +@ddt +class TestStandardRB(RBTestCase): + """Test for standard RB.""" + + def test_single_qubit(self): + """Test single qubit RB.""" + 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()) + + expdata = exp.run() + self.assertExperimentDone(expdata) + + # Given we have gate number per Clifford n_gpc, we can compute EPC as + # EPC = 1 - (1 - r)^n_gpc + # where r is gate error of SX gate, i.e. dep-parameter divided by 2. + # We let transpiler use SX and RZ. + # The number of physical gate per Clifford will distribute + # 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") + + epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_two_qubit(self): + """Test two qubit RB.""" + exp = rb.StandardRB( + qubits=(0, 1), + lengths=list(range(1, 30, 3)), + seed=123, + backend=self.backend, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**self.transpiler_options) + self.assertAllIdentity(exp.circuits()) + + expdata = exp.run() + self.assertExperimentDone(expdata) + + # Given CX error is dominant and 1q error can be negligible. + # Arbitrary SU(4) can be decomposed with (0, 1, 2, 3) CX gates, the expected + # average number of CX gate per Clifford is 1.5. + # Since this is two qubit RB, the dep-parameter is factored by 3/4. + epc = expdata.analysis_results("EPC") + + # Allow for 50 percent tolerance since we ignore 1q gate contribution + epc_expected = 1 - (1 - 3 / 4 * self.p2q) ** 1.5 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) + + def test_add_more_circuit_yields_lower_variance(self): + """Test variance reduction with larger number of sampling.""" + exp1 = rb.StandardRB( + qubits=(0, 1), + lengths=list(range(1, 30, 3)), + seed=123, + backend=self.backend, + num_samples=3, + ) + exp1.analysis.set_options(gate_error_ratio=None) + exp1.set_transpile_options(**self.transpiler_options) + expdata1 = exp1.run() + self.assertExperimentDone(expdata1) + + exp2 = rb.StandardRB( + qubits=(0, 1), + lengths=list(range(1, 30, 3)), + seed=456, + backend=self.backend, + num_samples=5, + ) + exp2.analysis.set_options(gate_error_ratio=None) + exp2.set_transpile_options(**self.transpiler_options) + expdata2 = exp2.run() + self.assertExperimentDone(expdata2) + + self.assertLess( + expdata2.analysis_results("EPC").value.s, + expdata1.analysis_results("EPC").value.s, + ) + + def test_poor_experiment_result(self): + """Test edge case that tail of decay is not sampled. + + This is a special case that fit outcome is very sensitive to initial guess. + Perhaps generated initial guess is close to a local minima. + """ + from qiskit.providers.fake_provider import FakeVigo + + backend = AerSimulator.from_backend(FakeVigo(), seed_simulator=123) + exp = rb.StandardRB( + qubits=(0,), + lengths=[100, 200, 300, 400], + seed=123, + backend=backend, + num_samples=5, + ) + exp.set_transpile_options(basis_gates=["x", "sx", "rz"], optimization_level=1) + expdata = exp.run() + self.assertExperimentDone(expdata) + + overview = expdata.analysis_results(0).value + # This yields bad fit due to poor data points, but still fit is not completely off. + self.assertLess(overview.reduced_chisq, 10) + + def test_return_same_circuit(self): + """Test if setting the same seed returns the same circuits.""" + exp1 = rb.StandardRB( + qubits=(0, 1), + lengths=[10, 20, 30], + seed=123, + backend=self.backend, + ) + + exp2 = rb.StandardRB( + qubits=(0, 1), + lengths=[10, 20, 30], + seed=123, + backend=self.backend, + ) + + circs1 = exp1.circuits() + circs2 = exp2.circuits() + + self.assertEqual(circs1[0].decompose(), circs2[0].decompose()) + self.assertEqual(circs1[1].decompose(), circs2[1].decompose()) + self.assertEqual(circs1[2].decompose(), circs2[2].decompose()) + + def test_full_sampling(self): + """Test if full sampling generates different circuits.""" + exp1 = rb.StandardRB( + qubits=(0, 1), + lengths=[10, 20, 30], + seed=123, + backend=self.backend, + full_sampling=False, + ) + + exp2 = rb.StandardRB( + qubits=(0, 1), + 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()) + + @data( + {"qubits": [3, 3], "lengths": [1, 3, 5, 7, 9], "num_samples": 1, "seed": 100}, + {"qubits": [0, 1], "lengths": [1, 3, 5, -7, 9], "num_samples": 1, "seed": 100}, + {"qubits": [0, 1], "lengths": [1, 3, 5, 7, 9], "num_samples": -4, "seed": 100}, + {"qubits": [0, 1], "lengths": [1, 3, 5, 7, 9], "num_samples": 0, "seed": 100}, + {"qubits": [0, 1], "lengths": [1, 5, 5, 5, 9], "num_samples": 2, "seed": 100}, + ) + def test_invalid_configuration(self, configs): + """Test raise error when creating experiment with invalid configs.""" + self.assertRaises(QiskitError, rb.StandardRB, **configs) + + def test_experiment_config(self): + """Test converting to and from config works""" + 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) + self.assertRoundTripSerializable(exp, self.json_equiv) + + def test_analysis_config(self): + """ "Test converting analysis to and from config works""" + analysis = rb.RBAnalysis() + loaded = rb.RBAnalysis.from_config(analysis.config()) + self.assertNotEqual(analysis, loaded) + self.assertEqual(analysis.config(), loaded.config()) + + def test_expdata_serialization(self): + """Test serializing experiment data works.""" + exp = rb.StandardRB( + qubits=(0,), + lengths=list(range(1, 200, 50)), + seed=123, + backend=self.backend, + ) + exp.set_transpile_options(**self.transpiler_options) + expdata = exp.run() + self.assertExperimentDone(expdata) + self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) + self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) + + +@ddt +class TestInterleavedRB(RBTestCase): + """Test for interleaved RB.""" + + @data([XGate(), [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 + 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 + ) + + 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 + + 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, + ) + exp.set_transpile_options(**self.transpiler_options) + 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) + + def test_two_qubit(self): + """Test two qubit IRB.""" + exp = rb.InterleavedRB( + interleaved_element=CXGate(), + qubits=(0, 1), + lengths=list(range(1, 30, 3)), + seed=123, + backend=self.backend, + ) + exp.set_transpile_options(**self.transpiler_options) + 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 = 3 / 4 * self.p2q + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_non_clifford_interleaved_element(self): + """Verifies trying to run interleaved RB with non Clifford element throws an exception""" + qubits = 1 + lengths = [1, 4, 6, 9, 13, 16] + interleaved_element = TGate() # T gate is not Clifford, this should fail + self.assertRaises( + QiskitError, + rb.InterleavedRB, + interleaved_element=interleaved_element, + qubits=qubits, + lengths=lengths, + ) + + def test_interleaving_delay(self): + """Test delay instruction can be interleaved.""" + # See qiskit-experiments/#727 for details + interleaved_element = Delay(10, unit="us") + exp = rb.InterleavedRB( + interleaved_element, + qubits=[0], + lengths=[1], + num_samples=1, + ) + # Not raises an error + _, int_circ = exp.circuits() + + # barrier, clifford, barrier, "delay", barrier, ... + self.assertEqual(int_circ.data[3][0], interleaved_element) + + def test_interleaving_circuit_with_delay(self): + """Test circuit with delay can be interleaved.""" + delay_qc = QuantumCircuit(2) + delay_qc.delay(10, [0], unit="us") + delay_qc.x(1) + + exp = rb.InterleavedRB( + interleaved_element=delay_qc, qubits=[1, 2], lengths=[1], seed=123, num_samples=1 + ) + _, int_circ = exp.circuits() + + qc = QuantumCircuit(2) + qc.x(1) + expected_inversion = Clifford(int_circ.data[1][0]).compose(qc).adjoint() + # barrier, clifford, barrier, "interleaved circuit", barrier, inversion, ... + self.assertEqual(expected_inversion, Clifford(int_circ.data[5][0])) + + 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 + ) + loaded_exp = rb.InterleavedRB.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.InterleavedRB( + interleaved_element=SXGate(), qubits=(0,), lengths=[10, 20, 30], seed=123 + ) + self.assertRoundTripSerializable(exp, self.json_equiv) + + def test_analysis_config(self): + """ "Test converting analysis to and from config works""" + analysis = rb.InterleavedRBAnalysis() + loaded = rb.InterleavedRBAnalysis.from_config(analysis.config()) + self.assertNotEqual(analysis, loaded) + self.assertEqual(analysis.config(), loaded.config()) + + def test_expdata_serialization(self): + """Test serializing experiment data works.""" + exp = rb.InterleavedRB( + interleaved_element=SXGate(), + qubits=(0,), + lengths=list(range(1, 200, 50)), + seed=123, + backend=self.backend, + ) + exp.set_transpile_options(**self.transpiler_options) + expdata = exp.run() + self.assertExperimentDone(expdata) + self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) + self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) + + +class TestEPGAnalysis(QiskitExperimentsTestCase): + """Test case for EPG colculation from EPC. + EPG and depplarizing probability p are assumed to have following relationship + EPG = (2^n - 1) / 2^n · p + This p is provided to the Aer noise model, thus we verify EPG computation + by comparing the value with the depolarizing probability. + """ + + def setUp(self): + """Setup the tests.""" + super().setUp() + + # Setup noise model, including more gate for complicated EPG computation + # Note that 1Q channel error is amplified to check 1q channel correction mechanism + x_error = depolarizing_error(0.04, 1) + h_error = depolarizing_error(0.02, 1) + s_error = depolarizing_error(0.00, 1) + cx_error = depolarizing_error(0.08, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(x_error, "x") + noise_model.add_all_qubit_quantum_error(h_error, "h") + noise_model.add_all_qubit_quantum_error(s_error, "s") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + + # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { + "basis_gates": ["x", "h", "s", "cx"], + "optimization_level": 1, + } + + # Aer simulator + backend = AerSimulator(noise_model=noise_model, seed_simulator=123) + + # Prepare experiment data and cache for analysis + exp_1qrb_q0 = rb.StandardRB( + qubits=(0,), + lengths=[1, 10, 30, 50, 80, 120, 150, 200], + seed=123, + backend=backend, + ) + 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, + ) + exp_1qrb_q1.set_transpile_options(**transpiler_options) + expdata_1qrb_q1 = exp_1qrb_q1.run(analysis=None).block_for_results(timeout=300) + + exp_2qrb = rb.StandardRB( + qubits=(0, 1), + lengths=[1, 3, 5, 10, 15, 20, 30, 50], + seed=123, + backend=backend, + ) + exp_2qrb.set_transpile_options(**transpiler_options) + expdata_2qrb = exp_2qrb.run(analysis=None).block_for_results(timeout=300) + + self.expdata_1qrb_q0 = expdata_1qrb_q0 + self.expdata_1qrb_q1 = expdata_1qrb_q1 + self.expdata_2qrb = expdata_2qrb + + def test_default_epg_ratio(self): + """Calculate EPG with default ratio dictionary. H and X have the same ratio.""" + analysis = rb.RBAnalysis() + analysis.set_options(outcome="0") + result = analysis.run(self.expdata_1qrb_q0, replace_results=False) + self.assertExperimentDone(result) + + s_epg = result.analysis_results("EPG_s") + h_epg = result.analysis_results("EPG_h") + x_epg = result.analysis_results("EPG_x") + + self.assertEqual(s_epg.value.n, 0.0) + + # H and X gate EPG are assumed to be the same, so this underestimate X and overestimate H + self.assertEqual(h_epg.value.n, x_epg.value.n) + self.assertLess(x_epg.value.n, 0.04 * 0.5) + self.assertGreater(h_epg.value.n, 0.02 * 0.5) + + def test_no_epg(self): + """Calculate no EPGs.""" + analysis = rb.RBAnalysis() + analysis.set_options(outcome="0", gate_error_ratio=None) + result = analysis.run(self.expdata_1qrb_q0, replace_results=False) + self.assertExperimentDone(result) + + with self.assertRaises(DbExperimentEntryNotFound): + result.analysis_results("EPG_s") + + with self.assertRaises(DbExperimentEntryNotFound): + result.analysis_results("EPG_h") + + with self.assertRaises(DbExperimentEntryNotFound): + result.analysis_results("EPG_x") + + def test_with_custom_epg_ratio(self): + """Calculate no EPGs with custom EPG ratio dictionary.""" + analysis = rb.RBAnalysis() + analysis.set_options(outcome="0", gate_error_ratio={"x": 2, "h": 1, "s": 0}) + result = analysis.run(self.expdata_1qrb_q0, replace_results=False) + self.assertExperimentDone(result) + + h_epg = result.analysis_results("EPG_h") + x_epg = result.analysis_results("EPG_x") + + self.assertAlmostEqual(x_epg.value.n, 0.04 * 0.5, delta=0.005) + self.assertAlmostEqual(h_epg.value.n, 0.02 * 0.5, delta=0.005) + + def test_2q_epg(self): + """Compute 2Q EPG without correction. + Since 1Q gates are designed to have comparable EPG with CX gate, + this will overestimate the error of CX gate. + """ + analysis = rb.RBAnalysis() + analysis.set_options(outcome="00") + result = analysis.run(self.expdata_2qrb, replace_results=False) + self.assertExperimentDone(result) + + cx_epg = result.analysis_results("EPG_cx") + + self.assertGreater(cx_epg.value.n, 0.08 * 0.75) + + def test_correct_1q_depolarization(self): + """Compute 2Q EPG with 1Q depolarization correction.""" + analysis_1qrb_q0 = rb.RBAnalysis() + analysis_1qrb_q0.set_options(outcome="0", gate_error_ratio={"x": 2, "h": 1, "s": 0}) + result_q0 = analysis_1qrb_q0.run(self.expdata_1qrb_q0, replace_results=False) + self.assertExperimentDone(result_q0) + + analysis_1qrb_q1 = rb.RBAnalysis() + analysis_1qrb_q1.set_options(outcome="0", gate_error_ratio={"x": 2, "h": 1, "s": 0}) + result_q1 = analysis_1qrb_q1.run(self.expdata_1qrb_q1, replace_results=False) + self.assertExperimentDone(result_q1) + + analysis_2qrb = rb.RBAnalysis() + analysis_2qrb.set_options( + outcome="00", + epg_1_qubit=result_q0.analysis_results() + result_q1.analysis_results(), + ) + result_2qrb = analysis_2qrb.run(self.expdata_2qrb) + self.assertExperimentDone(result_2qrb) + + cx_epg = result_2qrb.analysis_results("EPG_cx") + self.assertAlmostEqual(cx_epg.value.n, 0.08 * 0.75, delta=0.006) From 2de778b0d713d68f8ad61b5371d62c37f36f3c3c Mon Sep 17 00:00:00 2001 From: paco-ri Date: Tue, 12 Jul 2022 09:50:09 -0400 Subject: [PATCH 03/56] remove prints and add paper ref --- docs/tutorials/randomized_benchmarking.rst | 15 +++++++-------- qiskit_experiments/library/__init__.py | 2 ++ .../library/randomized_benchmarking/__init__.py | 2 ++ .../randomized_benchmarking/mirror_rb_analysis.py | 2 +- .../test_randomized_benchmarking.py | 2 -- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/tutorials/randomized_benchmarking.rst b/docs/tutorials/randomized_benchmarking.rst index 131ec0efd9..8dc54e4285 100644 --- a/docs/tutorials/randomized_benchmarking.rst +++ b/docs/tutorials/randomized_benchmarking.rst @@ -325,9 +325,9 @@ randomized Clifford mirror circuit consists of - a layer of uniformly random one-qubit Cliffords at the beginning and the end of the circuit. -Unlike other RB experiments in Qiskit Experiments, the backend must be specified -when the experiment is instantiated because :math:`\Omega` depends on the -backend's connectivity. Additionally, :math:`\mathbb{L}` +Even though a `MirrorRB` experiment can be instantiated without a backend, the +backend must be specified when the circuits are sampled because :math:`\Omega` +depends on the backend's connectivity. In standard and interleaved RB, $n$-qubit circuits of varying lengths :math:`\ell` that compose to the identity are run on a device, and the @@ -362,15 +362,14 @@ effective polarizations to find entanglement infidelities. In Qiskit Experiments, mirror RB analysis results include the following: -- ``alpha``: the depolarizing parameter. The user can select which of - :math:`P, P_0, S` to fit, and the corresponding :math:`\alpha` - will be provided. +- ``alpha``: the depolarizing parameter. The user can select which of :math:`P, P_0, S` + to fit, and the corresponding :math:`\alpha` will be provided. - ``EPC``: the expectation of the average gate infidelity of a layer sampled - according to :math:`\Omega`. + according to :math:`\Omega`. - ``EI``: the expectation of the entanglement infidelity of a layer sampled - according to :math:`\Omega`. + according to :math:`\Omega`. Note that the ``EPC`` :math:`\epsilon_a` and the ``EI`` :math:`\epsilon_e` are related by diff --git a/qiskit_experiments/library/__init__.py b/qiskit_experiments/library/__init__.py index c9ee968447..c3b7c8f135 100644 --- a/qiskit_experiments/library/__init__.py +++ b/qiskit_experiments/library/__init__.py @@ -36,6 +36,8 @@ ~randomized_benchmarking.StandardRB ~randomized_benchmarking.InterleavedRB + ~randomized_benchmarking.MirrorRB + ~randomized_benchmarking.MirrorRBPyGSTi ~tomography.StateTomography ~tomography.ProcessTomography ~tomography.MitigatedStateTomography diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index 14b0da5c05..2de26c2267 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -25,6 +25,8 @@ StandardRB InterleavedRB + MirrorRB + MirrorRBPyGSTi Analysis diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index cd4764acd7..eba1ada8df 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -154,7 +154,7 @@ def _default_options(cls): # By default, EPG for single qubits aren't set default_options.epg_1_qubit = None - # By default, effective polarization (see Tim Proctor paper) is plotted. We can + # By default, effective polarization is plotted (see arXiv:2112.09853). We can # also plot success probability or adjusted success probability (see PyGSTi). # Do this by setting options to "Success Probability" or "Adjusted Success Probability" default_options.y_axis = "Effective Polarization" diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index e5b2458a9b..6f380a7660 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -210,10 +210,8 @@ def test_single_qubit(self): # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 epc = expdata.analysis_results("EPC") epg_sx = expdata.analysis_results("EPG_sx") - print(f"epg_sx: {epg_sx}") epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 - print(f"epc: {epc}, epc_expected: {epc_expected}") self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) def test_two_qubit(self): From a28e6d23a7b0f7ace8dc51330380bf2f3dac374a Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Mon, 11 Jul 2022 17:01:17 -0400 Subject: [PATCH 04/56] update docstrings --- qiskit_experiments/library/__init__.py | 1 - .../randomized_benchmarking/__init__.py | 1 + .../randomized_benchmarking/clifford_utils.py | 34 ++++++++++++++----- .../mirror_rb_analysis.py | 4 +-- .../mirror_rb_experiment.py | 3 +- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/qiskit_experiments/library/__init__.py b/qiskit_experiments/library/__init__.py index c3b7c8f135..ea3c510e75 100644 --- a/qiskit_experiments/library/__init__.py +++ b/qiskit_experiments/library/__init__.py @@ -37,7 +37,6 @@ ~randomized_benchmarking.StandardRB ~randomized_benchmarking.InterleavedRB ~randomized_benchmarking.MirrorRB - ~randomized_benchmarking.MirrorRBPyGSTi ~tomography.StateTomography ~tomography.ProcessTomography ~tomography.MitigatedStateTomography diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index 2de26c2267..53d73e8f04 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -38,6 +38,7 @@ RBAnalysis InterleavedRBAnalysis + MirrorRBAnalysis .. autosummary:: :toctree: ../stubs/ diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index f2467781ba..e9df02602b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -15,9 +15,10 @@ import itertools import os +import warnings from functools import lru_cache from numbers import Integral -from typing import Optional, Union, Tuple, Sequence +from typing import Optional, Union, Tuple, Sequence, List import numpy as np import scipy.sparse @@ -248,12 +249,25 @@ def random_edgegrab_clifford_circuits( self, qubits: Sequence[int], coupling_map: list, - two_qubit_gate_density: float = 0.25, + two_qubit_gate_density: float = 0.2, size: int = 1, rng: Optional[Union[int, Generator]] = None, - ): + ) -> List[QuantumCircuit]: """Generate a list of random Clifford circuits sampled using the edgegrab algorithm + Args: + qubits: Sequence of integers representing the physical qubits + coupling_map: List of edges, where an edge is a list of 2 integers + two_qubit_gate_density: :math:`1/2` times the expected fraction of qubits with CX gates + size: length of RB sequence + rng: Random seed + + Raises: + Warning: If device has no connectivity or two_qubit_gate_density is too high + + Returns: + List of QuantumCircuits + Ref: arXiv:2008.11294v2 """ num_qubits = len(qubits) @@ -273,15 +287,16 @@ def random_edgegrab_clifford_circuits( selected_edges = [] while all_edges: rand_edge = all_edges.pop(rng.integers(len(all_edges))) - selected_edges.append(rand_edge) # move random edge from B to A + selected_edges.append( + rand_edge + ) # move random edge from all_edges to selected_edges old_all_edges = all_edges[:] all_edges = [] - # only keep edges in B that do not share a vertex with rand_edge + # only keep edges in all_edges that do not share a vertex with rand_edge for edge in old_all_edges: if rand_edge[0] not in edge and rand_edge[1] not in edge: all_edges.append(edge) - # A is reduced version of coupling map where each vertex appears maximally once qr = QuantumRegister(num_qubits) qc = QuantumCircuit(qr) two_qubit_prob = 0 @@ -299,14 +314,15 @@ def random_edgegrab_clifford_circuits( selected_edges_logical = [ [np.where(q == np.asarray(qubits))[0][0] for q in edge] for edge in selected_edges ] - # A_logical is A with logical qubit labels rather than physical ones: - # Example: qubits = (8,4,5,3,7), A = [[4,8],[7,5]] ==> A_logical = [[1,0],[4,2]] + # selected_edges_logical is selected_edges with logical qubit labels rather than physical + # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] + # ==> selected_edges_logical = [[1,0],[4,2]] put_1_qubit_clifford = np.arange(num_qubits) # put_1_qubit_clifford is a list of qubits that aren't assigned to a 2-qubit Clifford # 1-qubit Clifford will be assigned to these edges for edge in selected_edges_logical: if rng.random() < two_qubit_prob: - # with probability two_qubit_prob, place CNOT on edge in A + # with probability two_qubit_prob, place CNOT on edge in selected_edges qc.cx(edge[0], edge[1]) # remove these qubits from put_1_qubit_clifford put_1_qubit_clifford = np.setdiff1d(put_1_qubit_clifford, edge) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index eba1ada8df..0d4a455678 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -66,7 +66,7 @@ class MirrorRBAnalysis(curve.CurveAnalysis): .. math:: - p_0 = \sum_{k = 0}^n (-\frac{1}{2})^k h_k + p_0 = \sum_{k = 0}^n \left(-\frac{1}{2}\right)^k h_k where :math:`h_k` is the probability of observing a bitstring of Hamming distance of k from the correct bitstring @@ -75,7 +75,7 @@ class MirrorRBAnalysis(curve.CurveAnalysis): .. math:: - S = \frac{4^n}{4^n - 1}\sum_{k = 0}^n (-\frac{1}{2})^k h_k - \frac{1}{4^n - 1} + S = \frac{4^n}{4^n-1}\left(\sum_{k=0}^n\left(-\frac{1}{2}\right)^k h_k\right)-\frac{1}{4^n-1} # section: fit_model The fit is based on the following decay functions: diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index de61554787..3cb8d0c4dd 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -106,8 +106,7 @@ def __init__( possibly a global phase) Raises: - QiskitError: if an odd length or a negative two qubit gate density is - provided + QiskitError: if an odd length or a negative two qubit gate density is provided """ # All lengths must be even if not all(length % 2 == 0 for length in lengths): From 9d440e8a3d9e5651cd2553839a691f81d84dd6a4 Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Mon, 11 Jul 2022 17:05:04 -0400 Subject: [PATCH 05/56] delete commented series code --- .../randomized_benchmarking/mirror_rb_analysis.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index 0d4a455678..d1f33b6225 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -118,19 +118,6 @@ def __init__(self): self._physical_qubits = None self._num_qubits = None - # __series__ = [ - # curve.SeriesDef( - # name="Mirror", - # fit_func=lambda x, a, alpha, b: curve.fit_function.exponential_decay( - # x, amp=a, lamb=-1.0, base=alpha, baseline=b - # ), - # filter_kwargs={"mirror": True}, - # plot_color="blue", - # plot_symbol="^", - # model_description=r"a \alpha^{x} + b", - # ) - # ] - @classmethod def _default_options(cls): """Default analysis options.""" From 8d656b684825b2998b8a8a5f7bb56ce1eb257565 Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Tue, 12 Jul 2022 09:11:36 -0400 Subject: [PATCH 06/56] fix pygsti version --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index e2696d2048..ce70b90cad 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -19,4 +19,4 @@ pylatexenc # Pin `importlib-metadata` because of a bug relating to version 5.0.0. See #931 for more. importlib-metadata==4.13.0;python_version<'3.8' scikit-learn -pygsti +pygsti==0.9.10.1 From b0432fd673ec676218419318e98e0901ec9202d3 Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Tue, 12 Jul 2022 09:46:52 -0400 Subject: [PATCH 07/56] remove outcomes setting --- .../library/randomized_benchmarking/mirror_rb_experiment.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 3cb8d0c4dd..0e4c04d5b1 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -134,7 +134,6 @@ def __init__( # Set analysis options self.analysis = MirrorRBAnalysis() - self.analysis.set_options(outcome="0" * self.num_qubits) def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: """Sample Mirror RB circuits. From e1de0e478be1267192221470835a3f82fa9d78d5 Mon Sep 17 00:00:00 2001 From: paco-ri Date: Tue, 12 Jul 2022 11:14:31 -0400 Subject: [PATCH 08/56] cleaned RB tutorial --- .../pygsti-data-pygsti-transpiled-circ.png | Bin 0 -> 466714 bytes .../pygsti-data-qiskit-transpiled-circ.png | Bin 0 -> 440826 bytes docs/tutorials/randomized_benchmarking.rst | 15 ++++++++++++++- .../test_randomized_benchmarking.py | 1 - 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 docs/tutorials/pygsti-data-pygsti-transpiled-circ.png create mode 100644 docs/tutorials/pygsti-data-qiskit-transpiled-circ.png diff --git a/docs/tutorials/pygsti-data-pygsti-transpiled-circ.png b/docs/tutorials/pygsti-data-pygsti-transpiled-circ.png new file mode 100644 index 0000000000000000000000000000000000000000..9718be96b7fc0e46afc72096108e9b176af530f1 GIT binary patch literal 466714 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 z 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
  • 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

    R2@C(#cCacEf4;1_*Ovm+c=! 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¥qRTDuqX$$Z{eenP5K{h6kDt(m(^zg2W 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

    0!$h+m$0#<(^MAJK|9ainpyR>nc|} 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 z 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%0AV)PB>(_t;3aq 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 AZvX%Q literal 0 HcmV?d00001 diff --git a/docs/tutorials/randomized_benchmarking.rst b/docs/tutorials/randomized_benchmarking.rst index 8dc54e4285..2fbd6c28b3 100644 --- a/docs/tutorials/randomized_benchmarking.rst +++ b/docs/tutorials/randomized_benchmarking.rst @@ -499,7 +499,20 @@ Mirror RB implementation in ``pyGSTi`` The ``MirrorRBPyGSTi`` subclass of ``MirrorRB`` uses the circuit generation in ``pyGSTi`` but the circuit transpilation in Qiskit Experiments. It is primarily used for testing and comparison, and an instance of such an experiment is -constructed in the same way as described above. +constructed in the same way as described above. ``MirrorRBPyGSTi`` uses Qiskit's +transpilation because ``pyGSTi`` transpiles circuits slightly differently, +producing small discrepancies in fit parameters between the two codes. To +illustrate, consider the two circuits below, both of which were generated in +``pyGSTi``. The first circuit was transpiled in ``pyGSTi``, + +.. image:: pygsti-data-pygsti-transpiled-circ.png + +and the second was transpiled in Qiskit. + +.. image:: pygsti-data-qiskit-transpiled-circ.png + +Note the different implementations of the same Clifford on +qubit 0 in the fifth layer. Running a simultaneous RB experiment diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 6f380a7660..dcbac84a17 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -209,7 +209,6 @@ def test_single_qubit(self): # which is 2 for X and Y gates and 0 for I and Z gates (average = 1.0). So the # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 epc = expdata.analysis_results("EPC") - epg_sx = expdata.analysis_results("EPG_sx") epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) From 859a94e82fefbb61e149a4189f85d6b4448b80ed Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Tue, 12 Jul 2022 10:12:06 -0400 Subject: [PATCH 09/56] move coupling map outside loop, delete elements_without_inv and int_circuits, comment pauli label --- .../mirror_rb_experiment.py | 27 ++++++++++--------- .../test_randomized_benchmarking.py | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 0e4c04d5b1..0f7add1d94 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -164,13 +164,16 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: circuits = [] lengths_half = [length // 2 for length in lengths] - for length in lengths_half if self._full_sampling else [lengths_half[-1]]: - # Sample Clifford layer elements for first half of mirror circuit - coupling_map = self._backend.configuration().coupling_map - experiment_coupling_map = [] - for edge in coupling_map: + + # Get backend coupling map and create coupling map for physical qubits + coupling_map = self._backend.configuration().coupling_map + experiment_coupling_map = [] + for edge in coupling_map: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append(edge) + + for length in lengths_half if self._full_sampling else [lengths_half[-1]]: + # Sample Clifford layer elements for first half of mirror circuit elements = self._clifford_utils.random_edgegrab_clifford_circuits( self.physical_qubits, experiment_coupling_map, @@ -179,11 +182,8 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: rng, ) - # Copy Clifford layer elements in first half of circuit - elements_without_inv = elements[:] - # Append inverses of Clifford elements to second half of circuit - for element in elements_without_inv[::-1]: + for element in elements[::-1]: elements.append(element.inverse()) element_lengths = [len(elements)] if self._full_sampling else lengths @@ -191,10 +191,6 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: if self._pauli_randomize: elements = self._pauli_dress(elements, rng) element_lengths = [length * 2 + 1 for length in element_lengths] - int_circuits = self._generate_mirror(elements, element_lengths) - for circuit in int_circuits: - circuit.metadata["mirror"] = True - circuit.metadata["xval"] = (circuit.metadata["xval"] - 1) // 2 # Add start and end local cliffords if set by user if self._local_clifford: @@ -214,7 +210,12 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: # Append inverting Pauli layer at end of circuit if set by user if self._inverting_pauli_layer: for circuit in circuits: + # Get target bitstring (ideal bitstring outputted by the circuit) target = circuit.metadata["target"] + + # Pauli gates to apply to each qubit to reset each to the state 0. + # E.g., if the ideal bitstring is 01001, the Pauli label is IXIIX, + # which sets all qubits to 0 (up to a global phase) label = "".join(["X" if char == "1" else "I" for char in target]) circuit.remove_final_measurements() circuit.append(Pauli(label), list(range(self._num_qubits))) diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index dcbac84a17..60fc25b998 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -520,7 +520,7 @@ def test_local_clifford(self): def test_pauli_randomize(self): """Test that the number of layers is correct depending on whether - local_clifford is set to True or False by counting the number of barriers.""" + pauli_randomize is set to True or False by counting the number of barriers.""" exp = rb.MirrorRB( qubits=(0,), lengths=[2], From c1444aef40e3c57ac0f3b5a3915f7ca7c4d8ffb3 Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Tue, 12 Jul 2022 10:15:20 -0400 Subject: [PATCH 10/56] reformat files with black and lint --- .../library/randomized_benchmarking/mirror_rb_experiment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 0f7add1d94..7129848fd7 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -169,8 +169,8 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: coupling_map = self._backend.configuration().coupling_map experiment_coupling_map = [] for edge in coupling_map: - if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: - experiment_coupling_map.append(edge) + if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: + experiment_coupling_map.append(edge) for length in lengths_half if self._full_sampling else [lengths_half[-1]]: # Sample Clifford layer elements for first half of mirror circuit From 6857a48f54c1c846c0a60c4f25313b2353ce99b3 Mon Sep 17 00:00:00 2001 From: paco-ri Date: Tue, 12 Jul 2022 12:26:39 -0400 Subject: [PATCH 11/56] moved Clifford sampling in edgegrab algo --- .../randomized_benchmarking/clifford_utils.py | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index e9df02602b..c857fe39cc 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -282,7 +282,7 @@ def random_edgegrab_clifford_circuits( rng = default_rng(rng) qc_list = [] - for i in list(range(size)): + for _ in list(range(size)): all_edges = coupling_map[:] # make copy of coupling map from which we pop edges selected_edges = [] while all_edges: @@ -327,21 +327,10 @@ def random_edgegrab_clifford_circuits( # remove these qubits from put_1_qubit_clifford put_1_qubit_clifford = np.setdiff1d(put_1_qubit_clifford, edge) for q in put_1_qubit_clifford: - # pylint: disable=unbalanced-tuple-unpacking - # copied from clifford_1_qubit_circuit() below - (i, j, p) = self._unpack_num(rng.integers(24), self.CLIFFORD_1_QUBIT_SIG) - if i == 1: - qc.h(q) - if j == 1: - qc._append(SXdgGate(), [qr[q]], []) - if j == 2: - qc._append(SGate(), [qr[q]], []) - if p == 1: - qc.x(q) - if p == 2: - qc.y(q) - if p == 3: - qc.z(q) + clifford1q = self.clifford_1_qubit_circuit(rng.integers(24)) + insts = [datum[0] for datum in clifford1q.data] + for inst in insts: + qc.compose(inst, [q], inplace=True) qc_list.append(qc) return qc_list From 8445f4afb2e5a6013f3884064b5cae00a68ea8f6 Mon Sep 17 00:00:00 2001 From: albertzhu01 Date: Mon, 8 Aug 2022 10:59:53 -0400 Subject: [PATCH 12/56] use full connectivity for coupling map if coupling map is not provided --- .../mirror_rb_experiment.py | 15 ++++++++------- .../test_randomized_benchmarking.py | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 7129848fd7..3325ba327a 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -13,6 +13,7 @@ Mirror RB Experiment class. """ from typing import Union, Iterable, Optional, List, Sequence +from itertools import permutations from numpy.random import Generator from numpy.random.bit_generator import BitGenerator, SeedSequence @@ -156,17 +157,17 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: """ # Backend must have a coupling map - if not self._backend or not self._backend.configuration().coupling_map: - raise QiskitError( - "Must provide a backend with a coupling map or provide " - + "coupling map if using a simulator" - ) + if not self._backend: + raise QiskitError("Must provide a backend") circuits = [] lengths_half = [length // 2 for length in lengths] - # Get backend coupling map and create coupling map for physical qubits - coupling_map = self._backend.configuration().coupling_map + # Coupling map is full connectivity by default. If backend has a coupling map, + # get backend coupling map and create coupling map for physical qubits + coupling_map = list(permutations(np.arange(max(self.physical_qubits) + 1), 2)) + if self._backend.configuration().coupling_map: + coupling_map = self._backend.configuration().coupling_map experiment_coupling_map = [] for edge in coupling_map: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py index 60fc25b998..c429a6ee6b 100644 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/randomized_benchmarking/test_randomized_benchmarking.py @@ -619,7 +619,7 @@ def test_invalid_configuration(self, configs): "lengths": [2, 4, 6, 8, 10], "num_samples": 1, "seed": 100, - "backend": AerSimulator(), + "backend": None, }, # no backend ) def test_no_backend(self, configs): From 63f171c9159f8196eb728cfec4b6a9cbbc6f47f7 Mon Sep 17 00:00:00 2001 From: Paco Rilloraza Date: Thu, 1 Sep 2022 15:56:44 -0400 Subject: [PATCH 13/56] changed AnalysisResult imports --- qiskit_experiments/library/randomized_benchmarking/__init__.py | 3 +-- .../library/randomized_benchmarking/mirror_rb_analysis.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index 53d73e8f04..f65657541f 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -26,7 +26,6 @@ StandardRB InterleavedRB MirrorRB - MirrorRBPyGSTi Analysis @@ -47,7 +46,7 @@ """ from .rb_experiment import StandardRB from .interleaved_rb_experiment import InterleavedRB -from .mirror_rb_experiment import MirrorRB, MirrorRBPyGSTi +from .mirror_rb_experiment import MirrorRB from .rb_analysis import RBAnalysis from .interleaved_rb_analysis import InterleavedRBAnalysis from .mirror_rb_analysis import MirrorRBAnalysis diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index d1f33b6225..fa2f5546fe 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -24,7 +24,7 @@ import qiskit_experiments.curve_analysis as curve from qiskit_experiments.exceptions import AnalysisError from qiskit_experiments.framework import AnalysisResultData, ExperimentData -from qiskit_experiments.database_service import DbAnalysisResultV1 +from qiskit_experiments.framework.analysis_result import AnalysisResult from qiskit_experiments.data_processing.exceptions import DataProcessorError from uncertainties import unumpy as unp # pylint: disable=wrong-import-order From bbf111f672f78279881d7176aa1d7bb8c4a4c0ce Mon Sep 17 00:00:00 2001 From: Paco Rilloraza Date: Wed, 7 Sep 2022 11:43:42 -0400 Subject: [PATCH 14/56] edited BitGenerator and SeedSequence imports --- .../randomized_benchmarking/interleaved_rb_experiment.py | 3 +-- .../library/randomized_benchmarking/mirror_rb_analysis.py | 4 ++-- .../library/randomized_benchmarking/mirror_rb_experiment.py | 3 +-- .../library/randomized_benchmarking/rb_experiment.py | 3 +-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index a16086979f..cf3db91337 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -15,8 +15,7 @@ import warnings from typing import Union, Iterable, Optional, List, Sequence, Tuple -from numpy.random import Generator -from numpy.random.bit_generator import BitGenerator, SeedSequence +from numpy.random import Generator, BitGenerator, SeedSequence from qiskit.circuit import QuantumCircuit, Instruction, Gate, Delay from qiskit.compiler import transpile diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index fa2f5546fe..adb61e46de 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -419,7 +419,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. # Compute hamming distance proportions target_bs_to_list = [int(char) for char in target_bs] actual_bs_to_list = [int(char) for char in bitstring] - k = round(hamming(target_bs_to_list, actual_bs_to_list) * self._num_qubits) + k = int(round(hamming(target_bs_to_list, actual_bs_to_list) * self._num_qubits)) hamming_dists[k] += count / circ_result.get( "shots", sum(circ_result["counts"].values()) ) @@ -621,7 +621,7 @@ def _exclude_1q_error( epc: Union[float, "UFloat"], qubits: Tuple[int, int], gate_counts_per_clifford: Dict[QubitGateTuple, float], - extra_analyses: Optional[List[DbAnalysisResultV1]], + extra_analyses: Optional[List[AnalysisResult]], ) -> Union[float, "UFloat"]: """A helper method to exclude contribution of single qubit gates from 2Q EPC. diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 3325ba327a..ed5b6b1af2 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -14,8 +14,7 @@ """ from typing import Union, Iterable, Optional, List, Sequence from itertools import permutations -from numpy.random import Generator -from numpy.random.bit_generator import BitGenerator, SeedSequence +from numpy.random import Generator, BitGenerator, SeedSequence import numpy as np diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index f329436bd8..a5ec7dfdbc 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -19,8 +19,7 @@ from typing import Union, Iterable, Optional, List, Sequence, Tuple import numpy as np -from numpy.random import Generator, default_rng -from numpy.random.bit_generator import BitGenerator, SeedSequence +from numpy.random import Generator, default_rng, BitGenerator, SeedSequence from qiskit.circuit import QuantumCircuit, Instruction, Barrier from qiskit.exceptions import QiskitError From 23080723af57fedf8b2b333d945d9640792dc3b7 Mon Sep 17 00:00:00 2001 From: Paco Rilloraza Date: Wed, 7 Sep 2022 12:08:59 -0400 Subject: [PATCH 15/56] removed MirrorRBPyGSTi from library init file --- docs/_ext/autoref.py | 2 + docs/tutorials/calibrating_real_device.ipynb | 18 +++--- docs/tutorials/fine_calibrations.ipynb | 59 ++++++++++++------- qiskit_experiments/library/__init__.py | 2 +- .../library/quantum_volume/qv_experiment.py | 3 +- 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/docs/_ext/autoref.py b/docs/_ext/autoref.py index 6a4c42a4ae..3c8f2cefd1 100644 --- a/docs/_ext/autoref.py +++ b/docs/_ext/autoref.py @@ -30,6 +30,7 @@ class WebSite(Directive): .. ref_website:: qiskit-experiments, https://github.com/Qiskit/qiskit-experiments """ + required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True @@ -67,6 +68,7 @@ class Arxiv(Directive): If an article is not found, no journal information will be shown. """ + required_arguments = 2 optional_arguments = 0 final_argument_whitespace = False diff --git a/docs/tutorials/calibrating_real_device.ipynb b/docs/tutorials/calibrating_real_device.ipynb index 6de10a5aa5..4faa746a1f 100644 --- a/docs/tutorials/calibrating_real_device.ipynb +++ b/docs/tutorials/calibrating_real_device.ipynb @@ -41,8 +41,8 @@ "outputs": [], "source": [ "IBMQ.load_account()\n", - "provider = IBMQ.get_provider(hub='ibm-q', group='open', project='main')\n", - "backend = provider.get_backend('ibmq_lima')" + "provider = IBMQ.get_provider(hub=\"ibm-q\", group=\"open\", project=\"main\")\n", + "backend = provider.get_backend(\"ibmq_lima\")" ] }, { @@ -86,16 +86,17 @@ "\n", " with pulse.build(name=\"xm\") as xm:\n", " pulse.play(pulse.Drag(dur, -amp, sigma, beta), drive)\n", - " \n", + "\n", " with pulse.build(name=\"x90p\") as x90p:\n", " pulse.play(pulse.Drag(dur, Parameter(\"amp\"), sigma, Parameter(\"β\")), drive)\n", "\n", " cals.add_schedule(xp, num_qubits=1)\n", " cals.add_schedule(xm, num_qubits=1)\n", " cals.add_schedule(x90p, num_qubits=1)\n", - " \n", + "\n", " return cals\n", "\n", + "\n", "def add_parameter_guesses(cals: Calibrations):\n", " \"\"\"Add guesses for the parameter values to the calibrations.\"\"\"\n", " for sched in [\"xp\", \"x90p\"]:\n", @@ -376,7 +377,7 @@ "outputs": [], "source": [ "freq01_estimate = backend.defaults().qubit_freq_est[qubit]\n", - "frequencies = np.linspace(freq01_estimate -15e6, freq01_estimate + 15e6, 51)\n", + "frequencies = np.linspace(freq01_estimate - 15e6, freq01_estimate + 15e6, 51)\n", "spec = RoughFrequencyCal(qubit, cals, frequencies, backend=backend)\n", "spec.set_experiment_options(amp=0.005)" ] @@ -1098,7 +1099,7 @@ "source": [ "cal_drag.set_experiment_options(reps=[3, 5, 7])\n", "\n", - "cal_drag.circuits()[5].draw(output='mpl')" + "cal_drag.circuits()[5].draw(output=\"mpl\")" ] }, { @@ -1395,7 +1396,9 @@ "scale = target_angle / (target_angle + dtheta)\n", "pulse_amp = cals.get_parameter_value(\"amp\", qubit, \"x\")\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")" + "print(\n", + " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", + ")" ] }, { @@ -1946,6 +1949,7 @@ ], "source": [ "import qiskit.tools.jupyter\n", + "\n", "%qiskit_copyright" ] } diff --git a/docs/tutorials/fine_calibrations.ipynb b/docs/tutorials/fine_calibrations.ipynb index 518d489193..a84f6fa35a 100644 --- a/docs/tutorials/fine_calibrations.ipynb +++ b/docs/tutorials/fine_calibrations.ipynb @@ -40,8 +40,8 @@ "outputs": [], "source": [ "IBMQ.load_account()\n", - "provider = IBMQ.get_provider(hub='ibm-q', group='open', project='main')\n", - "backend = provider.get_backend('ibmq_lima')" + "provider = IBMQ.get_provider(hub=\"ibm-q\", group=\"open\", project=\"main\")\n", + "backend = provider.get_backend(\"ibmq_lima\")" ] }, { @@ -82,7 +82,7 @@ } ], "source": [ - "x_pulse = backend.defaults().instruction_schedule_map.get('x', (qubit,)).instructions[0][1].pulse\n", + "x_pulse = backend.defaults().instruction_schedule_map.get(\"x\", (qubit,)).instructions[0][1].pulse\n", "x_pulse" ] }, @@ -94,15 +94,19 @@ "outputs": [], "source": [ "# create the schedules we need and add them to an instruction schedule map.\n", - "sx_pulse = pulse.Drag(x_pulse.duration, 0.5*x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"SXp_d0\")\n", - "y_pulse = pulse.Drag(x_pulse.duration, 1.0j*x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"Yp_d0\")\n", + "sx_pulse = pulse.Drag(\n", + " x_pulse.duration, 0.5 * x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"SXp_d0\"\n", + ")\n", + "y_pulse = pulse.Drag(\n", + " x_pulse.duration, 1.0j * x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"Yp_d0\"\n", + ")\n", "\n", "d0, inst_map = pulse.DriveChannel(qubit), InstructionScheduleMap()\n", "\n", "for name, pulse_ in [(\"x\", x_pulse), (\"y\", y_pulse), (\"sx\", sx_pulse)]:\n", " with pulse.build(name=name) as sched:\n", " pulse.play(pulse_, d0)\n", - " \n", + "\n", " inst_map.add(name, (qubit,), sched)" ] }, @@ -150,12 +154,12 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_amp = ideal_amp*1.02\n", + "pulse_amp = ideal_amp * 1.02\n", "target_angle = np.pi\n", "\n", "with pulse.build(backend=backend, name=\"x\") as x_over:\n", " pulse.play(pulse.Drag(x_pulse.duration, pulse_amp, x_pulse.sigma, x_pulse.beta), d0)\n", - " \n", + "\n", "inst_map.add(\"x\", (qubit,), x_over)" ] }, @@ -276,7 +280,9 @@ "dtheta = data_over.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")\n", + "print(\n", + " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", + ")\n", "print(f\"Amplitude reported by the backend {ideal_amp:.4f}.\")" ] }, @@ -338,12 +344,12 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_amp = ideal_amp*0.98\n", + "pulse_amp = ideal_amp * 0.98\n", "target_angle = np.pi\n", "\n", "with pulse.build(backend=backend, name=\"xp\") as x_under:\n", " pulse.play(pulse.Drag(x_pulse.duration, pulse_amp, x_pulse.sigma, x_pulse.beta), d0)\n", - " \n", + "\n", "inst_map.add(\"x\", (qubit,), x_under)" ] }, @@ -434,7 +440,9 @@ "dtheta = data_under.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")\n", + "print(\n", + " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", + ")\n", "print(f\"Amplitude reported by the backend {ideal_amp:.4f}.\")" ] }, @@ -462,7 +470,7 @@ "outputs": [], "source": [ "# restore the x_pulse\n", - "inst_map.add(\"x\", (qubit,), backend.defaults().instruction_schedule_map.get('x', (qubit,)))" + "inst_map.add(\"x\", (qubit,), backend.defaults().instruction_schedule_map.get(\"x\", (qubit,)))" ] }, { @@ -571,14 +579,16 @@ } ], "source": [ - "sx = backend.defaults().instruction_schedule_map.get('sx', (qubit,))\n", + "sx = backend.defaults().instruction_schedule_map.get(\"sx\", (qubit,))\n", "sx_ideal_amp = sx.instructions[0][1].pulse.amp\n", "\n", "target_angle = np.pi / 2\n", "dtheta = data_x90p.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(f\"Thus, scale the {sx_pulse.amp:.4f} pulse amplitude by {scale:.3f} to obtain {sx_pulse.amp*scale:.5f}.\")\n", + "print(\n", + " f\"Thus, scale the {sx_pulse.amp:.4f} pulse amplitude by {scale:.3f} to obtain {sx_pulse.amp*scale:.5f}.\"\n", + ")\n", "print(f\"Amplitude reported by the backend {sx_ideal_amp:.4f}.\")" ] }, @@ -597,11 +607,11 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_amp = sx_pulse.amp*scale\n", + "pulse_amp = sx_pulse.amp * scale\n", "\n", "with pulse.build(backend=backend, name=\"sx\") as sx_new:\n", " pulse.play(pulse.Drag(x_pulse.duration, pulse_amp, x_pulse.sigma, x_pulse.beta), d0)\n", - " \n", + "\n", "inst_map.add(\"sx\", (qubit,), sx_new)" ] }, @@ -681,7 +691,9 @@ "dtheta = data_x90p.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")\n", + "print(\n", + " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", + ")\n", "print(f\"Amplitude reported by the backend {sx_ideal_amp:.4f}.\")" ] }, @@ -729,12 +741,12 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_beta = ideal_beta*1.25\n", + "pulse_beta = ideal_beta * 1.25\n", "target_angle = np.pi\n", "\n", "with pulse.build(backend=backend, name=\"x\") as x_over:\n", " pulse.play(pulse.Drag(x_pulse.duration, x_pulse.amp, x_pulse.sigma, pulse_beta), d0)\n", - " \n", + "\n", "inst_map.add(\"x\", (qubit,), x_over)" ] }, @@ -891,7 +903,9 @@ "\n", "ddelta = -0.25 * np.sqrt(np.pi) * dtheta * x_pulse.sigma / ((target_angle**2) / 4)\n", "\n", - "print(f\"Adjust β={pulse_beta:.3f} by ddelta={ddelta:.3f} to get {ddelta + pulse_beta:.3f} as new β.\")\n", + "print(\n", + " f\"Adjust β={pulse_beta:.3f} by ddelta={ddelta:.3f} to get {ddelta + pulse_beta:.3f} as new β.\"\n", + ")\n", "print(f\"The backend reports β={x_pulse.beta:.3f}\")" ] }, @@ -1053,7 +1067,7 @@ } ], "source": [ - "sx = backend.defaults().instruction_schedule_map.get('sx', (qubit,))\n", + "sx = backend.defaults().instruction_schedule_map.get(\"sx\", (qubit,))\n", "sx_amp = sx.instructions[0][1].pulse.amp\n", "\n", "print(f\"Adjust the phase of {np.angle(sx_pulse.amp)} of the sx pulse by {-dhac/2:.3f} rad.\")\n", @@ -1081,6 +1095,7 @@ ], "source": [ "import qiskit.tools.jupyter\n", + "\n", "%qiskit_copyright" ] } diff --git a/qiskit_experiments/library/__init__.py b/qiskit_experiments/library/__init__.py index ea3c510e75..333fa7510b 100644 --- a/qiskit_experiments/library/__init__.py +++ b/qiskit_experiments/library/__init__.py @@ -158,7 +158,7 @@ class instance to manage parameters and pulse schedules. ZZRamsey, MultiStateDiscrimination, ) -from .randomized_benchmarking import StandardRB, InterleavedRB, MirrorRB, MirrorRBPyGSTi +from .randomized_benchmarking import StandardRB, InterleavedRB, MirrorRB from .tomography import ( StateTomography, ProcessTomography, diff --git a/qiskit_experiments/library/quantum_volume/qv_experiment.py b/qiskit_experiments/library/quantum_volume/qv_experiment.py index e56a3b8df2..5067d2ef3f 100644 --- a/qiskit_experiments/library/quantum_volume/qv_experiment.py +++ b/qiskit_experiments/library/quantum_volume/qv_experiment.py @@ -14,8 +14,7 @@ """ from typing import Union, Sequence, Optional, List -from numpy.random import Generator, default_rng -from numpy.random.bit_generator import BitGenerator, SeedSequence +from numpy.random import Generator, default_rng, BitGenerator, SeedSequence try: from qiskit import Aer From ebfa4d617d2bd47161e65003e5cceac1654b797c Mon Sep 17 00:00:00 2001 From: Albert Zhu Date: Sun, 30 Oct 2022 20:49:38 -0400 Subject: [PATCH 16/56] fix full connectivity map generation code --- .../library/randomized_benchmarking/mirror_rb_experiment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index ed5b6b1af2..df0024a2d3 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -164,7 +164,7 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: # Coupling map is full connectivity by default. If backend has a coupling map, # get backend coupling map and create coupling map for physical qubits - coupling_map = list(permutations(np.arange(max(self.physical_qubits) + 1), 2)) + coupling_map = list(permutations(self.physical_qubits, 2)) if self._backend.configuration().coupling_map: coupling_map = self._backend.configuration().coupling_map experiment_coupling_map = [] From de3387626a957545bd0f5cf58387ddce74abdca9 Mon Sep 17 00:00:00 2001 From: Albert Zhu Date: Mon, 31 Oct 2022 17:18:43 -0400 Subject: [PATCH 17/56] remove MirrorRBPyGSTi from mirror_rb_experiment.py, rb tutorial, and release note --- docs/tutorials/randomized_benchmarking.rst | 13 +- .../mirror_rb_experiment.py | 200 ------------------ ...domized_benchmarking-de55fda43765c34c.yaml | 4 +- 3 files changed, 6 insertions(+), 211 deletions(-) diff --git a/docs/tutorials/randomized_benchmarking.rst b/docs/tutorials/randomized_benchmarking.rst index 2fbd6c28b3..f57c1cf610 100644 --- a/docs/tutorials/randomized_benchmarking.rst +++ b/docs/tutorials/randomized_benchmarking.rst @@ -496,14 +496,11 @@ object is instantiated: Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``MirrorRBPyGSTi`` subclass of ``MirrorRB`` uses the circuit generation in -``pyGSTi`` but the circuit transpilation in Qiskit Experiments. It is primarily -used for testing and comparison, and an instance of such an experiment is -constructed in the same way as described above. ``MirrorRBPyGSTi`` uses Qiskit's -transpilation because ``pyGSTi`` transpiles circuits slightly differently, -producing small discrepancies in fit parameters between the two codes. To -illustrate, consider the two circuits below, both of which were generated in -``pyGSTi``. The first circuit was transpiled in ``pyGSTi``, +The ``pyGSTi`` implementation of Mirror RB can be used for testing and +comparison. We note however that ``pyGSTi`` transpiles circuits slightly +differently, producing small discrepancies in fit parameters between the two +codes. To illustrate, consider the two circuits below, both of which were +generated in ``pyGSTi``. The first circuit was transpiled in ``pyGSTi``, .. image:: pygsti-data-pygsti-transpiled-circ.png diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index df0024a2d3..28fde1fab1 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -16,18 +16,6 @@ from itertools import permutations from numpy.random import Generator, BitGenerator, SeedSequence -import numpy as np - -try: - import pygsti - from pygsti.processors import QubitProcessorSpec as QPS - from pygsti.processors import CliffordCompilationRules as CCR - from pygsti.baseobjs import QubitGraph as QG - - HAS_PYGSTI = True -except ImportError: - HAS_PYGSTI = False - from qiskit import QuantumCircuit, QiskitError from qiskit.circuit import Instruction from qiskit.quantum_info import Clifford, random_pauli, random_clifford @@ -332,191 +320,3 @@ def _generate_mirror( rb_circ.measure_all() circuits.append(rb_circ) return circuits - - -class MirrorRBPyGSTi(MirrorRB): - """Mirror RB experiment that uses pyGSTi's circuit generation. This subclass - is primarily used for testing.""" - - def __init__( - self, - qubits: Sequence[int], - lengths: Iterable[int], - local_clifford: bool = True, - pauli_randomize: bool = True, - two_qubit_gate_density: float = 0.2, - backend: Optional[Backend] = None, - num_samples: int = 3, - seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, - full_sampling: bool = False, - inverting_pauli_layer: bool = False, - ): - """Initialize a mirror randomized benchmarking experiment that uses - pyGSTi's circuit generation. - - Args: - qubits: A list of physical qubits for the experiment. - lengths: A list of RB sequences lengths. - local_clifford: If True, begin the circuit with uniformly random 1-qubit - Cliffords and end the circuit with their inverses. - pauli_randomize: If True, surround each inner Clifford layer with - uniformly random Paulis. - two_qubit_gate_density: Expected proportion of qubits with CNOTs based on - the backend coupling map. - backend: The backend to run the experiment on. - num_samples: Number of samples to generate for each - sequence length. - seed: Optional, seed used to initialize ``numpy.random.default_rng``. - when generating circuits. The ``default_rng`` will be initialized - with this seed value everytime :meth:`circuits` is called. - full_sampling: If True all Cliffords are independently sampled for - all lengths. If False for sample of lengths longer - sequences are constructed by appending additional - Clifford samples to shorter sequences. - inverting_pauli_layer: If True, a layer of Pauli gates is appended at the - end of the circuit to set all qubits to 0 (with - possibly a global phase) - - Raises: - ImportError: if user does not have pyGSTi installed - """ - if not HAS_PYGSTI: - raise ImportError("MirrorRBPyGSTi requires pyGSTi to generate circuits.") - - super().__init__( - qubits, - lengths, - local_clifford=local_clifford, - pauli_randomize=pauli_randomize, - two_qubit_gate_density=two_qubit_gate_density, - backend=backend, - num_samples=num_samples, - seed=seed, - full_sampling=full_sampling, - inverting_pauli_layer=inverting_pauli_layer, - ) - - self.analysis = MirrorRBAnalysis() - self._lengths = lengths - self._num_samples = num_samples - self._seed = seed - self.analysis.set_options(outcome="0" * self.num_qubits) - - def _transpiled_circuits(self) -> List[QuantumCircuit]: - """Return a list of experiment circuits, transpiled, with transpiled - circuits stored as metadata.""" - transpiled = super()._transpiled_circuits() - - # Store transpiled circuits in metadata - for circ in transpiled: - circ.metadata["transpiled_qiskit_circ"] = circ - - return transpiled - - def circuits(self) -> List[QuantumCircuit]: - """Return a list of RB circuits generated with PyGSTi. - - Returns: - A list of :class:`QuantumCircuit`. - """ - # Number of qubits to perform MRB on - n_qubits = self._num_qubits - - # Maximum number of qubits in device - max_qubits = self._backend.configuration().n_qubits - qubit_labels = ["Q" + str(i) for i in range(max_qubits)] - - # List of gates to construct circuits with (CNOT and the 24 one-qubit Cliffords) - gate_names = ["Gcnot"] + [f"Gc{i}" for i in range(24)] - - # Construct connectivity map of backend - backend_edge_list = [list(edge) for edge in self._backend.configuration().coupling_map] - connectivity = np.zeros((max_qubits, max_qubits)) - for edge in backend_edge_list: - connectivity[edge[0]][edge[1]] = 1 - connectivity = np.array(connectivity, dtype=bool) - - # Define CNOT availability in backend - availability = {"Gcnot": []} - for i in range(max_qubits): - for j in range(i + 1, max_qubits): - if connectivity[i][j]: - availability["Gcnot"].append(("Q" + str(i), "Q" + str(j))) - - # Initialize graph and quantum processor spec - graph = QG(qubit_labels=qubit_labels, initial_connectivity=connectivity) - pspec = QPS( - max_qubits, - gate_names, - availability=availability, - qubit_labels=qubit_labels, - geometry=graph, - ) - - # Compilation rules for how to combine (or not) random Pauli gates - compilations = { - "absolute": CCR.create_standard( - pspec, "absolute", ("paulis", "1Qcliffords"), verbosity=0 - ), - "paulieq": CCR.create_standard( - pspec, "paulieq", ("1Qcliffords", "allcnots"), verbosity=0 - ), - } - - # Depths to run MRB - depths = self._lengths - - # Number of samples at each depth - num_samples = self._num_samples - - # Random circuit sampler algorithm and the average density of 2Q gate per layer - sampler = "edgegrab" - samplerargs = [2 * self._two_qubit_gate_density] - - # Create pyGSTi experiment design - mrb_design = pygsti.protocols.MirrorRBDesign( - pspec, - depths, - num_samples, - qubit_labels=tuple(qubit_labels[:n_qubits]), - sampler=sampler, - clifford_compilations=compilations, - samplerargs=samplerargs, - seed=self._seed, - ) - - # Create list of circuits to run and analyze using Qiskit Experiments framework - circuits = [] - for idx, d in enumerate(depths): - for sample in range(num_samples): - # Convert PyGSTi circuits to qasm object and then to QuantumCircuit object - qasm = mrb_design.all_circuits_needing_data[ - idx * num_samples + sample - ].convert_to_openqasm() - rb_circ = QuantumCircuit.from_qasm_str(qasm) - - # Store metadata, such as target bitstring and experiment design, to the circuits - rb_circ.metadata = { - "experiment_type": self._type, - "xval": d, - "group": "Clifford", - "physical_qubits": self.physical_qubits, - "target": mrb_design.idealout_lists[idx][sample][0][::-1], - "pygsti_circ": mrb_design, - "inverting_pauli_layer": self._inverting_pauli_layer, - "mirror": True, - } - - circuits.append(rb_circ) - - # Add final layer of inverting Pauli gates if specified by user - if self._inverting_pauli_layer: - for i, circuit in enumerate(circuits): - target = circuit.metadata["target"] - label = "".join(["X" if char == "1" else "I" for char in target]) - circuit.remove_final_measurements() - circuit.barrier(list(range(self._num_qubits))) - circuit.append(Pauli(label=label), list(range(n_qubits))) - circuit.measure_all() - - return circuits diff --git a/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml b/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml index 1589892e9e..06295a358e 100644 --- a/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml +++ b/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml @@ -4,9 +4,7 @@ features: A new experiment class :class:`qiskit_experiments.library.MirrorRB` is introduced. This class implements mirror randomized benchmarking (RB), a version of RB that uses mirror circuits. It is more scalable than other RB protocols and - can consequently be used to detect crosstalk errors. A similar class - :class:`qiskit_experiments.library.MirrorRBPyGSTi` is also introduced that uses - ``pyGSTi`` circuit generation; it is primarily used for testing. + can consequently be used to detect crosstalk errors. fixes: - | From 6fccca12a6af7d97fae5c985d704fb2927cd3960 Mon Sep 17 00:00:00 2001 From: Albert Zhu Date: Tue, 1 Nov 2022 10:46:50 -0400 Subject: [PATCH 18/56] fix coupling map full connectivity generation and update aer imports in tests --- .../library/randomized_benchmarking/mirror_rb_experiment.py | 2 +- .../randomized_benchmarking/test_randomized_benchmarking.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 28fde1fab1..f631a805e2 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -152,7 +152,7 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: # Coupling map is full connectivity by default. If backend has a coupling map, # get backend coupling map and create coupling map for physical qubits - coupling_map = list(permutations(self.physical_qubits, 2)) + coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) if self._backend.configuration().coupling_map: coupling_map = self._backend.configuration().coupling_map experiment_coupling_map = [] diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 4c7ab95731..0f48244391 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -26,6 +26,8 @@ from qiskit.quantum_info import Operator from qiskit_aer import AerSimulator from qiskit_aer.noise import NoiseModel, depolarizing_error + +from qiskit_experiments.library import randomized_benchmarking as rb from qiskit_experiments.database_service.exceptions import ExperimentEntryNotFound from qiskit_experiments.framework.composite import ParallelExperiment from qiskit_experiments.library import randomized_benchmarking as rb From d2f8ff9abf92c75112da4a1b58a22a9309726dd8 Mon Sep 17 00:00:00 2001 From: Albert Zhu Date: Wed, 2 Nov 2022 20:27:50 -0400 Subject: [PATCH 19/56] reformat imports (temporarily) to pass lint with merged code from upstream main --- .../library/randomized_benchmarking/clifford_utils.py | 1 - .../library/randomized_benchmarking/mirror_rb_experiment.py | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index c857fe39cc..179090e7ec 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -22,7 +22,6 @@ import numpy as np import scipy.sparse -import warnings from numpy.random import Generator, default_rng from qiskit.circuit import CircuitInstruction, Qubit diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index f631a805e2..2279759028 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -24,6 +24,7 @@ from .rb_experiment import StandardRB from .mirror_rb_analysis import MirrorRBAnalysis +from .clifford_utils import CliffordUtils class MirrorRB(StandardRB): @@ -117,6 +118,10 @@ def __init__( self._pauli_randomize = pauli_randomize self._two_qubit_gate_density = two_qubit_gate_density + # Will need to update these 2 lines below to fit with current rb experiment code + self._full_sampling = full_sampling + self._clifford_utils = CliffordUtils() + # By default, the inverting Pauli layer at the end of the circuit is not added self._inverting_pauli_layer = inverting_pauli_layer From a7b7a7002ff8522556adb4fc1784ed207878f196 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 31 Jan 2023 18:40:22 -0500 Subject: [PATCH 20/56] merged main branch --- docs/tutorials/calibrating_real_device.ipynb | 18 +- docs/tutorials/fine_calibrations.ipynb | 59 ++-- .../multi_state_discrimination_analysis.py | 21 ++ .../randomized_benchmarking/clifford_utils.py | 295 +++++++++++++++++- .../mirror_rb_analysis.py | 2 +- .../mirror_rb_experiment.py | 36 ++- .../tomography/tomography_experiment.py | 27 ++ .../notes/fix-992-1d3ab6862e7578ac.yaml | 8 + test/base.py | 14 + .../test_randomized_benchmarking.py | 6 +- 10 files changed, 421 insertions(+), 65 deletions(-) create mode 100644 releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml diff --git a/docs/tutorials/calibrating_real_device.ipynb b/docs/tutorials/calibrating_real_device.ipynb index 4faa746a1f..6de10a5aa5 100644 --- a/docs/tutorials/calibrating_real_device.ipynb +++ b/docs/tutorials/calibrating_real_device.ipynb @@ -41,8 +41,8 @@ "outputs": [], "source": [ "IBMQ.load_account()\n", - "provider = IBMQ.get_provider(hub=\"ibm-q\", group=\"open\", project=\"main\")\n", - "backend = provider.get_backend(\"ibmq_lima\")" + "provider = IBMQ.get_provider(hub='ibm-q', group='open', project='main')\n", + "backend = provider.get_backend('ibmq_lima')" ] }, { @@ -86,17 +86,16 @@ "\n", " with pulse.build(name=\"xm\") as xm:\n", " pulse.play(pulse.Drag(dur, -amp, sigma, beta), drive)\n", - "\n", + " \n", " with pulse.build(name=\"x90p\") as x90p:\n", " pulse.play(pulse.Drag(dur, Parameter(\"amp\"), sigma, Parameter(\"β\")), drive)\n", "\n", " cals.add_schedule(xp, num_qubits=1)\n", " cals.add_schedule(xm, num_qubits=1)\n", " cals.add_schedule(x90p, num_qubits=1)\n", - "\n", + " \n", " return cals\n", "\n", - "\n", "def add_parameter_guesses(cals: Calibrations):\n", " \"\"\"Add guesses for the parameter values to the calibrations.\"\"\"\n", " for sched in [\"xp\", \"x90p\"]:\n", @@ -377,7 +376,7 @@ "outputs": [], "source": [ "freq01_estimate = backend.defaults().qubit_freq_est[qubit]\n", - "frequencies = np.linspace(freq01_estimate - 15e6, freq01_estimate + 15e6, 51)\n", + "frequencies = np.linspace(freq01_estimate -15e6, freq01_estimate + 15e6, 51)\n", "spec = RoughFrequencyCal(qubit, cals, frequencies, backend=backend)\n", "spec.set_experiment_options(amp=0.005)" ] @@ -1099,7 +1098,7 @@ "source": [ "cal_drag.set_experiment_options(reps=[3, 5, 7])\n", "\n", - "cal_drag.circuits()[5].draw(output=\"mpl\")" + "cal_drag.circuits()[5].draw(output='mpl')" ] }, { @@ -1396,9 +1395,7 @@ "scale = target_angle / (target_angle + dtheta)\n", "pulse_amp = cals.get_parameter_value(\"amp\", qubit, \"x\")\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(\n", - " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", - ")" + "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")" ] }, { @@ -1949,7 +1946,6 @@ ], "source": [ "import qiskit.tools.jupyter\n", - "\n", "%qiskit_copyright" ] } diff --git a/docs/tutorials/fine_calibrations.ipynb b/docs/tutorials/fine_calibrations.ipynb index a84f6fa35a..518d489193 100644 --- a/docs/tutorials/fine_calibrations.ipynb +++ b/docs/tutorials/fine_calibrations.ipynb @@ -40,8 +40,8 @@ "outputs": [], "source": [ "IBMQ.load_account()\n", - "provider = IBMQ.get_provider(hub=\"ibm-q\", group=\"open\", project=\"main\")\n", - "backend = provider.get_backend(\"ibmq_lima\")" + "provider = IBMQ.get_provider(hub='ibm-q', group='open', project='main')\n", + "backend = provider.get_backend('ibmq_lima')" ] }, { @@ -82,7 +82,7 @@ } ], "source": [ - "x_pulse = backend.defaults().instruction_schedule_map.get(\"x\", (qubit,)).instructions[0][1].pulse\n", + "x_pulse = backend.defaults().instruction_schedule_map.get('x', (qubit,)).instructions[0][1].pulse\n", "x_pulse" ] }, @@ -94,19 +94,15 @@ "outputs": [], "source": [ "# create the schedules we need and add them to an instruction schedule map.\n", - "sx_pulse = pulse.Drag(\n", - " x_pulse.duration, 0.5 * x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"SXp_d0\"\n", - ")\n", - "y_pulse = pulse.Drag(\n", - " x_pulse.duration, 1.0j * x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"Yp_d0\"\n", - ")\n", + "sx_pulse = pulse.Drag(x_pulse.duration, 0.5*x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"SXp_d0\")\n", + "y_pulse = pulse.Drag(x_pulse.duration, 1.0j*x_pulse.amp, x_pulse.sigma, x_pulse.beta, name=\"Yp_d0\")\n", "\n", "d0, inst_map = pulse.DriveChannel(qubit), InstructionScheduleMap()\n", "\n", "for name, pulse_ in [(\"x\", x_pulse), (\"y\", y_pulse), (\"sx\", sx_pulse)]:\n", " with pulse.build(name=name) as sched:\n", " pulse.play(pulse_, d0)\n", - "\n", + " \n", " inst_map.add(name, (qubit,), sched)" ] }, @@ -154,12 +150,12 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_amp = ideal_amp * 1.02\n", + "pulse_amp = ideal_amp*1.02\n", "target_angle = np.pi\n", "\n", "with pulse.build(backend=backend, name=\"x\") as x_over:\n", " pulse.play(pulse.Drag(x_pulse.duration, pulse_amp, x_pulse.sigma, x_pulse.beta), d0)\n", - "\n", + " \n", "inst_map.add(\"x\", (qubit,), x_over)" ] }, @@ -280,9 +276,7 @@ "dtheta = data_over.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(\n", - " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", - ")\n", + "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")\n", "print(f\"Amplitude reported by the backend {ideal_amp:.4f}.\")" ] }, @@ -344,12 +338,12 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_amp = ideal_amp * 0.98\n", + "pulse_amp = ideal_amp*0.98\n", "target_angle = np.pi\n", "\n", "with pulse.build(backend=backend, name=\"xp\") as x_under:\n", " pulse.play(pulse.Drag(x_pulse.duration, pulse_amp, x_pulse.sigma, x_pulse.beta), d0)\n", - "\n", + " \n", "inst_map.add(\"x\", (qubit,), x_under)" ] }, @@ -440,9 +434,7 @@ "dtheta = data_under.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(\n", - " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", - ")\n", + "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")\n", "print(f\"Amplitude reported by the backend {ideal_amp:.4f}.\")" ] }, @@ -470,7 +462,7 @@ "outputs": [], "source": [ "# restore the x_pulse\n", - "inst_map.add(\"x\", (qubit,), backend.defaults().instruction_schedule_map.get(\"x\", (qubit,)))" + "inst_map.add(\"x\", (qubit,), backend.defaults().instruction_schedule_map.get('x', (qubit,)))" ] }, { @@ -579,16 +571,14 @@ } ], "source": [ - "sx = backend.defaults().instruction_schedule_map.get(\"sx\", (qubit,))\n", + "sx = backend.defaults().instruction_schedule_map.get('sx', (qubit,))\n", "sx_ideal_amp = sx.instructions[0][1].pulse.amp\n", "\n", "target_angle = np.pi / 2\n", "dtheta = data_x90p.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(\n", - " f\"Thus, scale the {sx_pulse.amp:.4f} pulse amplitude by {scale:.3f} to obtain {sx_pulse.amp*scale:.5f}.\"\n", - ")\n", + "print(f\"Thus, scale the {sx_pulse.amp:.4f} pulse amplitude by {scale:.3f} to obtain {sx_pulse.amp*scale:.5f}.\")\n", "print(f\"Amplitude reported by the backend {sx_ideal_amp:.4f}.\")" ] }, @@ -607,11 +597,11 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_amp = sx_pulse.amp * scale\n", + "pulse_amp = sx_pulse.amp*scale\n", "\n", "with pulse.build(backend=backend, name=\"sx\") as sx_new:\n", " pulse.play(pulse.Drag(x_pulse.duration, pulse_amp, x_pulse.sigma, x_pulse.beta), d0)\n", - "\n", + " \n", "inst_map.add(\"sx\", (qubit,), sx_new)" ] }, @@ -691,9 +681,7 @@ "dtheta = data_x90p.analysis_results(\"d_theta\").value.nominal_value\n", "scale = target_angle / (target_angle + dtheta)\n", "print(f\"The ideal angle is {target_angle:.2f} rad. We measured a deviation of {dtheta:.3f} rad.\")\n", - "print(\n", - " f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\"\n", - ")\n", + "print(f\"Thus, scale the {pulse_amp:.4f} pulse amplitude by {scale:.3f} to obtain {pulse_amp*scale:.5f}.\")\n", "print(f\"Amplitude reported by the backend {sx_ideal_amp:.4f}.\")" ] }, @@ -741,12 +729,12 @@ "metadata": {}, "outputs": [], "source": [ - "pulse_beta = ideal_beta * 1.25\n", + "pulse_beta = ideal_beta*1.25\n", "target_angle = np.pi\n", "\n", "with pulse.build(backend=backend, name=\"x\") as x_over:\n", " pulse.play(pulse.Drag(x_pulse.duration, x_pulse.amp, x_pulse.sigma, pulse_beta), d0)\n", - "\n", + " \n", "inst_map.add(\"x\", (qubit,), x_over)" ] }, @@ -903,9 +891,7 @@ "\n", "ddelta = -0.25 * np.sqrt(np.pi) * dtheta * x_pulse.sigma / ((target_angle**2) / 4)\n", "\n", - "print(\n", - " f\"Adjust β={pulse_beta:.3f} by ddelta={ddelta:.3f} to get {ddelta + pulse_beta:.3f} as new β.\"\n", - ")\n", + "print(f\"Adjust β={pulse_beta:.3f} by ddelta={ddelta:.3f} to get {ddelta + pulse_beta:.3f} as new β.\")\n", "print(f\"The backend reports β={x_pulse.beta:.3f}\")" ] }, @@ -1067,7 +1053,7 @@ } ], "source": [ - "sx = backend.defaults().instruction_schedule_map.get(\"sx\", (qubit,))\n", + "sx = backend.defaults().instruction_schedule_map.get('sx', (qubit,))\n", "sx_amp = sx.instructions[0][1].pulse.amp\n", "\n", "print(f\"Adjust the phase of {np.angle(sx_pulse.amp)} of the sx pulse by {-dhac/2:.3f} rad.\")\n", @@ -1095,7 +1081,6 @@ ], "source": [ "import qiskit.tools.jupyter\n", - "\n", "%qiskit_copyright" ] } diff --git a/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py b/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py index 94b9bd990a..498286fc55 100644 --- a/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py +++ b/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py @@ -20,12 +20,20 @@ from qiskit.providers.options import Options from qiskit_experiments.framework import BaseAnalysis, AnalysisResultData, ExperimentData from qiskit_experiments.data_processing import SkQDA +from qiskit_experiments.data_processing.exceptions import DataProcessorError from qiskit_experiments.visualization import BasePlotter, IQPlotter, MplDrawer, PlotStyle from qiskit_experiments.warnings import HAS_SKLEARN if TYPE_CHECKING: from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis +try: + from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis + + HAS_SKLEARN = True +except ImportError: + HAS_SKLEARN = False + class MultiStateDiscriminationAnalysis(BaseAnalysis): r"""This class fits a multi-state discriminator to the data. @@ -44,6 +52,19 @@ class MultiStateDiscriminationAnalysis(BaseAnalysis): This class requires that scikit-learn is installed. """ + def __init__(self): + """Setup the analysis. + + Raises: + DataProcessorError: if sklearn is not installed. + """ + if not HAS_SKLEARN: + raise DataProcessorError( + f"SKlearn is needed to initialize an {self.__class__.__name__}." + ) + + super().__init__() + @classmethod @HAS_SKLEARN.require_in_call def _default_options(cls) -> Options: diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 179090e7ec..ed071d2ebb 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -688,20 +688,289 @@ def _unpack_num_multi_sigs(self, num, sigs): num -= sig_size return None - def compute_target_bitstring(self, circuit: QuantumCircuit) -> str: - """For a Clifford circuit C, compute C|0>. - Args: - circuit: A Clifford QuantumCircuit +# Constant mapping from 1Q single Clifford gate to 1Q Clifford numerical identifier. +# This table must be generated using `data.generate_clifford_data.gen_cliff_single_1q_gate_map`, or, +# equivalently, correspond to the ordering implicitly defined by CliffUtils.clifford_1_qubit_circuit. +_CLIFF_SINGLE_GATE_MAP_1Q = { + ("id", (0,)): 0, + ("h", (0,)): 1, + ("sxdg", (0,)): 2, + ("s", (0,)): 4, + ("x", (0,)): 6, + ("sx", (0,)): 8, + ("y", (0,)): 12, + ("z", (0,)): 18, + ("sdg", (0,)): 22, +} +# Constant mapping from 2Q single Clifford gate to 2Q Clifford numerical identifier. +# This table must be generated using `data.generate_clifford_data.gen_cliff_single_2q_gate_map`, or, +# equivalently, correspond to the ordering defined by _layer_indices_from_num and _CLIFFORD_LAYER. +_CLIFF_SINGLE_GATE_MAP_2Q = { + ("id", (0,)): 0, + ("id", (1,)): 0, + ("h", (0,)): 5760, + ("h", (1,)): 2880, + ("sxdg", (0,)): 6720, + ("sxdg", (1,)): 3200, + ("s", (0,)): 7680, + ("s", (1,)): 3520, + ("x", (0,)): 4, + ("x", (1,)): 1, + ("sx", (0,)): 6724, + ("sx", (1,)): 3201, + ("y", (0,)): 8, + ("y", (1,)): 2, + ("z", (0,)): 12, + ("z", (1,)): 3, + ("sdg", (0,)): 7692, + ("sdg", (1,)): 3523, + ("cx", (0, 1)): 16, + ("cx", (1, 0)): 2336, + ("cz", (0, 1)): 368, + ("cz", (1, 0)): 368, +} + + +######## +# Functions for 1-qubit integer Clifford operations +def compose_1q(lhs: Integral, rhs: Integral) -> Integral: + """Return the composition of 1-qubit clifford integers.""" + return _CLIFFORD_COMPOSE_1Q[lhs, rhs] + + +def inverse_1q(num: Integral) -> Integral: + """Return the inverse of a 1-qubit clifford integer.""" + return _CLIFFORD_INVERSE_1Q[num] + + +def num_from_1q_circuit(qc: QuantumCircuit) -> Integral: + """Convert a given 1-qubit Clifford circuit to the corresponding integer.""" + num = 0 + for inst in qc: + rhs = _num_from_1q_gate(op=inst.operation) + num = _CLIFFORD_COMPOSE_1Q[num, rhs] + return num - Returns: - Target bit string - """ - # convert circuit to Boolean phase vector of stabilizer table - phase_vector = Clifford(circuit).table.phase - n = circuit.num_qubits +def _num_from_1q_gate(op: Instruction) -> int: + """ + Convert a given 1-qubit clifford operation to the corresponding integer. + Note that supported operations are limited to ones in :const:`CLIFF_SINGLE_GATE_MAP_1Q` or Rz gate. + + Args: + op: operation to be converted. - # target string has a 1 for each True in the stabilizer half of the phase vector - target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) - return target + Returns: + An integer representing a Clifford consisting of a single operation. + + Raises: + QiskitError: if the input instruction is not a Clifford instruction. + QiskitError: if rz is given with a angle that is not Clifford. + """ + if op.name in {"delay", "barrier"}: + return 0 + try: + name = _deparameterized_name(op) + return _CLIFF_SINGLE_GATE_MAP_1Q[(name, (0,))] + except QiskitError as err: + raise QiskitError( + f"Parameterized instruction {op.name} could not be converted to integer Clifford" + ) from err + except KeyError as err: + raise QiskitError( + f"Instruction {op.name} could not be converted to integer Clifford" + ) from err + + +def _deparameterized_name(inst: Instruction) -> str: + if inst.name == "rz": + if np.isclose(inst.params[0], np.pi) or np.isclose(inst.params[0], -np.pi): + return "z" + elif np.isclose(inst.params[0], np.pi / 2): + return "s" + elif np.isclose(inst.params[0], -np.pi / 2): + return "sdg" + else: + raise QiskitError("Wrong param {} for rz in clifford".format(inst.params[0])) + + return inst.name + + +######## +# Functions for 2-qubit integer Clifford operations +def compose_2q(lhs: Integral, rhs: Integral) -> Integral: + """Return the composition of 2-qubit clifford integers.""" + num = lhs + for layer, idx in enumerate(_layer_indices_from_num(rhs)): + circ = _CLIFFORD_LAYER[layer][idx] + num = _compose_num_with_circuit_2q(num, circ) + return num + + +def inverse_2q(num: Integral) -> Integral: + """Return the inverse of a 2-qubit clifford integer.""" + return _CLIFFORD_INVERSE_2Q[num] + + +def num_from_2q_circuit(qc: QuantumCircuit) -> Integral: + """Convert a given 2-qubit Clifford circuit to the corresponding integer.""" + return _compose_num_with_circuit_2q(0, qc) + + +def _compose_num_with_circuit_2q(num: Integral, qc: QuantumCircuit) -> Integral: + """Compose a number that represents a Clifford, with a Clifford circuit, and return the + number that represents the resulting Clifford.""" + lhs = num + for inst in qc: + qubits = tuple(qc.find_bit(q).index for q in inst.qubits) + rhs = _num_from_2q_gate(op=inst.operation, qubits=qubits) + lhs = _CLIFFORD_COMPOSE_2Q[lhs, rhs] + return lhs + + +def _num_from_2q_gate( + op: Instruction, qubits: Optional[Union[Tuple[int, int], Tuple[int]]] = None +) -> int: + """ + Convert a given 1-qubit clifford operation to the corresponding integer. + Note that supported operations are limited to ones in `CLIFF_SINGLE_GATE_MAP_2Q` or Rz gate. + + Args: + op: operation of instruction to be converted. + qubits: qubits to which the operation applies + + Returns: + An integer representing a Clifford consisting of a single operation. + + Raises: + QiskitError: if the input instruction is not a Clifford instruction. + QiskitError: if rz is given with a angle that is not Clifford. + """ + if op.name in {"delay", "barrier"}: + return 0 + + qubits = qubits or (0, 1) + try: + name = _deparameterized_name(op) + return _CLIFF_SINGLE_GATE_MAP_2Q[(name, qubits)] + except QiskitError as err: + raise QiskitError( + f"Parameterized instruction {op.name} could not be converted to integer Clifford" + ) from err + except KeyError as err: + raise QiskitError( + f"Instruction {op.name} on {qubits} could not be converted to integer Clifford" + ) from err + + +def _append_v_w(qc, vw0, vw1): + if vw0 == "v": + qc.sdg(0) + qc.h(0) + elif vw0 == "w": + qc.h(0) + qc.s(0) + if vw1 == "v": + qc.sdg(1) + qc.h(1) + elif vw1 == "w": + qc.h(1) + qc.s(1) + + +def _create_cliff_2q_layer_0(): + """Layer 0 consists of 0 or 1 H gates on each qubit, followed by 0/1/2 V gates on each qubit. + Number of Cliffords == 36.""" + circuits = [] + num_h = [0, 1] + v_w_gates = ["i", "v", "w"] + for h0, h1, v0, v1 in itertools.product(num_h, num_h, v_w_gates, v_w_gates): + qc = QuantumCircuit(2) + for _ in range(h0): + qc.h(0) + for _ in range(h1): + qc.h(1) + _append_v_w(qc, v0, v1) + circuits.append(qc) + return circuits + + +def _create_cliff_2q_layer_1(): + """Layer 1 consists of one of the following: + - nothing + - cx(0,1) followed by 0/1/2 V gates on each qubit + - cx(0,1), cx(1,0) followed by 0/1/2 V gates on each qubit + - cx(0,1), cx(1,0), cx(0,1) + Number of Cliffords == 20.""" + circuits = [QuantumCircuit(2)] # identity at the beginning + + v_w_gates = ["i", "v", "w"] + for v0, v1 in itertools.product(v_w_gates, v_w_gates): + qc = QuantumCircuit(2) + qc.cx(0, 1) + _append_v_w(qc, v0, v1) + circuits.append(qc) + + for v0, v1 in itertools.product(v_w_gates, v_w_gates): + qc = QuantumCircuit(2) + qc.cx(0, 1) + qc.cx(1, 0) + _append_v_w(qc, v0, v1) + circuits.append(qc) + + qc = QuantumCircuit(2) # swap at the end + qc.cx(0, 1) + qc.cx(1, 0) + qc.cx(0, 1) + circuits.append(qc) + return circuits + + +def _create_cliff_2q_layer_2(): + """Layer 2 consists of a Pauli gate on each qubit {Id, X, Y, Z}. + Number of Cliffords == 16.""" + circuits = [] + pauli = ("i", XGate(), YGate(), ZGate()) + for p0, p1 in itertools.product(pauli, pauli): + qc = QuantumCircuit(2) + if p0 != "i": + qc.append(p0, [0]) + if p1 != "i": + qc.append(p1, [1]) + circuits.append(qc) + return circuits + + +_CLIFFORD_LAYER = ( + _create_cliff_2q_layer_0(), + _create_cliff_2q_layer_1(), + _create_cliff_2q_layer_2(), +) +_NUM_LAYER_0 = 36 +_NUM_LAYER_1 = 20 +_NUM_LAYER_2 = 16 + + +@lru_cache(maxsize=None) +def _transformed_clifford_layer( + layer: int, index: Integral, basis_gates: Tuple[str, ...] +) -> QuantumCircuit: + # Return the index-th quantum circuit of the layer translated with the basis_gates. + # The result is cached for speed. + return _synthesize_clifford_circuit(_CLIFFORD_LAYER[layer][index], basis_gates) + + +def _num_from_layer_indices(triplet: Tuple[Integral, Integral, Integral]) -> Integral: + """Return the clifford number corresponding to the input triplet.""" + num = triplet[0] * _NUM_LAYER_1 * _NUM_LAYER_2 + triplet[1] * _NUM_LAYER_2 + triplet[2] + return num + + +def _layer_indices_from_num(num: Integral) -> Tuple[Integral, Integral, Integral]: + """Return the triplet of layer indices corresponding to the input number.""" + idx2 = num % _NUM_LAYER_2 + num = num // _NUM_LAYER_2 + idx1 = num % _NUM_LAYER_1 + idx0 = num // _NUM_LAYER_1 + return idx0, idx1, idx2 diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index adb61e46de..0e2ca48c12 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -124,7 +124,7 @@ def _default_options(cls): default_options = super()._default_options() # Set labels of axes - default_options.curve_drawer.set_options( + default_options.plotter.set_figure_options( xlabel="Clifford Length", ylabel="Effective Polarization", ) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 2279759028..e79cae5218 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -12,21 +12,55 @@ """ Mirror RB Experiment class. """ +from abc import ABC, abstractmethod from typing import Union, Iterable, Optional, List, Sequence from itertools import permutations -from numpy.random import Generator, BitGenerator, SeedSequence +from numpy.random import Generator, BitGenerator, SeedSequence, default_rng from qiskit import QuantumCircuit, QiskitError from qiskit.circuit import Instruction from qiskit.quantum_info import Clifford, random_pauli, random_clifford from qiskit.quantum_info.operators import Pauli from qiskit.providers.backend import Backend +from qiskit.transpiler.basepasses import TransformationPass from .rb_experiment import StandardRB from .mirror_rb_analysis import MirrorRBAnalysis from .clifford_utils import CliffordUtils +class MirrorRBDistribution(ABC): + """Sampling distribution for the mirror randomized benchmarking experiment.""" + + def __init__(self, seed=None): + self.rng = default_rng(seed) + + @abstractmethod + def __call__(self, qubits, two_qubit_density, coupling_map, **params): + self.qubits = qubits + + +class RandomEdgeGrabDistribution(MirrorRBDistribution): + def __init__(self): + super().__init__(seed) + + def __call__(self, qubits, two_qubit_density, coupling_map, seed=None): + self.two_qubit_density = two_qubit_density + self.coupling_map = coupling_map + + ... + + +class DiscreteLayerDistribution(MirrorRBDistribution): + def __init__(self): + super().__init__(qubits, seed) + + def __call__(self, qubits, layers, probs=None, seed=None): + self.layers = list(layers) + self.probs = probs or [1 / len(layers)] * len(layers) + return rng.choice(self.layers, self.prob) + + class MirrorRB(StandardRB): """Mirror randomized benchmarking experiment. diff --git a/qiskit_experiments/library/tomography/tomography_experiment.py b/qiskit_experiments/library/tomography/tomography_experiment.py index 015f7fa1df..6e3eab64fe 100644 --- a/qiskit_experiments/library/tomography/tomography_experiment.py +++ b/qiskit_experiments/library/tomography/tomography_experiment.py @@ -13,6 +13,7 @@ Quantum Tomography experiment """ +import warnings from typing import Union, Optional, Iterable, List, Tuple, Sequence from itertools import product from qiskit.circuit import QuantumCircuit, Instruction, ClassicalRegister, Clbit @@ -102,6 +103,32 @@ def __init__( Raises: QiskitError: if input params are invalid. """ + # Deprecated kwargs + if qubits is not None: + physical_qubits = qubits + warnings.warn( + "The `qubits` kwarg has been renamed to `physical_qubits`." + " It will be removed in a future release.", + DeprecationWarning, + stacklevel=2, + ) + if measurement_qubits is not None: + measurement_indices = measurement_qubits + warnings.warn( + "The `measurement_qubits` kwarg has been renamed to `measurement_indices`." + " It will be removed in a future release.", + DeprecationWarning, + stacklevel=2, + ) + if preparation_qubits is not None: + preparation_indices = preparation_qubits + warnings.warn( + "The `preparation_qubits` kwarg has been renamed to `preparation_indices`." + " It will be removed in a future release.", + DeprecationWarning, + stacklevel=2, + ) + # Initialize BaseExperiment if physical_qubits is None: physical_qubits = tuple(range(circuit.num_qubits)) diff --git a/releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml b/releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml new file mode 100644 index 0000000000..84722589c8 --- /dev/null +++ b/releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixes bug in the :class:`~.LocalReadoutError` experiment where analysis + would fail when run on an ideal simulator with no readout error. + + See Issue #992 `_ + for additional details. diff --git a/test/base.py b/test/base.py index 41915c2b8d..f8903264e1 100644 --- a/test/base.py +++ b/test/base.py @@ -19,6 +19,20 @@ import warnings from typing import Any, Callable, Optional +# Temporary work around for https://github.com/Qiskit/qiskit-terra/issues/9291 +# The class decorator / method wrapper in qiskit does not handle +# __init_subclass__ properly. Python 3.11.1 added an __init_subclass__ to +# TestCase. It's not that important so as a temporary hack we just drop it. +from unittest import TestCase + +if "__init_subclass__" in TestCase.__dict__: + del TestCase.__init_subclass__ +if not hasattr(TestCase, "_test_cleanups"): + TestCase._test_cleanups = [] +if not hasattr(TestCase, "_classSetupFailed"): + TestCase._classSetupFailed = False +# pylint: disable=wrong-import-position + import numpy as np import uncertainties from lmfit import Model diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 0f48244391..aefc04d46e 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -21,13 +21,15 @@ from qiskit.circuit import Delay, QuantumCircuit, Parameter, Gate from qiskit.circuit.library import SXGate, CXGate, TGate, CZGate from qiskit.exceptions import QiskitError -from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington +from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington, FakeParis from qiskit.pulse import Schedule, InstructionScheduleMap from qiskit.quantum_info import Operator +from qiskit.transpiler.basepasses import TransformationPass +from qiskit.transpiler import Layout, PassManager, CouplingMap + from qiskit_aer import AerSimulator from qiskit_aer.noise import NoiseModel, depolarizing_error -from qiskit_experiments.library import randomized_benchmarking as rb from qiskit_experiments.database_service.exceptions import ExperimentEntryNotFound from qiskit_experiments.framework.composite import ParallelExperiment from qiskit_experiments.library import randomized_benchmarking as rb From 20b36db8cb573680c4a9d0ca9900caaaef1989d1 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Fri, 24 Feb 2023 13:15:02 -0500 Subject: [PATCH 21/56] added edge grab docstring --- .../randomized_benchmarking/__init__.py | 8 +- .../randomized_benchmarking/clifford_utils.py | 30 +-- .../mirror_rb_experiment.py | 186 ++++++++++++++++-- .../test_randomized_benchmarking.py | 18 ++ 4 files changed, 210 insertions(+), 32 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index f65657541f..43506b02e5 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -39,14 +39,20 @@ InterleavedRBAnalysis MirrorRBAnalysis +Utilities +========= + .. autosummary:: :toctree: ../stubs/ RBUtils + MirrorRBDistribution + RandomEdgeGrabDistribution + """ from .rb_experiment import StandardRB from .interleaved_rb_experiment import InterleavedRB -from .mirror_rb_experiment import MirrorRB +from .mirror_rb_experiment import MirrorRB, MirrorRBDistribution, RandomEdgeGrabDistribution from .rb_analysis import RBAnalysis from .interleaved_rb_analysis import InterleavedRBAnalysis from .mirror_rb_analysis import MirrorRBAnalysis diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index ed071d2ebb..4b7c1670bf 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -675,19 +675,6 @@ def _layer_indices_from_num(num: Integral) -> Tuple[Integral, Integral, Integral idx0 = num // _NUM_LAYER_1 return idx0, idx1, idx2 - def _unpack_num_multi_sigs(self, num, sigs): - """Returns the result of `_unpack_num` on one of the - signatures in `sigs` - """ - for i, sig in enumerate(sigs): - sig_size = 1 - for k in sig: - sig_size *= k - if num < sig_size: - return [i] + self._unpack_num(num, sig) - num -= sig_size - return None - # Constant mapping from 1Q single Clifford gate to 1Q Clifford numerical identifier. # This table must be generated using `data.generate_clifford_data.gen_cliff_single_1q_gate_map`, or, @@ -974,3 +961,20 @@ def _layer_indices_from_num(num: Integral) -> Tuple[Integral, Integral, Integral idx1 = num % _NUM_LAYER_1 idx0 = num // _NUM_LAYER_1 return idx0, idx1, idx2 + + +def compute_target_bitstring(self, circuit: QuantumCircuit) -> str: + """For a Clifford circuit C, compute C|0>. + Args: + circuit: A Clifford QuantumCircuit + Returns: + Target bit string + """ + + # convert circuit to Boolean phase vector of stabilizer table + phase_vector = Clifford(circuit).table.phase + n = circuit.num_qubits + + # target string has a 1 for each True in the stabilizer half of the phase vector + target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) + return target diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index e79cae5218..a0949740f4 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -12,9 +12,12 @@ """ Mirror RB Experiment class. """ +import warnings from abc import ABC, abstractmethod from typing import Union, Iterable, Optional, List, Sequence from itertools import permutations +from numbers import Integral + from numpy.random import Generator, BitGenerator, SeedSequence, default_rng from qiskit import QuantumCircuit, QiskitError @@ -22,12 +25,15 @@ from qiskit.quantum_info import Clifford, random_pauli, random_clifford from qiskit.quantum_info.operators import Pauli from qiskit.providers.backend import Backend +from qiskit.providers.options import Options from qiskit.transpiler.basepasses import TransformationPass from .rb_experiment import StandardRB from .mirror_rb_analysis import MirrorRBAnalysis from .clifford_utils import CliffordUtils +SequenceElementType = Union[Clifford, Integral, QuantumCircuit] + class MirrorRBDistribution(ABC): """Sampling distribution for the mirror randomized benchmarking experiment.""" @@ -41,24 +47,104 @@ def __call__(self, qubits, two_qubit_density, coupling_map, **params): class RandomEdgeGrabDistribution(MirrorRBDistribution): - def __init__(self): + """The edge grab algorithm for sampling one- and two-qubit layers. + + # section: overview + + + + # section: reference + .. ref_arxiv:: 1 2008.11294 + + """ + + def __init__(self, seed=None): super().__init__(seed) - def __call__(self, qubits, two_qubit_density, coupling_map, seed=None): - self.two_qubit_density = two_qubit_density - self.coupling_map = coupling_map + def __call__(self, qubits, two_qubit_gate_density, coupling_map, length, seed=None): + """Sample layers using the ege grab algorithm. - ... + Args: + qubits: The number of qubits in the circuit. + two_qubit_gate_density: :math:`1/2` times the expected fraction + of qubits with CX gates. + coupling_map: List of pairs of connected edges between qubits. + length: The length of the sequence to output. + seed: Seed for random generation. + Raises: + Warning: If device has no connectivity or two_qubit_gate_density is too high + + Returns: + List of QuantumCircuits -class DiscreteLayerDistribution(MirrorRBDistribution): - def __init__(self): - super().__init__(qubits, seed) + """ + self.two_qubit_density = two_qubit_gate_density + self.coupling_map = coupling_map - def __call__(self, qubits, layers, probs=None, seed=None): - self.layers = list(layers) - self.probs = probs or [1 / len(layers)] * len(layers) - return rng.choice(self.layers, self.prob) + num_qubits = len(qubits) + + if num_qubits == 1: + return rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) + + if rng is None: + rng = default_rng(seed=seed) + + if isinstance(rng, int): + rng = default_rng(rng) + + qc_list = [] + for _ in list(range(size)): + all_edges = coupling_map[:] # make copy of coupling map from which we pop edges + selected_edges = [] + while all_edges: + rand_edge = all_edges.pop(rng.integers(len(all_edges))) + selected_edges.append( + rand_edge + ) # move random edge from all_edges to selected_edges + old_all_edges = all_edges[:] + all_edges = [] + # only keep edges in all_edges that do not share a vertex with rand_edge + for edge in old_all_edges: + if rand_edge[0] not in edge and rand_edge[1] not in edge: + all_edges.append(edge) + + qr = QuantumRegister(num_qubits) + qc = QuantumCircuit(qr) + two_qubit_prob = 0 + try: + two_qubit_prob = num_qubits * two_qubit_gate_density / len(selected_edges) + except ZeroDivisionError: + warnings.warn( + "Device has no connectivity. All cliffords will be single-qubit Cliffords" + ) + if two_qubit_prob > 1: + warnings.warn( + "Mean number of two-qubit gates is higher than number of selected edges for CNOTs. " + + "Actual density of two-qubit gates will likely be lower than input density" + ) + selected_edges_logical = [ + [np.where(q == np.asarray(qubits))[0][0] for q in edge] for edge in selected_edges + ] + # selected_edges_logical is selected_edges with logical qubit labels rather than physical + # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] + # ==> selected_edges_logical = [[1,0],[4,2]] + put_1_qubit_clifford = np.arange(num_qubits) + # put_1_qubit_clifford is a list of qubits that aren't assigned to a 2-qubit Clifford + # 1-qubit Clifford will be assigned to these edges + for edge in selected_edges_logical: + if rng.random() < two_qubit_prob: + # with probability two_qubit_prob, place CNOT on edge in selected_edges + qc.cx(edge[0], edge[1]) + # remove these qubits from put_1_qubit_clifford + put_1_qubit_clifford = np.setdiff1d(put_1_qubit_clifford, edge) + for q in put_1_qubit_clifford: + clifford1q = self.clifford_1_qubit_circuit(rng.integers(24)) + insts = [datum[0] for datum in clifford1q.data] + for inst in insts: + qc.compose(inst, [q], inplace=True) + qc_list.append(qc) + return qc_list class MirrorRB(StandardRB): @@ -66,8 +152,7 @@ class MirrorRB(StandardRB): # section: overview Mirror Randomized Benchmarking (RB) is a method to estimate the average - error-rate of quantum gates that is more scalable than other RB methods - and can thus detect crosstalk errors. + error-rate of quantum gates that is more scalable than the standard RB methods. A mirror RB experiment generates circuits of layers of Cliffords interleaved with layers of Pauli gates and capped at the start and end by a layer of @@ -92,8 +177,9 @@ class MirrorRB(StandardRB): def __init__( self, - qubits: Sequence[int], + physical_qubits: Sequence[int], lengths: Iterable[int], + distribution: MirrorRBDistribution, local_clifford: bool = True, pauli_randomize: bool = True, two_qubit_gate_density: float = 0.2, @@ -106,8 +192,9 @@ def __init__( """Initialize a mirror randomized benchmarking experiment. Args: - qubits: A list of physical qubits for the experiment. + physical_qubits: A list of physical qubits for the experiment. lengths: A list of RB sequences lengths. + distribution: The probability distribution over the layer set to sample. local_clifford: If True, begin the circuit with uniformly random 1-qubit Cliffords and end the circuit with their inverses. pauli_randomize: If True, surround each inner Clifford layer with @@ -140,7 +227,7 @@ def __init__( raise QiskitError("Two-qubit gate density must be non-negative") super().__init__( - qubits, + physical_qubits, lengths, backend=backend, num_samples=num_samples, @@ -152,9 +239,9 @@ def __init__( self._pauli_randomize = pauli_randomize self._two_qubit_gate_density = two_qubit_gate_density - # Will need to update these 2 lines below to fit with current rb experiment code self._full_sampling = full_sampling self._clifford_utils = CliffordUtils() + self._distribution = distribution # By default, the inverting Pauli layer at the end of the circuit is not added self._inverting_pauli_layer = inverting_pauli_layer @@ -162,6 +249,69 @@ def __init__( # Set analysis options self.analysis = MirrorRBAnalysis() + @classmethod + def _default_experiment_options(cls) -> Options: + """Default experiment options. + + Experiment Options: + lengths (List[int]): A list of RB sequences lengths. + num_samples (int): Number of samples to generate for each sequence length. + seed (None or int or SeedSequence or BitGenerator or Generator): A seed + used to initialize ``numpy.random.default_rng`` when generating circuits. + The ``default_rng`` will be initialized with this seed value everytime + :meth:`circuits` is called. + """ + options = super()._default_experiment_options() + options.update_options( + distribution=None, + num_samples=None, + seed=None, + full_sampling=None, + ) + + return options + + def circuits(self) -> List[QuantumCircuit]: + """Return a list of Mirror RB circuits. + + Returns: + A list of :class:`QuantumCircuit`. + """ + sequences = self._sample_sequences() + circuits = self._sequences_to_circuits(sequences) + + for circ, seq in zip(circuits, sequences): + circ.metadata = { + "experiment_type": self._type, + "xval": len(seq), + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "target": self._clifford_utils.compute_target_bitstring(circ), + "inverting_pauli_layer": self._inverting_pauli_layer, + } + return circuits + + def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: + """Sample mirror RB sequences using the provided distribution. + + Returns: + A list of mirror RB sequences. + """ + + rng = default_rng(seed=self.experiment_options.seed) + sequences = [] + if self.experiment_options.full_sampling: + for _ in range(self.experiment_options.num_samples): + for length in self.experiment_options.lengths: + sequences.append(self._distribution(length, rng)) + else: + for _ in range(self.experiment_options.num_samples): + longest_seq = self.__sample_sequence(max(self.experiment_options.lengths), rng) + for length in self.experiment_options.lengths: + sequences.append(longest_seq[:length]) + + return sequences + def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: """Sample Mirror RB circuits. diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index aefc04d46e..2e446cb05b 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -546,6 +546,24 @@ def test_single_qubit(self): epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + def test_custom_distribution(self): + """Test providing a custom distribution.""" + qubits = ( + 0, + 1, + 2, + ) + exp = rb.MirrorRB( + physical_qubits=qubits, + distribution=rb.RandomEdgeGrabDistribution, + two_qubit_gate_density=0.5, + lengths=list(range(2, 300, 20)), + seed=124, + backend=self.backend, + num_samples=30, + ) + # test that feeding the circuit from edge grab into discrete yields the same answer(?) + def test_two_qubit(self): """Test two qubit RB. Use default basis gates.""" exp = rb.StandardRB( From c8c8a7b28f142d1c319136ad4dab4b829b22f571 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Sat, 25 Feb 2023 10:45:21 -0500 Subject: [PATCH 22/56] moved sampler to its own file --- .../mirror_rb_experiment.py | 158 ++------------- .../randomized_benchmarking/sampling_utils.py | 181 ++++++++++++++++++ 2 files changed, 201 insertions(+), 138 deletions(-) create mode 100644 qiskit_experiments/library/randomized_benchmarking/sampling_utils.py diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index a0949740f4..261b4fdaef 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -13,15 +13,14 @@ Mirror RB Experiment class. """ import warnings -from abc import ABC, abstractmethod from typing import Union, Iterable, Optional, List, Sequence from itertools import permutations -from numbers import Integral + from numpy.random import Generator, BitGenerator, SeedSequence, default_rng -from qiskit import QuantumCircuit, QiskitError -from qiskit.circuit import Instruction +from qiskit.exceptions import QiskitError +from qiskit.circuit import QuantumCircuit, QuantumRegister, Instruction from qiskit.quantum_info import Clifford, random_pauli, random_clifford from qiskit.quantum_info.operators import Pauli from qiskit.providers.backend import Backend @@ -31,122 +30,11 @@ from .rb_experiment import StandardRB from .mirror_rb_analysis import MirrorRBAnalysis from .clifford_utils import CliffordUtils +from .sampling_utils import MirrorRBSampler, EdgeGrabSampler SequenceElementType = Union[Clifford, Integral, QuantumCircuit] -class MirrorRBDistribution(ABC): - """Sampling distribution for the mirror randomized benchmarking experiment.""" - - def __init__(self, seed=None): - self.rng = default_rng(seed) - - @abstractmethod - def __call__(self, qubits, two_qubit_density, coupling_map, **params): - self.qubits = qubits - - -class RandomEdgeGrabDistribution(MirrorRBDistribution): - """The edge grab algorithm for sampling one- and two-qubit layers. - - # section: overview - - - - # section: reference - .. ref_arxiv:: 1 2008.11294 - - """ - - def __init__(self, seed=None): - super().__init__(seed) - - def __call__(self, qubits, two_qubit_gate_density, coupling_map, length, seed=None): - """Sample layers using the ege grab algorithm. - - Args: - qubits: The number of qubits in the circuit. - two_qubit_gate_density: :math:`1/2` times the expected fraction - of qubits with CX gates. - coupling_map: List of pairs of connected edges between qubits. - length: The length of the sequence to output. - seed: Seed for random generation. - - Raises: - Warning: If device has no connectivity or two_qubit_gate_density is too high - - Returns: - List of QuantumCircuits - - """ - self.two_qubit_density = two_qubit_gate_density - self.coupling_map = coupling_map - - num_qubits = len(qubits) - - if num_qubits == 1: - return rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) - - if rng is None: - rng = default_rng(seed=seed) - - if isinstance(rng, int): - rng = default_rng(rng) - - qc_list = [] - for _ in list(range(size)): - all_edges = coupling_map[:] # make copy of coupling map from which we pop edges - selected_edges = [] - while all_edges: - rand_edge = all_edges.pop(rng.integers(len(all_edges))) - selected_edges.append( - rand_edge - ) # move random edge from all_edges to selected_edges - old_all_edges = all_edges[:] - all_edges = [] - # only keep edges in all_edges that do not share a vertex with rand_edge - for edge in old_all_edges: - if rand_edge[0] not in edge and rand_edge[1] not in edge: - all_edges.append(edge) - - qr = QuantumRegister(num_qubits) - qc = QuantumCircuit(qr) - two_qubit_prob = 0 - try: - two_qubit_prob = num_qubits * two_qubit_gate_density / len(selected_edges) - except ZeroDivisionError: - warnings.warn( - "Device has no connectivity. All cliffords will be single-qubit Cliffords" - ) - if two_qubit_prob > 1: - warnings.warn( - "Mean number of two-qubit gates is higher than number of selected edges for CNOTs. " - + "Actual density of two-qubit gates will likely be lower than input density" - ) - selected_edges_logical = [ - [np.where(q == np.asarray(qubits))[0][0] for q in edge] for edge in selected_edges - ] - # selected_edges_logical is selected_edges with logical qubit labels rather than physical - # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] - # ==> selected_edges_logical = [[1,0],[4,2]] - put_1_qubit_clifford = np.arange(num_qubits) - # put_1_qubit_clifford is a list of qubits that aren't assigned to a 2-qubit Clifford - # 1-qubit Clifford will be assigned to these edges - for edge in selected_edges_logical: - if rng.random() < two_qubit_prob: - # with probability two_qubit_prob, place CNOT on edge in selected_edges - qc.cx(edge[0], edge[1]) - # remove these qubits from put_1_qubit_clifford - put_1_qubit_clifford = np.setdiff1d(put_1_qubit_clifford, edge) - for q in put_1_qubit_clifford: - clifford1q = self.clifford_1_qubit_circuit(rng.integers(24)) - insts = [datum[0] for datum in clifford1q.data] - for inst in insts: - qc.compose(inst, [q], inplace=True) - qc_list.append(qc) - return qc_list - - class MirrorRB(StandardRB): """Mirror randomized benchmarking experiment. @@ -179,7 +67,7 @@ def __init__( self, physical_qubits: Sequence[int], lengths: Iterable[int], - distribution: MirrorRBDistribution, + distribution: MirrorRBSampler = EdgeGrabSampler, local_clifford: bool = True, pauli_randomize: bool = True, two_qubit_gate_density: float = 0.2, @@ -246,7 +134,8 @@ def __init__( # By default, the inverting Pauli layer at the end of the circuit is not added self._inverting_pauli_layer = inverting_pauli_layer - # Set analysis options + self.set_experiment_options(distribution=distribution, local_clifford=local_clifford) + self.analysis = MirrorRBAnalysis() @classmethod @@ -254,6 +143,7 @@ def _default_experiment_options(cls) -> Options: """Default experiment options. Experiment Options: + pauli_randomize lengths (List[int]): A list of RB sequences lengths. num_samples (int): Number of samples to generate for each sequence length. seed (None or int or SeedSequence or BitGenerator or Generator): A seed @@ -263,6 +153,7 @@ def _default_experiment_options(cls) -> Options: """ options = super()._default_experiment_options() options.update_options( + pauli_randomize=True, distribution=None, num_samples=None, seed=None, @@ -294,9 +185,20 @@ def circuits(self) -> List[QuantumCircuit]: def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: """Sample mirror RB sequences using the provided distribution. + Steps: + 1. Sample length/2 layers of random Cliffords + 2. Compute inverse of each layer in the first half of the circuit and append to circuit + 3. Sample the random paulis and interleave them between the Clifford layers + 4. Sample the 1-qubit local Clifford and add them to the beginning and end of the circuit + + Raises: + QiskitError: if backend without a coupling map is provided + Returns: A list of mirror RB sequences. """ + if not self._backend: + raise QiskitError("A backend must be provided.") rng = default_rng(seed=self.experiment_options.seed) sequences = [] @@ -313,28 +215,8 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: return sequences def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: - """Sample Mirror RB circuits. - - Steps: - 1. Sample length/2 layers of random Cliffords - 2. Compute inverse of each layer in the first half of the circuit and append to circuit - 3. Sample the random paulis and interleave them between the Clifford layers - 4. Sample the 1-qubit local Clifford and add them to the beginning and end of the circuit - - Args: - lengths: List of lengths to run Mirror RB - rng: Generator seed - - Returns: - List of QuantumCircuits - - Raises: - QiskitError: if backend without a coupling map is provided - """ # Backend must have a coupling map - if not self._backend: - raise QiskitError("Must provide a backend") circuits = [] lengths_half = [length // 2 for length in lengths] diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py new file mode 100644 index 0000000000..55a911af74 --- /dev/null +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -0,0 +1,181 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2023. +# +# 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. +""" +Utilities for sampling layers in randomized benchmarking experiments +""" + +import warnings +from abc import ABC, abstractmethod +from typing import Optional, Union, Sequence, List, Tuple +from numbers import Integral + +import numpy as np +from numpy.random import Generator, default_rng +from qiskit import QuantumCircuit, QuantumRegister +from qiskit.exceptions import QiskitError +from qiskit.circuit import Gate +from qiskit.circuit.library import ( + IGate, + XGate, + YGate, + ZGate, + CXGate, + CYGate, + SGate, + SdgGate, + SXGate, + SXdgGate, +) +from qiskit.quantum_info import random_unitary, random_clifford, Pauli +from qiskit.extensions import UnitaryGate +from qiskit.converters import circuit_to_dag +from .clifford_utils import CliffordUtils + +# SequenceElementType = Union[Clifford, Integral, QuantumCircuit] + + +class MirrorRBSampler(ABC): + """Sampling distribution for the mirror randomized benchmarking experiment.""" + + def __init__(self): + pass + + @abstractmethod + def __call__(self, num_qubits, seed=None, **params): + self.num_qubits = num_qubits + + +class EdgeGrabSampler(MirrorRBSampler): + r"""The edge grab algorithm for sampling one- and two-qubit layers. + + # section: overview + + The edge grab sampler, given a list of :math:`w` qubits, their connectivity + graph, and the desired two-qubit gate density :math:`\xi`, outputs a layer + as follows: + + 1. Begin with the empty set :math:`E` and :math:`E_r`, the set of all + edges in the connectivity graph. Select an edge from :math:`E_r` at random + and add it to :math:`E`, removing all edges that share a qubit with the edge + from :math:`E_r`. + 2. Select edges from :math:`E` with the probability :math:`w\xi/|E|`. These edges will + have two-qubit gates in the output layer. + + This produces a layer with an expected two-qubit gate density :math:`2\xi`. + Accounting for all the layers in mirror RB, this means the overall two-qubit gate + density will be :math:`\xi`. The overall average density will converge to + :math:`\xi` as the circuit size increases. + + # section: reference + .. ref_arxiv:: 1 2008.11294 + + """ + + def __call__( + self, + num_qubits, + two_qubit_gate_density, + coupling_map, + length, + one_qubit_gate_set: Optional[Union[str, List]] = "clifford", + two_qubit_gate_set: Optional[List] = ["cx"], + seed=None, + ): + """Sample layers using the ege grab algorithm. + + Args: + num_qubits: The number of qubits to generate layers for. + one_qubit_gate_set: The one qubit gate set to sample from. Can be either a list + of gates or "clifford". + two_qubit_gate_set: The two qubit gate set to sample from. Can be either a + list of gates or one of "cx", "cy", "cz", or "csx". + two_qubit_gate_density: the expected fraction of two-qubit gates in the + sampled layer. + coupling_map: List of pairs of connected edges between qubits. + length: The length of the sequence to output. + seed: Seed for random generation. + + Raises: + Warning: If device has no connectivity or two_qubit_gate_density is too high + TypeError: If invalid gate set(s) are specified. + + Returns: + List of sampled QuantumCircuits. + + """ + if isinstance(one_qubit_gate_set, list) or not ( + one_qubit_gate_set.casefold() in ["clifford"] + ): + raise TypeError("one_qubit_gate_set must be a list of gates or 'clifford'.") + + self.two_qubit_density = two_qubit_gate_density + self.coupling_map = coupling_map + + rng = default_rng(seed=seed) + + qc_list = [] + for _ in list(range(length)): + all_edges = coupling_map[:] # make copy of coupling map from which we pop edges + selected_edges = [] + while all_edges: + rand_edge = all_edges.pop(rng.integers(len(all_edges))) + selected_edges.append( + rand_edge + ) # move random edge from all_edges to selected_edges + old_all_edges = all_edges[:] + all_edges = [] + # only keep edges in all_edges that do not share a vertex with rand_edge + for edge in old_all_edges: + if rand_edge[0] not in edge and rand_edge[1] not in edge: + all_edges.append(edge) + + qr = QuantumRegister(num_qubits) + qc = QuantumCircuit(qr) + two_qubit_prob = 0 + try: + two_qubit_prob = num_qubits * two_qubit_gate_density / len(selected_edges) + except ZeroDivisionError: + warnings.warn("Device has no connectivity. All gates will be single-qubit.") + if two_qubit_prob > 1: + warnings.warn( + "Mean number of two-qubit gates is higher than the number of selected edges. " + + "Actual density of two-qubit gates will likely be lower than input density." + ) + selected_edges_logical = [ + [np.where(q == np.asarray(num_qubits))[0][0] for q in edge] + for edge in selected_edges + ] + + # selected_edges_logical is selected_edges with logical qubit labels rather than physical + # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] + # ==> selected_edges_logical = [[1,0],[4,2]] + put_1_qubit_gates = np.arange(num_qubits) + # put_1_qubit_gates is a list of qubits that aren't assigned to a 2-qubit gate + # 1-qubit gates will be assigned to these edges + for edge in selected_edges_logical: + if rng.random() < two_qubit_prob: + # with probability two_qubit_prob, place a two-qubit gate from the + # gate set on edge in selected_edges + try: + getattr(qc, rng.choice(two_qubit_gate_set))(edge[0], edge[1]) + except AttributeError: + raise QiskitError("Invalid two-qubit gate set specified.") + # remove these qubits from put_1_qubit_gates + put_1_qubit_gates = np.setdiff1d(put_1_qubit_gates, edge) + for q in put_1_qubit_gates: + if one_qubit_gate_set == "clifford": + clifford1q = random_clifford(self.num_qubits, rng).to_circuit() + insts = [datum[0] for datum in clifford1q.data] + for inst in insts: + qc.compose(inst, [q], inplace=True) + qc_list.append(qc) + return qc_list From ea53a5dabb3fbafad043646dee56278f93bff87b Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 28 Feb 2023 07:50:30 -0500 Subject: [PATCH 23/56] updated edgegrab --- .../randomized_benchmarking/__init__.py | 3 +- .../mirror_rb_experiment.py | 60 +++++++++++++++++-- .../randomized_benchmarking/sampling_utils.py | 16 +++-- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index 43506b02e5..fc927bfb38 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -52,7 +52,8 @@ """ from .rb_experiment import StandardRB from .interleaved_rb_experiment import InterleavedRB -from .mirror_rb_experiment import MirrorRB, MirrorRBDistribution, RandomEdgeGrabDistribution +from .mirror_rb_experiment import MirrorRB +from .sampling_utils import MirrorRBSampler, EdgeGrabSampler from .rb_analysis import RBAnalysis from .interleaved_rb_analysis import InterleavedRBAnalysis from .mirror_rb_analysis import MirrorRBAnalysis diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 261b4fdaef..dd72b486e0 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -12,8 +12,8 @@ """ Mirror RB Experiment class. """ -import warnings from typing import Union, Iterable, Optional, List, Sequence +from numbers import Integral from itertools import permutations @@ -200,24 +200,76 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if not self._backend: raise QiskitError("A backend must be provided.") + # Coupling map is full connectivity by default. If backend has a coupling map, + # get backend coupling map and create coupling map for physical qubits + coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) + if self._backend.configuration().coupling_map: + coupling_map = self._backend.configuration().coupling_map + experiment_coupling_map = [] + for edge in coupling_map: + if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: + experiment_coupling_map.append(edge) + rng = default_rng(seed=self.experiment_options.seed) sequences = [] if self.experiment_options.full_sampling: for _ in range(self.experiment_options.num_samples): for length in self.experiment_options.lengths: - sequences.append(self._distribution(length, rng)) + sequences.append( + self._distribution( + self.num_qubits, self._two_qubit_density, coupling_map, length, rng + ) + ) else: for _ in range(self.experiment_options.num_samples): - longest_seq = self.__sample_sequence(max(self.experiment_options.lengths), rng) + longest_seq = self._distribution( + self.num_qubits, + self._two_qubit_density, + coupling_map, + max(self.experiment_options.lengths), + rng, + ) for length in self.experiment_options.lengths: sequences.append(longest_seq[:length]) return sequences + def _sequences_to_circuits( + self, sequences: List[Sequence[SequenceElementType]] + ) -> List[QuantumCircuit]: + """Convert an RB sequence into circuit and append the inverse to the end. + + Returns: + A list of RB circuits. + """ + basis_gates = self._get_basis_gates() + # Circuit generation + circuits = [] + for i, seq in enumerate(sequences): + if ( + self.experiment_options.full_sampling + or i % len(self.experiment_options.lengths) == 0 + ): + prev_elem, prev_seq = self.__identity_clifford(), [] + + circ = QuantumCircuit(self.num_qubits) + for elem in seq: + circ.append(self._to_instruction(elem, basis_gates), circ.qubits) + circ.append(Barrier(self.num_qubits), circ.qubits) + + # Compute inverse, compute only the difference from the previous shorter sequence + prev_elem = self.__compose_clifford_seq(prev_elem, seq[len(prev_seq) :]) + prev_seq = seq + inv = self.__adjoint_clifford(prev_elem) + + circ.append(self._to_instruction(inv, basis_gates), circ.qubits) + circ.measure_all() # includes insertion of the barrier before measurement + circuits.append(circ) + return circuits + def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: # Backend must have a coupling map - circuits = [] lengths_half = [length // 2 for length in lengths] diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 55a911af74..38797a7fe5 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -90,7 +90,7 @@ def __call__( two_qubit_gate_set: Optional[List] = ["cx"], seed=None, ): - """Sample layers using the ege grab algorithm. + """Sample layers using the edge grab algorithm. Args: num_qubits: The number of qubits to generate layers for. @@ -109,7 +109,7 @@ def __call__( TypeError: If invalid gate set(s) are specified. Returns: - List of sampled QuantumCircuits. + List of sampled QuantumCircuit layers with length ``length``. """ if isinstance(one_qubit_gate_set, list) or not ( @@ -150,10 +150,6 @@ def __call__( "Mean number of two-qubit gates is higher than the number of selected edges. " + "Actual density of two-qubit gates will likely be lower than input density." ) - selected_edges_logical = [ - [np.where(q == np.asarray(num_qubits))[0][0] for q in edge] - for edge in selected_edges - ] # selected_edges_logical is selected_edges with logical qubit labels rather than physical # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] @@ -161,7 +157,7 @@ def __call__( put_1_qubit_gates = np.arange(num_qubits) # put_1_qubit_gates is a list of qubits that aren't assigned to a 2-qubit gate # 1-qubit gates will be assigned to these edges - for edge in selected_edges_logical: + for edge in selected_edges: if rng.random() < two_qubit_prob: # with probability two_qubit_prob, place a two-qubit gate from the # gate set on edge in selected_edges @@ -173,8 +169,10 @@ def __call__( put_1_qubit_gates = np.setdiff1d(put_1_qubit_gates, edge) for q in put_1_qubit_gates: if one_qubit_gate_set == "clifford": - clifford1q = random_clifford(self.num_qubits, rng).to_circuit() - insts = [datum[0] for datum in clifford1q.data] + gates_1q = random_clifford(1, rng).to_circuit() + else: + gates_1q = rng.choice(one_qubit_gate_set).to_circuit() + insts = [datum[0] for datum in gates_1q.data] for inst in insts: qc.compose(inst, [q], inplace=True) qc_list.append(qc) From 07b4b2866c541132a9f33a08108eac133bb78153 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 28 Feb 2023 07:50:43 -0500 Subject: [PATCH 24/56] coupling map --- .../mirror_rb_experiment.py | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index dd72b486e0..0732f19f7e 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -202,11 +202,11 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Coupling map is full connectivity by default. If backend has a coupling map, # get backend coupling map and create coupling map for physical qubits - coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) + self.coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) if self._backend.configuration().coupling_map: - coupling_map = self._backend.configuration().coupling_map + self.coupling_map = self._backend.configuration().coupling_map experiment_coupling_map = [] - for edge in coupling_map: + for edge in self.coupling_map: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append(edge) @@ -217,7 +217,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: for length in self.experiment_options.lengths: sequences.append( self._distribution( - self.num_qubits, self._two_qubit_density, coupling_map, length, rng + self.num_qubits, self._two_qubit_density, self.coupling_map, length, rng ) ) else: @@ -225,7 +225,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: longest_seq = self._distribution( self.num_qubits, self._two_qubit_density, - coupling_map, + self.coupling_map, max(self.experiment_options.lengths), rng, ) @@ -273,16 +273,6 @@ def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: circuits = [] lengths_half = [length // 2 for length in lengths] - # Coupling map is full connectivity by default. If backend has a coupling map, - # get backend coupling map and create coupling map for physical qubits - coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) - if self._backend.configuration().coupling_map: - coupling_map = self._backend.configuration().coupling_map - experiment_coupling_map = [] - for edge in coupling_map: - if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: - experiment_coupling_map.append(edge) - for length in lengths_half if self._full_sampling else [lengths_half[-1]]: # Sample Clifford layer elements for first half of mirror circuit elements = self._clifford_utils.random_edgegrab_clifford_circuits( From 31f565e53bfec3164ed96b1dab753184168abcdb Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Wed, 1 Mar 2023 21:58:01 -0500 Subject: [PATCH 25/56] updated release note --- .../0.4/randomized_benchmarking-de55fda43765c34c.yaml | 7 ------- releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml diff --git a/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml b/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml index 06295a358e..2942065e4b 100644 --- a/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml +++ b/releasenotes/notes/0.4/randomized_benchmarking-de55fda43765c34c.yaml @@ -1,11 +1,4 @@ --- -features: - - | - A new experiment class :class:`qiskit_experiments.library.MirrorRB` is - introduced. This class implements mirror randomized benchmarking (RB), a version - of RB that uses mirror circuits. It is more scalable than other RB protocols and - can consequently be used to detect crosstalk errors. - fixes: - | Initial guess function for the randomized benchmarking analysis :func:`.rb_decay` has been diff --git a/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml new file mode 100644 index 0000000000..bf6f4ad6f7 --- /dev/null +++ b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + A new experiment class :class:`.MirrorRB` is + introduced. This class implements mirror randomized benchmarking, a version + of RB that uses mirror circuits. It is more scalable than other RB protocols and + can consequently be used to detect crosstalk errors. From 41f9e81df7d864dd82b11a1d16c4dad0fd939f04 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Sat, 11 Mar 2023 11:18:19 -0500 Subject: [PATCH 26/56] partial refactoring --- .../mirror_randomized_benchmarking.rst | 228 ++++++++++++++++++ docs/tutorials/randomized_benchmarking.rst | 210 ---------------- .../randomized_benchmarking/__init__.py | 4 +- .../mirror_rb_experiment.py | 189 +++++++-------- .../randomized_benchmarking/sampling_utils.py | 30 ++- 5 files changed, 336 insertions(+), 325 deletions(-) create mode 100644 docs/tutorials/mirror_randomized_benchmarking.rst diff --git a/docs/tutorials/mirror_randomized_benchmarking.rst b/docs/tutorials/mirror_randomized_benchmarking.rst new file mode 100644 index 0000000000..dda59919be --- /dev/null +++ b/docs/tutorials/mirror_randomized_benchmarking.rst @@ -0,0 +1,228 @@ +Mirror Randomized Benchmarking +============================== + +Mirror randomized benchmarking (mirror RB) is a randomized benchmarking protocol +that is more scalable than standard randomized benchmarking and is suitable for +characterizing crosstalk errors over a large number of qubits in a quantum device. A +randomized Clifford mirror circuit [1]_ consists of: + +- random layers of one- and two-qubit Cliffords and their inverses sampled + according to some distribution :math:`\Omega` over a layer set + :math:`\mathbb{L}`, + +- uniformly random one-qubit Paulis between these layers, and + +- a layer of uniformly random one-qubit Cliffords at the beginning and the end + of the circuit. + +Because the Clifford gates are only one- and two-qubit, unlike in standard RB, which +requires the implementation of n-qubit Cliffords, mirror RB ????. Mirror RB can also be +generalized to universal gatesets beyond the Cliffords [2]_. + +Running a Mirror RB experiment +------------------------------ + +Even though a `MirrorRB` experiment can be instantiated without a backend, the +backend must be specified when the circuits are sampled because :math:`\Omega` +depends on the backend's connectivity. + +In standard and interleaved RB, $n$-qubit circuits of varying lengths +:math:`\ell` that compose to the identity are run on a device, and the +**success probability** $P$, the probability that the circuit's output bit +string equals the input bit string, is estimated for each circuit length by +running several circuits at each length. The :math:`P`-versus-:math:`\ell` +curve is fit to the function :math:`A\alpha^\ell + b`, and the error per +Clifford (EPC) (the average infidelity) is estimated using + +.. math:: + + r = \frac{\left(2^n - 1\right)p}{2^n}. + +Our implementation of MRB computes additional values in addition to the +success probability that have been seen in the literature and ``pyGSTi``. +Specifically, we compute the **adjusted success probability** + +.. math:: + + P_0 = \sum_{k=0}^n \left(-\frac{1}{2}\right)^k h_k, + +where :math:`h_k` is the probability of the actual output bit string being +Hamming distance :math:`k` away from the expected output bit string (note +:math:`h_0 = P`). We also compute the **effective polarization** + +.. math:: + + S = \frac{4^n P_0}{4^n - 1} - \frac{1}{4^n - 1}. + +In [1]_, the function :math:`A\alpha^\ell` (without a baseline) is fit to the +effective polarizations to find entanglement infidelities. + +In Qiskit Experiments, mirror RB analysis results include the following: + +- ``alpha``: the depolarizing parameter. The user can select which of :math:`P, P_0, S` + to fit, and the corresponding :math:`\alpha` will be provided. + +- ``EPC``: the expectation of the average gate infidelity of a layer sampled + according to :math:`\Omega`. + +- ``EI``: the expectation of the entanglement infidelity of a layer sampled + according to :math:`\Omega`. + +Note that the ``EPC`` :math:`\epsilon_a` and the ``EI`` :math:`\epsilon_e` are +related by + +.. math:: + + \epsilon_e = \left(1 + \frac{1}{2^n}\right) \epsilon_a, + +where :math:`n` is the number of qubits (see Ref. [7]). + + +Running a one-qubit mirror RB experiment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. jupyter-execute:: + + lengths = np.arange(2, 810, 200) + num_samples = 30 + seed = 1010 + qubits = (0,) + + # Run a MRB experiment on qubit 0 + exp_1q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) + expdata_1q = exp_1q.run(backend).block_for_results() + results_1q = expdata_1q.analysis_results() + +.. jupyter-execute:: + + # View result data + print("Gate error ratio: %s" % expdata_1q.experiment.analysis.options.gate_error_ratio) + display(expdata_1q.figure(0)) + for result in results_1q: + print(result) + + +Running a two-qubit mirror RB experiment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In MRB experiments with :math:`n > 1` qubits, intermediate Clifford layers +are sampled according to the **edge grab** algorithm [3]_. The Clifford layers +in :math:`\mathbb{L}` are constructed from a gate set consisting of +one-qubit Clifford gates and a single two-qubit Clifford gate (e.g., +CX) that can be applied to any two connected qubits. The user can specify +an expected two-qubit gate density +:math:`\xi \in \left[0, \frac{1}{2}\right]`, and each intermediate Clifford +layer will have approximately :math:`n \xi` CXs on average. + +.. jupyter-execute:: + + # Two-qubit circuit example + exp_2q_circ = MirrorRB((0,1), lengths=[4], backend=backend, num_samples=1, seed=1010, two_qubit_gate_density=.4) + qc2 = exp_2q_circ.circuits()[0].decompose()#gates_to_decompose=['Clifford*','circuit*']) + qc2.draw() + +.. jupyter-execute:: + + lengths = np.arange(2, 810, 200) + num_samples = 30 + seed = 1011 + qubits = (0,1) + + # Run a MRB experiment on qubits 0, 1 + exp_2q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) + expdata_2q = exp_2q.run(backend).block_for_results() + results_2q = expdata_2q.analysis_results() + +.. jupyter-execute:: + + # View result data + print("Gate error ratio: %s" % expdata_2q.experiment.analysis.options.gate_error_ratio) + display(expdata_2q.figure(0)) + for result in results_2q: + print(result) + + +Selecting :math:`y`-axis values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. jupyter-execute:: + + lengths = [2, 52, 102, 152] + num_samples = 30 + seed = 42 + qubits = (0,) + + exp = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) + # select y-axis + exp.analysis.set_options(y_axis="Success Probability") # or "Adjusted Success Probability" or "Effective Polarization" + # y-axis label must be set separately + exp.analysis.options.curve_drawer.set_options( + # xlabel="Clifford Length", + ylabel="Success Probability", + ) + expdata = exp.run(backend).block_for_results() + results = expdata.analysis_results() + +.. jupyter-execute:: + + display(expdata.figure(0)) + for result in results: + print(result) + + +Mirror RB user options +~~~~~~~~~~~~~~~~~~~~~~ + +Circuit generation options can be specified when a ``MirrorRB`` experiment +object is instantiated: + +- ``local_clifford`` (default ``True``): if ``True``, begin the circuit with + uniformly random one-qubit Cliffords and end the circuit with their inverses + +- ``pauli_randomize`` (default ``True``): if ``True``, put layers of uniformly + random Paulis between the intermediate Clifford layers + +- ``two_qubit_gate_density`` (default ``0.2``): expected fraction of two-qubit + gates in each intermediate Clifford layer + +- ``inverting_pauli_layer`` (default ``False``): if ``True``, put a layer of + Paulis at the end of the circuit to set the output to + :math:`\left\vert0\right\rangle^{\otimes n}`, up to a global phase + +Let's look at how these options change the circuit: + +## insert draw stuff here + + +Mirror RB implementation in ``pyGSTi`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``pyGSTi`` implementation of Mirror RB can be used for testing and +comparison. We note however that ``pyGSTi`` transpiles circuits slightly +differently, producing small discrepancies in fit parameters between the two +codes. To illustrate, consider the two circuits below, both of which were +generated in ``pyGSTi``. The first circuit was transpiled in ``pyGSTi``, + +.. image:: pygsti-data-pygsti-transpiled-circ.png + +and the second was transpiled in Qiskit. + +.. image:: pygsti-data-qiskit-transpiled-circ.png + +Note the different implementations of the same Clifford on +qubit 0 in the fifth layer. + +References +---------- + +[1]_ Timothy Proctor, Stefan Seritan, Kenneth Rudinger, Erik Nielsen, Robin +Blume-Kohout, Kevin Young, *Scalable randomized benchmarking of quantum +computers using mirror circuits*, https://arxiv.org/pdf/2112.09853.pdf + +[2]_ Hines, Jordan, et al. *Demonstrating scalable randomized benchmarking of universal gate +sets*, arXiv preprint arXiv:2207.07272 (2022). + +[3]_ Timothy Proctor, Kenneth Rudinger, Kevin Young, Erik Nielsen, and Robin +Blume-Kohout, *Measuring the Capabilities of Quantum Computers*, +https://arxiv.org/pdf/2008.11294.pdf + diff --git a/docs/tutorials/randomized_benchmarking.rst b/docs/tutorials/randomized_benchmarking.rst index f57c1cf610..7ec8bad4f7 100644 --- a/docs/tutorials/randomized_benchmarking.rst +++ b/docs/tutorials/randomized_benchmarking.rst @@ -309,208 +309,6 @@ Running a 2-qubit interleaved RB experiment print(result) -Mirror RB experiment --------------------- - -Mirror RB is a RB protocol that is more scalable to larger numbers of qubits, -and as such, it can be used to detect crosstalk errors in a quantum device. A -randomized Clifford mirror circuit consists of - -- random layers of one- and two-qubit Cliffords and their inverses sampled - according to some distribution :math:`\Omega` over a layer set - :math:`\mathbb{L}`, - -- uniformly random Paulis between these layers, and - -- a layer of uniformly random one-qubit Cliffords at the beginning and the end - of the circuit. - -Even though a `MirrorRB` experiment can be instantiated without a backend, the -backend must be specified when the circuits are sampled because :math:`\Omega` -depends on the backend's connectivity. - -In standard and interleaved RB, $n$-qubit circuits of varying lengths -:math:`\ell` that compose to the identity are run on a device, and the -**success probability** $P$, the probability that the circuit's output bit -string equals the input bit string, is estimated for each circuit length by -running several circuits at each length. The :math:`P`-versus-:math:`\ell` -curve is fit to the function :math:`A\alpha^\ell + b`, and the error per -Clifford (EPC) (the average infidelity) is estimated using - -.. math:: - - r = \frac{\left(2^n - 1\right)p}{2^n}. - -Our implementation of MRB computes additional values in addition to the -success probability that have been seen in the literature and ``pyGSTi``. -Specifically, we compute the **adjusted success probability** - -.. math:: - - P_0 = \sum_{k=0}^n \left(-\frac{1}{2}\right)^k h_k, - -where :math:`h_k` is the probability of the actual output bit string being -Hamming distance :math:`k` away from the expected output bit string (note -:math:`h_0 = P`). We also compute the **effective polarization** - -.. math:: - - S = \frac{4^n P_0}{4^n - 1} - \frac{1}{4^n - 1}. - -In [6], the function :math:`A\alpha^\ell` (without a baseline) is fit to the -effective polarizations to find entanglement infidelities. - -In Qiskit Experiments, mirror RB analysis results include the following: - -- ``alpha``: the depolarizing parameter. The user can select which of :math:`P, P_0, S` - to fit, and the corresponding :math:`\alpha` will be provided. - -- ``EPC``: the expectation of the average gate infidelity of a layer sampled - according to :math:`\Omega`. - -- ``EI``: the expectation of the entanglement infidelity of a layer sampled - according to :math:`\Omega`. - -Note that the ``EPC`` :math:`\epsilon_a` and the ``EI`` :math:`\epsilon_e` are -related by - -.. math:: - - \epsilon_e = \left(1 + \frac{1}{2^n}\right) \epsilon_a, - -where :math:`n` is the number of qubits (see Ref. [7]). - - -Running a one-qubit mirror RB experiment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. jupyter-execute:: - - lengths = np.arange(2, 810, 200) - num_samples = 30 - seed = 1010 - qubits = (0,) - - # Run a MRB experiment on qubit 0 - exp_1q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) - expdata_1q = exp_1q.run(backend).block_for_results() - results_1q = expdata_1q.analysis_results() - -.. jupyter-execute:: - - # View result data - print("Gate error ratio: %s" % expdata_1q.experiment.analysis.options.gate_error_ratio) - display(expdata_1q.figure(0)) - for result in results_1q: - print(result) - - -Running a two-qubit mirror RB experiment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In MRB experiments with :math:`n > 1` qubits, intermediate Clifford layers -are sampled according to the **edge grab** algorithm [7]. The Clifford layers -in :math:`\mathbb{L}` are constructed from a gate set consisting of -one-qubit Clifford gates and a single two-qubit Clifford gate (e.g., -CX) that can be applied to any two connected qubits. The user can specify -an expected two-qubit gate density -:math:`\xi \in \left[0, \frac{1}{2}\right]`, and each intermediate Clifford -layer will have approximately :math:`n \xi` CXs on average. - -.. jupyter-execute:: - - # Two-qubit circuit example - exp_2q_circ = MirrorRB((0,1), lengths=[4], backend=backend, num_samples=1, seed=1010, two_qubit_gate_density=.4) - qc2 = exp_2q_circ.circuits()[0].decompose()#gates_to_decompose=['Clifford*','circuit*']) - qc2.draw() - -.. jupyter-execute:: - - lengths = np.arange(2, 810, 200) - num_samples = 30 - seed = 1011 - qubits = (0,1) - - # Run a MRB experiment on qubits 0, 1 - exp_2q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) - expdata_2q = exp_2q.run(backend).block_for_results() - results_2q = expdata_2q.analysis_results() - -.. jupyter-execute:: - - # View result data - print("Gate error ratio: %s" % expdata_2q.experiment.analysis.options.gate_error_ratio) - display(expdata_2q.figure(0)) - for result in results_2q: - print(result) - - -Selecting :math:`y`-axis values -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. jupyter-execute:: - - lengths = [2, 52, 102, 152] - num_samples = 30 - seed = 42 - qubits = (0,) - - exp = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) - # select y-axis - exp.analysis.set_options(y_axis="Success Probability") # or "Adjusted Success Probability" or "Effective Polarization" - # y-axis label must be set separately - exp.analysis.options.curve_drawer.set_options( - # xlabel="Clifford Length", - ylabel="Success Probability", - ) - expdata = exp.run(backend).block_for_results() - results = expdata.analysis_results() - -.. jupyter-execute:: - - display(expdata.figure(0)) - for result in results: - print(result) - - -Mirror RB user options -~~~~~~~~~~~~~~~~~~~~~~ - -Circuit generation options can be specified when a ``MirrorRB`` experiment -object is instantiated: - -- ``local_clifford`` (default ``True``): if ``True``, begin the circuit with - uniformly random one-qubit Cliffords and end the circuit with their inverses - -- ``pauli_randomize`` (default ``True``): if ``True``, put layers of uniformly - random Paulis between the intermediate Clifford layers - -- ``two_qubit_gate_density`` (default ``0.2``): expected fraction of two-qubit - gates in each intermediate Clifford layer - -- ``inverting_pauli_layer`` (default ``False``): if ``True``, put a layer of - Paulis at the end of the circuit to set the output to - :math:`\left\vert0\right\rangle^{\otimes n}`, up to a global phase - - -Mirror RB implementation in ``pyGSTi`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``pyGSTi`` implementation of Mirror RB can be used for testing and -comparison. We note however that ``pyGSTi`` transpiles circuits slightly -differently, producing small discrepancies in fit parameters between the two -codes. To illustrate, consider the two circuits below, both of which were -generated in ``pyGSTi``. The first circuit was transpiled in ``pyGSTi``, - -.. image:: pygsti-data-pygsti-transpiled-circ.png - -and the second was transpiled in Qiskit. - -.. image:: pygsti-data-qiskit-transpiled-circ.png - -Note the different implementations of the same Clifford on -qubit 0 in the fifth layer. - Running a simultaneous RB experiment ------------------------------------ @@ -576,14 +374,6 @@ A. Ohki, Mark B. Ketchen, and M. Steffen, *Characterization of addressability by simultaneous randomized benchmarking*, https://arxiv.org/pdf/1204.6308 -[6] Timothy Proctor, Stefan Seritan, Kenneth Rudinger, Erik Nielsen, Robin -Blume-Kohout, Kevin Young, *Scalable randomized benchmarking of quantum -computers using mirror circuits*, https://arxiv.org/pdf/2112.09853.pdf - -[7] Timothy Proctor, Kenneth Rudinger, Kevin Young, Erik Nielsen, and Robin -Blume-Kohout, *Measuring the Capabilities of Quantum Computers*, -https://arxiv.org/pdf/2008.11294.pdf - .. jupyter-execute:: import qiskit.tools.jupyter diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index fc927bfb38..af22cf54fc 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -46,8 +46,8 @@ :toctree: ../stubs/ RBUtils - MirrorRBDistribution - RandomEdgeGrabDistribution + MirrorRBSampler + EdgeGrabSampler """ from .rb_experiment import StandardRB diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 0732f19f7e..619e8b35c5 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -20,7 +20,7 @@ from numpy.random import Generator, BitGenerator, SeedSequence, default_rng from qiskit.exceptions import QiskitError -from qiskit.circuit import QuantumCircuit, QuantumRegister, Instruction +from qiskit.circuit import QuantumCircuit, Instruction, Barrier from qiskit.quantum_info import Clifford, random_pauli, random_clifford from qiskit.quantum_info.operators import Pauli from qiskit.providers.backend import Backend @@ -123,16 +123,8 @@ def __init__( full_sampling=full_sampling, ) - self._local_clifford = local_clifford - self._pauli_randomize = pauli_randomize - self._two_qubit_gate_density = two_qubit_gate_density - - self._full_sampling = full_sampling self._clifford_utils = CliffordUtils() - self._distribution = distribution - - # By default, the inverting Pauli layer at the end of the circuit is not added - self._inverting_pauli_layer = inverting_pauli_layer + self._distribution = distribution() self.set_experiment_options(distribution=distribution, local_clifford=local_clifford) @@ -143,7 +135,10 @@ def _default_experiment_options(cls) -> Options: """Default experiment options. Experiment Options: - pauli_randomize + local_clifford (bool): Whether to begin the circuit with uniformly random 1-qubit + Cliffords and end the circuit with their inverses. + pauli_randomize (bool): Whether to surround each inner Clifford layer with + uniformly random Paulis. lengths (List[int]): A list of RB sequences lengths. num_samples (int): Number of samples to generate for each sequence length. seed (None or int or SeedSequence or BitGenerator or Generator): A seed @@ -153,6 +148,7 @@ def _default_experiment_options(cls) -> Options: """ options = super()._default_experiment_options() options.update_options( + local_clifford=True, pauli_randomize=True, distribution=None, num_samples=None, @@ -183,19 +179,18 @@ def circuits(self) -> List[QuantumCircuit]: return circuits def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: - """Sample mirror RB sequences using the provided distribution. - - Steps: - 1. Sample length/2 layers of random Cliffords - 2. Compute inverse of each layer in the first half of the circuit and append to circuit - 3. Sample the random paulis and interleave them between the Clifford layers - 4. Sample the 1-qubit local Clifford and add them to the beginning and end of the circuit + """Sample layers of mirror RB using the provided distribution and user options. + First, layers are sampled using the distribution, then Pauli-dressed if + ``pauli_randomize`` is ``True``. The inverse of the resulting circuit is + appended to the end. If ``local_clifford`` is True, then cliffords are added to + the beginning and end. If ``inverting_pauli_layer`` is ``True``, a Pauli layer + will be appended at the end to set the output bitstring to all zeros. Raises: - QiskitError: if backend without a coupling map is provided + QiskitError: If no backend is provided. Returns: - A list of mirror RB sequences. + A list of mirror RB sequences. Each element is a full circuit layer. """ if not self._backend: raise QiskitError("A backend must be provided.") @@ -210,24 +205,73 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append(edge) - rng = default_rng(seed=self.experiment_options.seed) sequences = [] + + for _ in range(self.experiment_options.num_samples): + for length in self.experiment_options.lengths: + # Sample Clifford layer elements for first half of mirror circuit + elements = self._distribution( + self.num_qubits, + self._two_qubit_gate_density, + self.coupling_map, + length // 2, + seed=self.experiment_options.seed, + ) + + # Append inverses of Clifford elements to second half of circuit + for element in elements[::-1]: + elements.append(element.inverse()) + + # Interleave random Paulis if set by user + if self._pauli_randomize: + elements = self._pauli_dress(elements, rng) + element_lengths = [length * 2 + 1 for length in element_lengths] + + # Add start and end local cliffords if set by user + if self._local_clifford: + elements = self._start_end_cliffords(elements, rng) + + mirror_circuits = self._generate_mirror(elements, element_lengths) + for circuit in mirror_circuits: + # Use "boolean arithmetic" to calculate xval correctly for each circuit + pauli_scale = self._pauli_randomize + 1 + clifford_const = self._local_clifford * 2 + circuit.metadata["xval"] = ( + circuit.metadata["xval"] - self._pauli_randomize - clifford_const + ) // pauli_scale + circuit.metadata["mirror"] = True + circuits += mirror_circuits + + sequences = [] + + # delete below + # Add start and end local cliffords if set by user + if self.experiment_options.local_clifford: + sequences = self._start_end_cliffords(sequences) + + if self.experiment_options.pauli_randomize: + elements = self._pauli_dress(elements) + if self.experiment_options.full_sampling: for _ in range(self.experiment_options.num_samples): for length in self.experiment_options.lengths: sequences.append( self._distribution( - self.num_qubits, self._two_qubit_density, self.coupling_map, length, rng + self.num_qubits, + self._two_qubit_gate_density, + self.coupling_map, + length // 2, + seed=self.experiment_options.seed, ) ) else: for _ in range(self.experiment_options.num_samples): longest_seq = self._distribution( self.num_qubits, - self._two_qubit_density, + self.experiment_options._two_qubit_gate_density, self.coupling_map, - max(self.experiment_options.lengths), - rng, + max(self.experiment_options.lengths // 2), + seed=self.rng, ) for length in self.experiment_options.lengths: sequences.append(longest_seq[:length]) @@ -237,7 +281,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: def _sequences_to_circuits( self, sequences: List[Sequence[SequenceElementType]] ) -> List[QuantumCircuit]: - """Convert an RB sequence into circuit and append the inverse to the end. + """Convert Mirror RB sequences into mirror circuits. Returns: A list of RB circuits. @@ -245,86 +289,27 @@ def _sequences_to_circuits( basis_gates = self._get_basis_gates() # Circuit generation circuits = [] - for i, seq in enumerate(sequences): - if ( - self.experiment_options.full_sampling - or i % len(self.experiment_options.lengths) == 0 - ): - prev_elem, prev_seq = self.__identity_clifford(), [] - + for seq in sequences: circ = QuantumCircuit(self.num_qubits) for elem in seq: circ.append(self._to_instruction(elem, basis_gates), circ.qubits) circ.append(Barrier(self.num_qubits), circ.qubits) - # Compute inverse, compute only the difference from the previous shorter sequence - prev_elem = self.__compose_clifford_seq(prev_elem, seq[len(prev_seq) :]) - prev_seq = seq - inv = self.__adjoint_clifford(prev_elem) - - circ.append(self._to_instruction(inv, basis_gates), circ.qubits) - circ.measure_all() # includes insertion of the barrier before measurement - circuits.append(circ) - return circuits - - def _sample_circuits(self, lengths, rng) -> List[QuantumCircuit]: - - # Backend must have a coupling map - circuits = [] - lengths_half = [length // 2 for length in lengths] - - for length in lengths_half if self._full_sampling else [lengths_half[-1]]: - # Sample Clifford layer elements for first half of mirror circuit - elements = self._clifford_utils.random_edgegrab_clifford_circuits( - self.physical_qubits, - experiment_coupling_map, - self._two_qubit_gate_density, - length, - rng, - ) - - # Append inverses of Clifford elements to second half of circuit - for element in elements[::-1]: - elements.append(element.inverse()) - element_lengths = [len(elements)] if self._full_sampling else lengths - - # Interleave random Paulis if set by user - if self._pauli_randomize: - elements = self._pauli_dress(elements, rng) - element_lengths = [length * 2 + 1 for length in element_lengths] - - # Add start and end local cliffords if set by user - if self._local_clifford: - element_lengths = [length + 2 for length in element_lengths] - elements = self._start_end_cliffords(elements, rng) - mirror_circuits = self._generate_mirror(elements, element_lengths) - for circuit in mirror_circuits: - # Use "boolean arithmetic" to calculate xval correctly for each circuit - pauli_scale = self._pauli_randomize + 1 - clifford_const = self._local_clifford * 2 - circuit.metadata["xval"] = ( - circuit.metadata["xval"] - self._pauli_randomize - clifford_const - ) // pauli_scale - circuit.metadata["mirror"] = True - circuits += mirror_circuits - - # Append inverting Pauli layer at end of circuit if set by user - if self._inverting_pauli_layer: - for circuit in circuits: + if self._inverting_pauli_layer: # Get target bitstring (ideal bitstring outputted by the circuit) - target = circuit.metadata["target"] + target = circ.metadata["target"] # Pauli gates to apply to each qubit to reset each to the state 0. # E.g., if the ideal bitstring is 01001, the Pauli label is IXIIX, # which sets all qubits to 0 (up to a global phase) label = "".join(["X" if char == "1" else "I" for char in target]) - circuit.remove_final_measurements() - circuit.append(Pauli(label), list(range(self._num_qubits))) - circuit.measure_all() + circ.append(Pauli(label), list(range(self._num_qubits))) + circ.measure_all() # includes insertion of the barrier before measurement + circuits.append(circ) return circuits - def _pauli_dress(self, element_list: List, rng: Optional[Union[int, Generator]]) -> List: + def _pauli_dress(self, element_list: List) -> List: """Interleaving layers of random Paulis inside the element list. Args: @@ -335,19 +320,21 @@ def _pauli_dress(self, element_list: List, rng: Optional[Union[int, Generator]]) The new list of elements with the Paulis interleaved. """ # Generate random Pauli - rand_pauli = random_pauli(self._num_qubits, seed=rng).to_instruction() + rand_pauli = random_pauli( + self._num_qubits, seed=self.experiment_options.seed + ).to_instruction() rand_pauli_op = Clifford(rand_pauli) new_element_list = [(rand_pauli, rand_pauli_op)] for element in element_list: new_element_list.append(element) - rand_pauli = random_pauli(self._num_qubits, seed=rng).to_instruction() + rand_pauli = random_pauli( + self._num_qubits, seed=self.experiment_options.seed + ).to_instruction() rand_pauli_op = Clifford(rand_pauli) new_element_list.append((rand_pauli, rand_pauli_op)) return new_element_list - def _start_end_cliffords( - self, elements: Iterable[Clifford], rng: Optional[Union[int, Generator]] - ) -> List[QuantumCircuit]: + def _start_end_cliffords(self, elements: Iterable[Clifford]) -> List[QuantumCircuit]: """Add a layer of uniformly random 1-qubit Cliffords to the beginning of the list and its inverse to the end of the list @@ -358,16 +345,17 @@ def _start_end_cliffords( Returns: The new list of elements with the start and end local (1-qubit) Cliffords. """ + rand_clifford = [ - self._clifford_utils.random_cliffords(num_qubits=1, rng=rng)[0] - for _ in self.physical_qubits + random_clifford(1, seed=self.experiment_options.seed) for _ in self.physical_qubits ] + + # Assemble the n-qubit Clifford layer tensor_op = rand_clifford[0] for cliff in rand_clifford[1:]: tensor_op = tensor_op ^ cliff tensor_circ = tensor_op.to_circuit() - rand_clifford = random_clifford(self.num_qubits, seed=rng).to_circuit() return [tensor_circ] + elements + [tensor_circ.inverse()] def _generate_mirror( @@ -430,6 +418,5 @@ def _generate_mirror( "target": self._clifford_utils.compute_target_bitstring(rb_circ), "inverting_pauli_layer": self._inverting_pauli_layer, } - rb_circ.measure_all() circuits.append(rb_circ) return circuits diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 38797a7fe5..54ef4ffb3b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -19,7 +19,8 @@ from numbers import Integral import numpy as np -from numpy.random import Generator, default_rng +from numpy.random import Generator, default_rng, BitGenerator, SeedSequence + from qiskit import QuantumCircuit, QuantumRegister from qiskit.exceptions import QiskitError from qiskit.circuit import Gate @@ -82,13 +83,13 @@ class EdgeGrabSampler(MirrorRBSampler): def __call__( self, - num_qubits, - two_qubit_gate_density, - coupling_map, - length, + num_qubits: int, + two_qubit_gate_density: float, + coupling_map: List[List[int]], + length: int, one_qubit_gate_set: Optional[Union[str, List]] = "clifford", two_qubit_gate_set: Optional[List] = ["cx"], - seed=None, + seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, ): """Sample layers using the edge grab algorithm. @@ -109,18 +110,22 @@ def __call__( TypeError: If invalid gate set(s) are specified. Returns: - List of sampled QuantumCircuit layers with length ``length``. + List of sampled QuantumCircuit layers with length ``length``. Integers are + returned for one-qubit Cliffords for speed. """ + rng = default_rng(seed=seed) + if isinstance(one_qubit_gate_set, list) or not ( - one_qubit_gate_set.casefold() in ["clifford"] + one_qubit_gate_set.casefold() == "clifford" ): raise TypeError("one_qubit_gate_set must be a list of gates or 'clifford'.") - self.two_qubit_density = two_qubit_gate_density - self.coupling_map = coupling_map - - rng = default_rng(seed=seed) + if num_qubits == 1: + if one_qubit_gate_set.casefold() == "clifford": + return rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) + else: + return rng.choice(one_qubit_gate_set, size=length) qc_list = [] for _ in list(range(length)): @@ -162,6 +167,7 @@ def __call__( # with probability two_qubit_prob, place a two-qubit gate from the # gate set on edge in selected_edges try: + print(edge[0], edge[1]) getattr(qc, rng.choice(two_qubit_gate_set))(edge[0], edge[1]) except AttributeError: raise QiskitError("Invalid two-qubit gate set specified.") From 1f58ffb52030118f6859111f37516a6139413874 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Sat, 11 Mar 2023 13:24:54 -0500 Subject: [PATCH 27/56] fix rebase errors --- docs/_ext/autoref.py | 2 - docs/tutorials/randomized_benchmarking.rst | 7 +- .../multi_state_discrimination_analysis.py | 21 - .../library/quantum_volume/qv_experiment.py | 3 +- .../randomized_benchmarking/clifford_utils.py | 287 ---- .../interleaved_rb_experiment.py | 3 +- .../randomized_benchmarking/rb_experiment.py | 3 +- .../tomography/tomography_experiment.py | 27 - .../notes/fix-992-1d3ab6862e7578ac.yaml | 8 - test/base.py | 14 - .../test_randomized_benchmarking.py | 544 +++++++- .../test_randomized_benchmarking.py | 1201 ----------------- 12 files changed, 528 insertions(+), 1592 deletions(-) delete mode 100644 releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml delete mode 100644 test/randomized_benchmarking/test_randomized_benchmarking.py diff --git a/docs/_ext/autoref.py b/docs/_ext/autoref.py index 3c8f2cefd1..6a4c42a4ae 100644 --- a/docs/_ext/autoref.py +++ b/docs/_ext/autoref.py @@ -30,7 +30,6 @@ class WebSite(Directive): .. ref_website:: qiskit-experiments, https://github.com/Qiskit/qiskit-experiments """ - required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True @@ -68,7 +67,6 @@ class Arxiv(Directive): If an article is not found, no journal information will be shown. """ - required_arguments = 2 optional_arguments = 0 final_argument_whitespace = False diff --git a/docs/tutorials/randomized_benchmarking.rst b/docs/tutorials/randomized_benchmarking.rst index 7ec8bad4f7..492d65c68d 100644 --- a/docs/tutorials/randomized_benchmarking.rst +++ b/docs/tutorials/randomized_benchmarking.rst @@ -11,15 +11,10 @@ See `Qiskit Textbook `__ for an explanation on the RB method, which is based on Ref. [1, 2]. -.. jupyter-execute:: - :hide-code: - - %matplotlib inline - .. jupyter-execute:: import numpy as np - from qiskit_experiments.library import StandardRB, InterleavedRB, MirrorRB + from qiskit_experiments.library import StandardRB, InterleavedRB from qiskit_experiments.framework import ParallelExperiment, BatchExperiment import qiskit.circuit.library as circuits diff --git a/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py b/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py index 498286fc55..94b9bd990a 100644 --- a/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py +++ b/qiskit_experiments/library/characterization/analysis/multi_state_discrimination_analysis.py @@ -20,20 +20,12 @@ from qiskit.providers.options import Options from qiskit_experiments.framework import BaseAnalysis, AnalysisResultData, ExperimentData from qiskit_experiments.data_processing import SkQDA -from qiskit_experiments.data_processing.exceptions import DataProcessorError from qiskit_experiments.visualization import BasePlotter, IQPlotter, MplDrawer, PlotStyle from qiskit_experiments.warnings import HAS_SKLEARN if TYPE_CHECKING: from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis -try: - from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis - - HAS_SKLEARN = True -except ImportError: - HAS_SKLEARN = False - class MultiStateDiscriminationAnalysis(BaseAnalysis): r"""This class fits a multi-state discriminator to the data. @@ -52,19 +44,6 @@ class MultiStateDiscriminationAnalysis(BaseAnalysis): This class requires that scikit-learn is installed. """ - def __init__(self): - """Setup the analysis. - - Raises: - DataProcessorError: if sklearn is not installed. - """ - if not HAS_SKLEARN: - raise DataProcessorError( - f"SKlearn is needed to initialize an {self.__class__.__name__}." - ) - - super().__init__() - @classmethod @HAS_SKLEARN.require_in_call def _default_options(cls) -> Options: diff --git a/qiskit_experiments/library/quantum_volume/qv_experiment.py b/qiskit_experiments/library/quantum_volume/qv_experiment.py index 5067d2ef3f..e56a3b8df2 100644 --- a/qiskit_experiments/library/quantum_volume/qv_experiment.py +++ b/qiskit_experiments/library/quantum_volume/qv_experiment.py @@ -14,7 +14,8 @@ """ from typing import Union, Sequence, Optional, List -from numpy.random import Generator, default_rng, BitGenerator, SeedSequence +from numpy.random import Generator, default_rng +from numpy.random.bit_generator import BitGenerator, SeedSequence try: from qiskit import Aer diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 4b7c1670bf..dcd4028e3a 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -652,293 +652,6 @@ def _create_cliff_2q_layer_2(): _NUM_LAYER_2 = 16 -@lru_cache(maxsize=None) -def _transformed_clifford_layer( - layer: int, index: Integral, basis_gates: Tuple[str, ...] -) -> QuantumCircuit: - # Return the index-th quantum circuit of the layer translated with the basis_gates. - # The result is cached for speed. - return _synthesize_clifford_circuit(_CLIFFORD_LAYER[layer][index], basis_gates) - - -def _num_from_layer_indices(triplet: Tuple[Integral, Integral, Integral]) -> Integral: - """Return the clifford number corresponding to the input triplet.""" - num = triplet[0] * _NUM_LAYER_1 * _NUM_LAYER_2 + triplet[1] * _NUM_LAYER_2 + triplet[2] - return num - - -def _layer_indices_from_num(num: Integral) -> Tuple[Integral, Integral, Integral]: - """Return the triplet of layer indices corresponding to the input number.""" - idx2 = num % _NUM_LAYER_2 - num = num // _NUM_LAYER_2 - idx1 = num % _NUM_LAYER_1 - idx0 = num // _NUM_LAYER_1 - return idx0, idx1, idx2 - - -# Constant mapping from 1Q single Clifford gate to 1Q Clifford numerical identifier. -# This table must be generated using `data.generate_clifford_data.gen_cliff_single_1q_gate_map`, or, -# equivalently, correspond to the ordering implicitly defined by CliffUtils.clifford_1_qubit_circuit. -_CLIFF_SINGLE_GATE_MAP_1Q = { - ("id", (0,)): 0, - ("h", (0,)): 1, - ("sxdg", (0,)): 2, - ("s", (0,)): 4, - ("x", (0,)): 6, - ("sx", (0,)): 8, - ("y", (0,)): 12, - ("z", (0,)): 18, - ("sdg", (0,)): 22, -} -# Constant mapping from 2Q single Clifford gate to 2Q Clifford numerical identifier. -# This table must be generated using `data.generate_clifford_data.gen_cliff_single_2q_gate_map`, or, -# equivalently, correspond to the ordering defined by _layer_indices_from_num and _CLIFFORD_LAYER. -_CLIFF_SINGLE_GATE_MAP_2Q = { - ("id", (0,)): 0, - ("id", (1,)): 0, - ("h", (0,)): 5760, - ("h", (1,)): 2880, - ("sxdg", (0,)): 6720, - ("sxdg", (1,)): 3200, - ("s", (0,)): 7680, - ("s", (1,)): 3520, - ("x", (0,)): 4, - ("x", (1,)): 1, - ("sx", (0,)): 6724, - ("sx", (1,)): 3201, - ("y", (0,)): 8, - ("y", (1,)): 2, - ("z", (0,)): 12, - ("z", (1,)): 3, - ("sdg", (0,)): 7692, - ("sdg", (1,)): 3523, - ("cx", (0, 1)): 16, - ("cx", (1, 0)): 2336, - ("cz", (0, 1)): 368, - ("cz", (1, 0)): 368, -} - - -######## -# Functions for 1-qubit integer Clifford operations -def compose_1q(lhs: Integral, rhs: Integral) -> Integral: - """Return the composition of 1-qubit clifford integers.""" - return _CLIFFORD_COMPOSE_1Q[lhs, rhs] - - -def inverse_1q(num: Integral) -> Integral: - """Return the inverse of a 1-qubit clifford integer.""" - return _CLIFFORD_INVERSE_1Q[num] - - -def num_from_1q_circuit(qc: QuantumCircuit) -> Integral: - """Convert a given 1-qubit Clifford circuit to the corresponding integer.""" - num = 0 - for inst in qc: - rhs = _num_from_1q_gate(op=inst.operation) - num = _CLIFFORD_COMPOSE_1Q[num, rhs] - return num - - -def _num_from_1q_gate(op: Instruction) -> int: - """ - Convert a given 1-qubit clifford operation to the corresponding integer. - Note that supported operations are limited to ones in :const:`CLIFF_SINGLE_GATE_MAP_1Q` or Rz gate. - - Args: - op: operation to be converted. - - Returns: - An integer representing a Clifford consisting of a single operation. - - Raises: - QiskitError: if the input instruction is not a Clifford instruction. - QiskitError: if rz is given with a angle that is not Clifford. - """ - if op.name in {"delay", "barrier"}: - return 0 - try: - name = _deparameterized_name(op) - return _CLIFF_SINGLE_GATE_MAP_1Q[(name, (0,))] - except QiskitError as err: - raise QiskitError( - f"Parameterized instruction {op.name} could not be converted to integer Clifford" - ) from err - except KeyError as err: - raise QiskitError( - f"Instruction {op.name} could not be converted to integer Clifford" - ) from err - - -def _deparameterized_name(inst: Instruction) -> str: - if inst.name == "rz": - if np.isclose(inst.params[0], np.pi) or np.isclose(inst.params[0], -np.pi): - return "z" - elif np.isclose(inst.params[0], np.pi / 2): - return "s" - elif np.isclose(inst.params[0], -np.pi / 2): - return "sdg" - else: - raise QiskitError("Wrong param {} for rz in clifford".format(inst.params[0])) - - return inst.name - - -######## -# Functions for 2-qubit integer Clifford operations -def compose_2q(lhs: Integral, rhs: Integral) -> Integral: - """Return the composition of 2-qubit clifford integers.""" - num = lhs - for layer, idx in enumerate(_layer_indices_from_num(rhs)): - circ = _CLIFFORD_LAYER[layer][idx] - num = _compose_num_with_circuit_2q(num, circ) - return num - - -def inverse_2q(num: Integral) -> Integral: - """Return the inverse of a 2-qubit clifford integer.""" - return _CLIFFORD_INVERSE_2Q[num] - - -def num_from_2q_circuit(qc: QuantumCircuit) -> Integral: - """Convert a given 2-qubit Clifford circuit to the corresponding integer.""" - return _compose_num_with_circuit_2q(0, qc) - - -def _compose_num_with_circuit_2q(num: Integral, qc: QuantumCircuit) -> Integral: - """Compose a number that represents a Clifford, with a Clifford circuit, and return the - number that represents the resulting Clifford.""" - lhs = num - for inst in qc: - qubits = tuple(qc.find_bit(q).index for q in inst.qubits) - rhs = _num_from_2q_gate(op=inst.operation, qubits=qubits) - lhs = _CLIFFORD_COMPOSE_2Q[lhs, rhs] - return lhs - - -def _num_from_2q_gate( - op: Instruction, qubits: Optional[Union[Tuple[int, int], Tuple[int]]] = None -) -> int: - """ - Convert a given 1-qubit clifford operation to the corresponding integer. - Note that supported operations are limited to ones in `CLIFF_SINGLE_GATE_MAP_2Q` or Rz gate. - - Args: - op: operation of instruction to be converted. - qubits: qubits to which the operation applies - - Returns: - An integer representing a Clifford consisting of a single operation. - - Raises: - QiskitError: if the input instruction is not a Clifford instruction. - QiskitError: if rz is given with a angle that is not Clifford. - """ - if op.name in {"delay", "barrier"}: - return 0 - - qubits = qubits or (0, 1) - try: - name = _deparameterized_name(op) - return _CLIFF_SINGLE_GATE_MAP_2Q[(name, qubits)] - except QiskitError as err: - raise QiskitError( - f"Parameterized instruction {op.name} could not be converted to integer Clifford" - ) from err - except KeyError as err: - raise QiskitError( - f"Instruction {op.name} on {qubits} could not be converted to integer Clifford" - ) from err - - -def _append_v_w(qc, vw0, vw1): - if vw0 == "v": - qc.sdg(0) - qc.h(0) - elif vw0 == "w": - qc.h(0) - qc.s(0) - if vw1 == "v": - qc.sdg(1) - qc.h(1) - elif vw1 == "w": - qc.h(1) - qc.s(1) - - -def _create_cliff_2q_layer_0(): - """Layer 0 consists of 0 or 1 H gates on each qubit, followed by 0/1/2 V gates on each qubit. - Number of Cliffords == 36.""" - circuits = [] - num_h = [0, 1] - v_w_gates = ["i", "v", "w"] - for h0, h1, v0, v1 in itertools.product(num_h, num_h, v_w_gates, v_w_gates): - qc = QuantumCircuit(2) - for _ in range(h0): - qc.h(0) - for _ in range(h1): - qc.h(1) - _append_v_w(qc, v0, v1) - circuits.append(qc) - return circuits - - -def _create_cliff_2q_layer_1(): - """Layer 1 consists of one of the following: - - nothing - - cx(0,1) followed by 0/1/2 V gates on each qubit - - cx(0,1), cx(1,0) followed by 0/1/2 V gates on each qubit - - cx(0,1), cx(1,0), cx(0,1) - Number of Cliffords == 20.""" - circuits = [QuantumCircuit(2)] # identity at the beginning - - v_w_gates = ["i", "v", "w"] - for v0, v1 in itertools.product(v_w_gates, v_w_gates): - qc = QuantumCircuit(2) - qc.cx(0, 1) - _append_v_w(qc, v0, v1) - circuits.append(qc) - - for v0, v1 in itertools.product(v_w_gates, v_w_gates): - qc = QuantumCircuit(2) - qc.cx(0, 1) - qc.cx(1, 0) - _append_v_w(qc, v0, v1) - circuits.append(qc) - - qc = QuantumCircuit(2) # swap at the end - qc.cx(0, 1) - qc.cx(1, 0) - qc.cx(0, 1) - circuits.append(qc) - return circuits - - -def _create_cliff_2q_layer_2(): - """Layer 2 consists of a Pauli gate on each qubit {Id, X, Y, Z}. - Number of Cliffords == 16.""" - circuits = [] - pauli = ("i", XGate(), YGate(), ZGate()) - for p0, p1 in itertools.product(pauli, pauli): - qc = QuantumCircuit(2) - if p0 != "i": - qc.append(p0, [0]) - if p1 != "i": - qc.append(p1, [1]) - circuits.append(qc) - return circuits - - -_CLIFFORD_LAYER = ( - _create_cliff_2q_layer_0(), - _create_cliff_2q_layer_1(), - _create_cliff_2q_layer_2(), -) -_NUM_LAYER_0 = 36 -_NUM_LAYER_1 = 20 -_NUM_LAYER_2 = 16 - - @lru_cache(maxsize=None) def _transformed_clifford_layer( layer: int, index: Integral, basis_gates: Tuple[str, ...] diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py index cf3db91337..a16086979f 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_experiment.py @@ -15,7 +15,8 @@ import warnings from typing import Union, Iterable, Optional, List, Sequence, Tuple -from numpy.random import Generator, BitGenerator, SeedSequence +from numpy.random import Generator +from numpy.random.bit_generator import BitGenerator, SeedSequence from qiskit.circuit import QuantumCircuit, Instruction, Gate, Delay from qiskit.compiler import transpile diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index a5ec7dfdbc..f329436bd8 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -19,7 +19,8 @@ from typing import Union, Iterable, Optional, List, Sequence, Tuple import numpy as np -from numpy.random import Generator, default_rng, BitGenerator, SeedSequence +from numpy.random import Generator, default_rng +from numpy.random.bit_generator import BitGenerator, SeedSequence from qiskit.circuit import QuantumCircuit, Instruction, Barrier from qiskit.exceptions import QiskitError diff --git a/qiskit_experiments/library/tomography/tomography_experiment.py b/qiskit_experiments/library/tomography/tomography_experiment.py index 6e3eab64fe..015f7fa1df 100644 --- a/qiskit_experiments/library/tomography/tomography_experiment.py +++ b/qiskit_experiments/library/tomography/tomography_experiment.py @@ -13,7 +13,6 @@ Quantum Tomography experiment """ -import warnings from typing import Union, Optional, Iterable, List, Tuple, Sequence from itertools import product from qiskit.circuit import QuantumCircuit, Instruction, ClassicalRegister, Clbit @@ -103,32 +102,6 @@ def __init__( Raises: QiskitError: if input params are invalid. """ - # Deprecated kwargs - if qubits is not None: - physical_qubits = qubits - warnings.warn( - "The `qubits` kwarg has been renamed to `physical_qubits`." - " It will be removed in a future release.", - DeprecationWarning, - stacklevel=2, - ) - if measurement_qubits is not None: - measurement_indices = measurement_qubits - warnings.warn( - "The `measurement_qubits` kwarg has been renamed to `measurement_indices`." - " It will be removed in a future release.", - DeprecationWarning, - stacklevel=2, - ) - if preparation_qubits is not None: - preparation_indices = preparation_qubits - warnings.warn( - "The `preparation_qubits` kwarg has been renamed to `preparation_indices`." - " It will be removed in a future release.", - DeprecationWarning, - stacklevel=2, - ) - # Initialize BaseExperiment if physical_qubits is None: physical_qubits = tuple(range(circuit.num_qubits)) diff --git a/releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml b/releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml deleted file mode 100644 index 84722589c8..0000000000 --- a/releasenotes/notes/fix-992-1d3ab6862e7578ac.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -fixes: - - | - Fixes bug in the :class:`~.LocalReadoutError` experiment where analysis - would fail when run on an ideal simulator with no readout error. - - See Issue #992 `_ - for additional details. diff --git a/test/base.py b/test/base.py index f8903264e1..41915c2b8d 100644 --- a/test/base.py +++ b/test/base.py @@ -19,20 +19,6 @@ import warnings from typing import Any, Callable, Optional -# Temporary work around for https://github.com/Qiskit/qiskit-terra/issues/9291 -# The class decorator / method wrapper in qiskit does not handle -# __init_subclass__ properly. Python 3.11.1 added an __init_subclass__ to -# TestCase. It's not that important so as a temporary hack we just drop it. -from unittest import TestCase - -if "__init_subclass__" in TestCase.__dict__: - del TestCase.__init_subclass__ -if not hasattr(TestCase, "_test_cleanups"): - TestCase._test_cleanups = [] -if not hasattr(TestCase, "_classSetupFailed"): - TestCase._classSetupFailed = False -# pylint: disable=wrong-import-position - import numpy as np import uncertainties from lmfit import Model diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 2e446cb05b..d421297994 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -21,15 +21,11 @@ from qiskit.circuit import Delay, QuantumCircuit, Parameter, Gate from qiskit.circuit.library import SXGate, CXGate, TGate, CZGate from qiskit.exceptions import QiskitError -from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington, FakeParis +from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington from qiskit.pulse import Schedule, InstructionScheduleMap from qiskit.quantum_info import Operator -from qiskit.transpiler.basepasses import TransformationPass -from qiskit.transpiler import Layout, PassManager, CouplingMap - from qiskit_aer import AerSimulator from qiskit_aer.noise import NoiseModel, depolarizing_error - from qiskit_experiments.database_service.exceptions import ExperimentEntryNotFound from qiskit_experiments.framework.composite import ParallelExperiment from qiskit_experiments.library import randomized_benchmarking as rb @@ -476,6 +472,526 @@ def test_interleaving_cnot_gate_with_non_supported_direction(self): self.assertEqual(inst.qubits, expected_qubits) +class NoiseSimulator(AerSimulator): + """Quantum device simulator that has nonlocal CX errors""" + + def run(self, circuits, validate=False, parameter_binds=None, **run_options): + """Applies transpiler pass NonlocalCXDepError to circuits run on this backend""" + pm = PassManager() + cm = CouplingMap(couplinglist=self.configuration().coupling_map) + pm.append([NonlocalCXDepError(cm)]) + noise_circuits = pm.run(circuits) + return super().run( + noise_circuits, validate=validate, parameter_binds=parameter_binds, **run_options + ) + + +@ddt +class TestMirrorRB(RBTestCase): + """Test for mirror RB.""" + + def test_single_qubit(self): + """Test single qubit mirror RB.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=list(range(2, 300, 20)), + seed=124, + backend=self.backend, + num_samples=30, + ) + # exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**self.transpiler_options) + self.assertAllIdentity(exp.circuits()) + + expdata = exp.run() + self.assertExperimentDone(expdata) + + # Given we have gate number per Clifford n_gpc, we can compute EPC as + # EPC = 1 - (1 - r)^n_gpc + # where r is gate error of SX gate, i.e. dep-parameter divided by 2. + # We let transpiler use SX and RZ. + # The number of physical gate per Clifford will distribute + # 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. + # But for mirror RB, we must also add the SX gate number per Pauli n_gpp, + # which is 2 for X and Y gates and 0 for I and Z gates (average = 1.0). So the + # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 + epc = expdata.analysis_results("EPC") + + epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_two_qubit(self): + """Test two qubit RB.""" + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 300, 20)), + seed=123, + backend=self.backend, + num_samples=30, + two_qubit_gate_density=two_qubit_gate_density, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**self.transpiler_options) + self.assertAllIdentity(exp.circuits()) + + expdata = exp.run() + self.assertExperimentDone(expdata) + + # Given a two qubit gate density xi and an n qubit circuit, a Clifford + # layer has n*xi two-qubit gates. Obviously a Pauli has no two-qubit + # gates, so on aveage, a Clifford + Pauli layer has n*xi two-qubit gates + # and 2*n - 2*n*xi one-qubit gates (two layers have 2*n lattice sites, + # 2*n*xi of which are occupied by two-qubit gates). For two-qubit + # mirrored RB, the average infidelity is ((2^2 - 1)/2^2 = 3/4) times + # the two-qubit depolarizing parameter + epc = expdata.analysis_results("EPC") + cx_factor = (1 - 3 * self.p2q / 4) ** (2 * two_qubit_gate_density) + sx_factor = (1 - self.p1q / 2) ** (2 * 2 * (1 - two_qubit_gate_density)) + epc_expected = 1 - cx_factor * sx_factor + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_two_qubit_nonlocal_noise(self): + """Test for 2 qubit Mirrored RB with a nonlocal noise model""" + # depolarizing error + p1q = 0.0 + p2q = 0.01 + pvz = 0.0 + + # setup noise model + sx_error = depolarizing_error(p1q, 1) + rz_error = depolarizing_error(pvz, 1) + cx_error = depolarizing_error(p2q, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + + basis_gates = ["id", "sx", "rz", "cx"] + # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { + "basis_gates": basis_gates, + "optimization_level": 1, + } + # Coupling map is 3 x 3 lattice + noise_backend = NoiseSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=CouplingMap.from_grid(3, 3).get_edges(), + ) + + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 110, 20)), + seed=123, + backend=noise_backend, + num_samples=20, + two_qubit_gate_density=two_qubit_gate_density, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**transpiler_options) + self.assertAllIdentity(exp.circuits()) + expdata = exp.run(noise_backend) + self.assertExperimentDone(expdata) + + epc = expdata.analysis_results("EPC") + # Compared to expected EPC in two-qubit test without nonlocal noise above, + # we include an extra factor for the nonlocal CX error. This nonlocal + # error is modeled by a one-qubit depolarizing channel on each qubit after + # each CX, so the expected number of one-qubit depolarizing channels + # induced by CXs is (number of CXs) * (number of qubits) = (two qubit gate + # density) * (number of qubits) * (number of qubits). + num_q = 2 + cx_factor = (1 - 3 * p2q / 4) ** (num_q * two_qubit_gate_density) + sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) + cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) + epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_three_qubit_nonlocal_noise(self): + """Test three-qubit mirrored RB on a nonlocal noise model""" + # depolarizing error + p1q = 0.001 + p2q = 0.01 + pvz = 0.0 + + # setup noise modelle + sx_error = depolarizing_error(p1q, 1) + rz_error = depolarizing_error(pvz, 1) + cx_error = depolarizing_error(p2q, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + + basis_gates = ["id", "sx", "rz", "cx"] + # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { + "basis_gates": basis_gates, + "optimization_level": 1, + } + noise_backend = NoiseSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=CouplingMap.from_grid(3, 3).get_edges(), + ) + + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1, 2), + lengths=list(range(2, 110, 50)), + seed=123, + backend=noise_backend, + num_samples=20, + two_qubit_gate_density=two_qubit_gate_density, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**transpiler_options) + self.assertAllIdentity(exp.circuits()) + expdata = exp.run(noise_backend) + self.assertExperimentDone(expdata) + + epc = expdata.analysis_results("EPC") + # The expected EPC was computed in simulations not presented here. + # Method: + # 1. Sample N Clifford layers according to the edgegrab algorithm + # in clifford_utils. + # 2. Transpile these into SX, RZ, and CX gates. + # 3. Replace each SX and CX with one- and two-qubit depolarizing + # channels, respectively, and remove RZ gates. + # 4. Use qiskit.quantum_info.average_gate_fidelity on these N layers + # to compute 1 - EPC for each layer, and average over the N layers. + epc_expected = 0.0124 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + + def test_add_more_circuit_yields_lower_variance(self): + """Test variance reduction with larger number of sampling.""" + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 30, 4)), + seed=123, + backend=self.backend, + num_samples=3, + inverting_pauli_layer=False, + ) + exp1.analysis.set_options(gate_error_ratio=None) + exp1.set_transpile_options(**self.transpiler_options) + expdata1 = exp1.run() + self.assertExperimentDone(expdata1) + + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 30, 4)), + seed=456, + backend=self.backend, + num_samples=10, + inverting_pauli_layer=False, + ) + exp2.analysis.set_options(gate_error_ratio=None) + exp2.set_transpile_options(**self.transpiler_options) + expdata2 = exp2.run() + self.assertExperimentDone(expdata2) + + self.assertLess( + expdata2.analysis_results("EPC").value.s, + expdata1.analysis_results("EPC").value.s, + ) + + def test_return_same_circuit(self): + """Test if setting the same seed returns the same circuits.""" + lengths = [10, 20] + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=lengths, + seed=123, + backend=self.backend, + ) + + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=lengths, + seed=123, + backend=self.backend, + ) + + circs1 = exp1.circuits() + circs2 = exp2.circuits() + + for circ1, circ2 in zip(circs1, circs2): + self.assertEqual(circ1.decompose(), circ2.decompose()) + + def test_full_sampling(self): + """Test if full sampling generates different circuits.""" + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=[10, 20], + seed=123, + backend=self.backend, + num_samples=1, + full_sampling=True, + ) + + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=[10, 20], + seed=123, + backend=self.backend, + num_samples=1, + full_sampling=False, + ) + + circs1 = exp1.circuits() + circs2 = exp2.circuits() + + self.assertNotEqual(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()) + + def test_target_bitstring(self): + """Test if correct target bitstring is returned.""" + qc = QuantumCircuit(9) + qc.z(0) + qc.y(1) + qc.y(2) + qc.z(3) + qc.y(4) + qc.x(7) + qc.y(8) + exp = rb.MirrorRB(qubits=[0], lengths=[2], backend=self.backend) + expected_tb = exp._clifford_utils.compute_target_bitstring(qc) + actual_tb = "110010110" + self.assertEqual(expected_tb, actual_tb) + + def test_zero_2q_gate_density(self): + """Test that there are no two-qubit gates when the two-qubit gate + density is set to 0.""" + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=[40], + seed=124, + backend=self.backend, + num_samples=1, + two_qubit_gate_density=0, + ) + circ = exp.circuits()[0].decompose() + for datum in circ.data: + inst_name = datum[0].name + self.assertNotEqual("cx", inst_name) + + def test_max_2q_gate_density(self): + """Test that every intermediate Clifford layer is filled with two-qubit + gates when the two-qubit gate density is set to 0.5, its maximum value + (assuming an even number of qubits and a backend coupling map with full + connectivity).""" + backend = AerSimulator(coupling_map=CouplingMap.from_full(4).get_edges()) + exp = rb.MirrorRB( + qubits=(0, 1, 2, 3), + lengths=[40], + seed=125, + backend=backend, + num_samples=1, + two_qubit_gate_density=0.5, + ) + circ = exp.circuits()[0].decompose() + num_cxs = 0 + for datum in circ.data: + if datum[0].name == "cx": + num_cxs += 1 + self.assertEqual(80, num_cxs) + + def test_local_clifford(self): + """Test that the number of layers is correct depending on whether + local_clifford is set to True or False by counting the number of barriers.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=[2], + seed=126, + backend=self.backend, + num_samples=1, + local_clifford=True, + pauli_randomize=False, + two_qubit_gate_density=0.2, + inverting_pauli_layer=False, + ) + circ = exp.circuits()[0] + num_barriers = 0 + for datum in circ.data: + if datum[0].name == "barrier": + num_barriers += 1 + self.assertEqual(5, num_barriers) + + def test_pauli_randomize(self): + """Test that the number of layers is correct depending on whether + pauli_randomize is set to True or False by counting the number of barriers.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=[2], + seed=126, + backend=self.backend, + num_samples=1, + local_clifford=False, + pauli_randomize=True, + two_qubit_gate_density=0.2, + inverting_pauli_layer=False, + ) + circ = exp.circuits()[0] + num_barriers = 0 + for datum in circ.data: + if datum[0].name == "barrier": + num_barriers += 1 + self.assertEqual(6, num_barriers) + + def test_inverting_pauli_layer(self): + """Test that a circuit with an inverting Pauli layer at the end (i.e., + a layer of Paulis before the final measurement that restores the output + to |0>^num_qubits up to a global phase) composes to the identity (up to + a global phase)""" + exp = rb.MirrorRB( + qubits=(0, 1, 2), + lengths=[2], + seed=127, + backend=self.backend, + num_samples=3, + local_clifford=True, + pauli_randomize=True, + two_qubit_gate_density=0.2, + inverting_pauli_layer=True, + ) + self.assertAllIdentity(exp.circuits()) + + @data( + { + "qubits": [3, 3], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # repeated qubits + { + "qubits": [0, 1], + "lengths": [2, 4, 6, -8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative length + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": -4, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative number of samples + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 0, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # zero samples + { + "qubits": [0, 1], + "lengths": [2, 6, 6, 6, 10], + "num_samples": 2, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # repeated lengths + { + "qubits": [0, 1], + "lengths": [2, 4, 5, 8, 10], + "num_samples": 2, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # odd length + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "two_qubit_gate_density": -0.1, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative two-qubit gate density + ) + def test_invalid_configuration(self, configs): + """Test raise error when creating experiment with invalid configs.""" + self.assertRaises(QiskitError, rb.MirrorRB, **configs) + + @data( + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": None, + }, # no backend + ) + def test_no_backend(self, configs): + """Test raise error when no backend is provided for sampling circuits.""" + mirror_exp = rb.MirrorRB(**configs) + self.assertRaises(QiskitError, mirror_exp.run) + + @data( + { + "qubits": [0, 25], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator.from_backend(FakeParis()), + }, # Uncoupled qubits to test edgegrab algorithm warning + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "two_qubit_gate_density": 0.6, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # High two-qubit gate density warning + ) + def test_warnings(self, configs): + """Test raise warnings when creating experiment.""" + mirror_exp = rb.MirrorRB(**configs) + self.assertWarns(Warning, mirror_exp.run) + + def test_experiment_config(self): + """Test converting to and from config works""" + exp = rb.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123, backend=self.backend) + loaded_exp = rb.MirrorRB.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.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123) + self.assertRoundTripSerializable(exp, self.json_equiv) + + def test_analysis_config(self): + """ "Test converting analysis to and from config works""" + analysis = RBAnalysis() + loaded = RBAnalysis.from_config(analysis.config()) + self.assertNotEqual(analysis, loaded) + self.assertEqual(analysis.config(), loaded.config()) + + def test_expdata_serialization(self): + """Test serializing experiment data works.""" + exp = rb.MirrorRB( + qubits=(0,), + lengths=list(range(2, 200, 50)), + seed=123, + backend=self.backend, + inverting_pauli_layer=False, + ) + exp.set_transpile_options(**self.transpiler_options) + expdata = exp.run() + self.assertExperimentDone(expdata) + self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) + self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) + + class RBRunTestCase(QiskitExperimentsTestCase, RBTestMixin): """Base test case for running RB experiments defining a common noise model.""" @@ -546,24 +1062,6 @@ def test_single_qubit(self): epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - def test_custom_distribution(self): - """Test providing a custom distribution.""" - qubits = ( - 0, - 1, - 2, - ) - exp = rb.MirrorRB( - physical_qubits=qubits, - distribution=rb.RandomEdgeGrabDistribution, - two_qubit_gate_density=0.5, - lengths=list(range(2, 300, 20)), - seed=124, - backend=self.backend, - num_samples=30, - ) - # test that feeding the circuit from edge grab into discrete yields the same answer(?) - def test_two_qubit(self): """Test two qubit RB. Use default basis gates.""" exp = rb.StandardRB( diff --git a/test/randomized_benchmarking/test_randomized_benchmarking.py b/test/randomized_benchmarking/test_randomized_benchmarking.py deleted file mode 100644 index c429a6ee6b..0000000000 --- a/test/randomized_benchmarking/test_randomized_benchmarking.py +++ /dev/null @@ -1,1201 +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 -from qiskit.providers.fake_provider import FakeParis -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.transpiler.basepasses import TransformationPass -from qiskit.transpiler import Layout, PassManager, CouplingMap -from qiskit.transpiler.exceptions import TranspilerError - -from qiskit_experiments.library import randomized_benchmarking as rb -from qiskit_experiments.database_service.exceptions import DbExperimentEntryNotFound -from qiskit_experiments.library.randomized_benchmarking.rb_analysis import RBAnalysis - - -class RBTestCase(QiskitExperimentsTestCase): - """Base test case for randomized benchmarking defining a common noise model.""" - - def setUp(self): - """Setup the tests.""" - super().setUp() - - # depolarizing error - self.p1q = 0.02 - self.p2q = 0.10 - self.pvz = 0.0 - - # basis gates - self.basis_gates = ["sx", "rz", "cx"] - - # setup noise model - sx_error = depolarizing_error(self.p1q, 1) - rz_error = depolarizing_error(self.pvz, 1) - cx_error = depolarizing_error(self.p2q, 2) - - noise_model = NoiseModel() - noise_model.add_all_qubit_quantum_error(sx_error, "sx") - noise_model.add_all_qubit_quantum_error(rz_error, "rz") - noise_model.add_all_qubit_quantum_error(cx_error, "cx") - - self.noise_model = noise_model - self.basis_gates = noise_model.basis_gates - - # Need level1 for consecutive gate cancellation for reference EPC value calculation - self.transpiler_options = { - "basis_gates": self.basis_gates, - "optimization_level": 1, - } - - # Aer simulator - self.backend = AerSimulator( - noise_model=noise_model, - seed_simulator=123, - coupling_map=AerSimulator.from_backend(FakeParis()).configuration().coupling_map, - ) - - 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)) - circ.remove_final_measurements() - # In case the final output is |0>^num_qubits up to a phase, we use .table.pauli - self.assertEqual( - Clifford(circ).table.pauli, - iden.table.pauli, - f"Circuit {circ.name} doesn't result in the identity matrix.", - ) - - -def decr_dep_param(q, q_1, q_2, coupling_map): - """Helper function to generate a one-qubit depolarizing channel whose - parameter depends on coupling map distance in a backend""" - d = min(coupling_map.distance(q, q_1), coupling_map.distance(q, q_2)) - return 0.0035 * 0.999**d - - -class NonlocalCXDepError(TransformationPass): - """Transpiler pass for simulating nonlocal errors in a quantum device""" - - def __init__(self, coupling_map, initial_layout=None): - """Maps a DAGCircuit onto a `coupling_map` using swap gates. - Args: - coupling_map (CouplingMap): Directed graph represented a coupling map. - initial_layout (Layout): initial layout of qubits in mapping - """ - super().__init__() - self.coupling_map = coupling_map - self.initial_layout = initial_layout - - def run(self, dag): - """Runs the NonlocalCXDepError pass on `dag` - - Args: - dag (DAGCircuit): DAG to map. - - Returns: - DAGCircuit: A mapped DAG. - - Raises: - TranspilerError: initial layout and coupling map do not have the - same size - """ - - if self.initial_layout is None: - if self.property_set["layout"]: - self.initial_layout = self.property_set["layout"] - else: - self.initial_layout = Layout.generate_trivial_layout(*dag.qregs.values()) - - if len(dag.qubits) != len(self.initial_layout): - raise TranspilerError("The layout does not match the amount of qubits in the DAG") - - if len(self.coupling_map.physical_qubits) != len(self.initial_layout): - raise TranspilerError( - "Mappers require to have the layout to be the same size as the coupling map" - ) - - canonical_register = dag.qregs["q"] - trivial_layout = Layout.generate_trivial_layout(canonical_register) - current_layout = trivial_layout.copy() - - subdags = [] - for layer in dag.layers(): - graph = layer["graph"] - cxs = graph.op_nodes(op=CXGate) - if len(cxs) > 0: - for cx in cxs: - qubit_1 = current_layout[cx.qargs[0]] - qubit_2 = current_layout[cx.qargs[1]] - for qubit in range(dag.num_qubits()): - dep_param = decr_dep_param(qubit, qubit_1, qubit_2, self.coupling_map) - graph.apply_operation_back( - depolarizing_error(dep_param, 1).to_instruction(), - qargs=[canonical_register[qubit]], - cargs=[], - ) - subdags.append(graph) - - err_dag = dag.copy_empty_like() - for subdag in subdags: - err_dag.compose(subdag) - - return err_dag - - -class NoiseSimulator(AerSimulator): - """Quantum device simulator that has nonlocal CX errors""" - - def run(self, circuits, validate=False, parameter_binds=None, **run_options): - """Applies transpiler pass NonlocalCXDepError to circuits run on this backend""" - pm = PassManager() - cm = CouplingMap(couplinglist=self.configuration().coupling_map) - pm.append([NonlocalCXDepError(cm)]) - noise_circuits = pm.run(circuits) - return super().run( - noise_circuits, validate=validate, parameter_binds=parameter_binds, **run_options - ) - - -@ddt -class TestMirrorRB(RBTestCase): - """Test for mirror RB.""" - - def test_single_qubit(self): - """Test single qubit mirror RB.""" - exp = rb.MirrorRB( - qubits=(0,), - lengths=list(range(2, 300, 20)), - seed=124, - backend=self.backend, - num_samples=30, - ) - # exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**self.transpiler_options) - self.assertAllIdentity(exp.circuits()) - - expdata = exp.run() - self.assertExperimentDone(expdata) - - # Given we have gate number per Clifford n_gpc, we can compute EPC as - # EPC = 1 - (1 - r)^n_gpc - # where r is gate error of SX gate, i.e. dep-parameter divided by 2. - # We let transpiler use SX and RZ. - # The number of physical gate per Clifford will distribute - # 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. - # But for mirror RB, we must also add the SX gate number per Pauli n_gpp, - # which is 2 for X and Y gates and 0 for I and Z gates (average = 1.0). So the - # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 - epc = expdata.analysis_results("EPC") - - epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - - def test_two_qubit(self): - """Test two qubit RB.""" - two_qubit_gate_density = 0.2 - exp = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 300, 20)), - seed=123, - backend=self.backend, - num_samples=30, - two_qubit_gate_density=two_qubit_gate_density, - ) - exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**self.transpiler_options) - self.assertAllIdentity(exp.circuits()) - - expdata = exp.run() - self.assertExperimentDone(expdata) - - # Given a two qubit gate density xi and an n qubit circuit, a Clifford - # layer has n*xi two-qubit gates. Obviously a Pauli has no two-qubit - # gates, so on aveage, a Clifford + Pauli layer has n*xi two-qubit gates - # and 2*n - 2*n*xi one-qubit gates (two layers have 2*n lattice sites, - # 2*n*xi of which are occupied by two-qubit gates). For two-qubit - # mirrored RB, the average infidelity is ((2^2 - 1)/2^2 = 3/4) times - # the two-qubit depolarizing parameter - epc = expdata.analysis_results("EPC") - cx_factor = (1 - 3 * self.p2q / 4) ** (2 * two_qubit_gate_density) - sx_factor = (1 - self.p1q / 2) ** (2 * 2 * (1 - two_qubit_gate_density)) - epc_expected = 1 - cx_factor * sx_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - - def test_two_qubit_nonlocal_noise(self): - """Test for 2 qubit Mirrored RB with a nonlocal noise model""" - # depolarizing error - p1q = 0.0 - p2q = 0.01 - pvz = 0.0 - - # setup noise model - sx_error = depolarizing_error(p1q, 1) - rz_error = depolarizing_error(pvz, 1) - cx_error = depolarizing_error(p2q, 2) - - noise_model = NoiseModel() - noise_model.add_all_qubit_quantum_error(sx_error, "sx") - noise_model.add_all_qubit_quantum_error(rz_error, "rz") - noise_model.add_all_qubit_quantum_error(cx_error, "cx") - - basis_gates = ["id", "sx", "rz", "cx"] - # Need level1 for consecutive gate cancellation for reference EPC value calculation - transpiler_options = { - "basis_gates": basis_gates, - "optimization_level": 1, - } - # Coupling map is 3 x 3 lattice - noise_backend = NoiseSimulator( - noise_model=noise_model, - seed_simulator=123, - coupling_map=CouplingMap.from_grid(3, 3).get_edges(), - ) - - two_qubit_gate_density = 0.2 - exp = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 110, 20)), - seed=123, - backend=noise_backend, - num_samples=20, - two_qubit_gate_density=two_qubit_gate_density, - ) - exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**transpiler_options) - self.assertAllIdentity(exp.circuits()) - expdata = exp.run(noise_backend) - self.assertExperimentDone(expdata) - - epc = expdata.analysis_results("EPC") - # Compared to expected EPC in two-qubit test without nonlocal noise above, - # we include an extra factor for the nonlocal CX error. This nonlocal - # error is modeled by a one-qubit depolarizing channel on each qubit after - # each CX, so the expected number of one-qubit depolarizing channels - # induced by CXs is (number of CXs) * (number of qubits) = (two qubit gate - # density) * (number of qubits) * (number of qubits). - num_q = 2 - cx_factor = (1 - 3 * p2q / 4) ** (num_q * two_qubit_gate_density) - sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) - cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) - epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - - def test_three_qubit_nonlocal_noise(self): - """Test three-qubit mirrored RB on a nonlocal noise model""" - # depolarizing error - p1q = 0.001 - p2q = 0.01 - pvz = 0.0 - - # setup noise modelle - sx_error = depolarizing_error(p1q, 1) - rz_error = depolarizing_error(pvz, 1) - cx_error = depolarizing_error(p2q, 2) - - noise_model = NoiseModel() - noise_model.add_all_qubit_quantum_error(sx_error, "sx") - noise_model.add_all_qubit_quantum_error(rz_error, "rz") - noise_model.add_all_qubit_quantum_error(cx_error, "cx") - - basis_gates = ["id", "sx", "rz", "cx"] - # Need level1 for consecutive gate cancellation for reference EPC value calculation - transpiler_options = { - "basis_gates": basis_gates, - "optimization_level": 1, - } - noise_backend = NoiseSimulator( - noise_model=noise_model, - seed_simulator=123, - coupling_map=CouplingMap.from_grid(3, 3).get_edges(), - ) - - two_qubit_gate_density = 0.2 - exp = rb.MirrorRB( - qubits=(0, 1, 2), - lengths=list(range(2, 110, 50)), - seed=123, - backend=noise_backend, - num_samples=20, - two_qubit_gate_density=two_qubit_gate_density, - ) - exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**transpiler_options) - self.assertAllIdentity(exp.circuits()) - expdata = exp.run(noise_backend) - self.assertExperimentDone(expdata) - - epc = expdata.analysis_results("EPC") - # The expected EPC was computed in simulations not presented here. - # Method: - # 1. Sample N Clifford layers according to the edgegrab algorithm - # in clifford_utils. - # 2. Transpile these into SX, RZ, and CX gates. - # 3. Replace each SX and CX with one- and two-qubit depolarizing - # channels, respectively, and remove RZ gates. - # 4. Use qiskit.quantum_info.average_gate_fidelity on these N layers - # to compute 1 - EPC for each layer, and average over the N layers. - epc_expected = 0.0124 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) - - def test_add_more_circuit_yields_lower_variance(self): - """Test variance reduction with larger number of sampling.""" - exp1 = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 30, 4)), - seed=123, - backend=self.backend, - num_samples=3, - inverting_pauli_layer=False, - ) - exp1.analysis.set_options(gate_error_ratio=None) - exp1.set_transpile_options(**self.transpiler_options) - expdata1 = exp1.run() - self.assertExperimentDone(expdata1) - - exp2 = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 30, 4)), - seed=456, - backend=self.backend, - num_samples=10, - inverting_pauli_layer=False, - ) - exp2.analysis.set_options(gate_error_ratio=None) - exp2.set_transpile_options(**self.transpiler_options) - expdata2 = exp2.run() - self.assertExperimentDone(expdata2) - - self.assertLess( - expdata2.analysis_results("EPC").value.s, - expdata1.analysis_results("EPC").value.s, - ) - - def test_return_same_circuit(self): - """Test if setting the same seed returns the same circuits.""" - lengths = [10, 20] - exp1 = rb.MirrorRB( - qubits=(0, 1), - lengths=lengths, - seed=123, - backend=self.backend, - ) - - exp2 = rb.MirrorRB( - qubits=(0, 1), - lengths=lengths, - seed=123, - backend=self.backend, - ) - - circs1 = exp1.circuits() - circs2 = exp2.circuits() - - for circ1, circ2 in zip(circs1, circs2): - self.assertEqual(circ1.decompose(), circ2.decompose()) - - def test_full_sampling(self): - """Test if full sampling generates different circuits.""" - exp1 = rb.MirrorRB( - qubits=(0, 1), - lengths=[10, 20], - seed=123, - backend=self.backend, - num_samples=1, - full_sampling=True, - ) - - exp2 = rb.MirrorRB( - qubits=(0, 1), - lengths=[10, 20], - seed=123, - backend=self.backend, - num_samples=1, - full_sampling=False, - ) - - circs1 = exp1.circuits() - circs2 = exp2.circuits() - - self.assertNotEqual(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()) - - def test_target_bitstring(self): - """Test if correct target bitstring is returned.""" - qc = QuantumCircuit(9) - qc.z(0) - qc.y(1) - qc.y(2) - qc.z(3) - qc.y(4) - qc.x(7) - qc.y(8) - exp = rb.MirrorRB(qubits=[0], lengths=[2], backend=self.backend) - expected_tb = exp._clifford_utils.compute_target_bitstring(qc) - actual_tb = "110010110" - self.assertEqual(expected_tb, actual_tb) - - def test_zero_2q_gate_density(self): - """Test that there are no two-qubit gates when the two-qubit gate - density is set to 0.""" - exp = rb.MirrorRB( - qubits=(0, 1), - lengths=[40], - seed=124, - backend=self.backend, - num_samples=1, - two_qubit_gate_density=0, - ) - circ = exp.circuits()[0].decompose() - for datum in circ.data: - inst_name = datum[0].name - self.assertNotEqual("cx", inst_name) - - def test_max_2q_gate_density(self): - """Test that every intermediate Clifford layer is filled with two-qubit - gates when the two-qubit gate density is set to 0.5, its maximum value - (assuming an even number of qubits and a backend coupling map with full - connectivity).""" - backend = AerSimulator(coupling_map=CouplingMap.from_full(4).get_edges()) - exp = rb.MirrorRB( - qubits=(0, 1, 2, 3), - lengths=[40], - seed=125, - backend=backend, - num_samples=1, - two_qubit_gate_density=0.5, - ) - circ = exp.circuits()[0].decompose() - num_cxs = 0 - for datum in circ.data: - if datum[0].name == "cx": - num_cxs += 1 - self.assertEqual(80, num_cxs) - - def test_local_clifford(self): - """Test that the number of layers is correct depending on whether - local_clifford is set to True or False by counting the number of barriers.""" - exp = rb.MirrorRB( - qubits=(0,), - lengths=[2], - seed=126, - backend=self.backend, - num_samples=1, - local_clifford=True, - pauli_randomize=False, - two_qubit_gate_density=0.2, - inverting_pauli_layer=False, - ) - circ = exp.circuits()[0] - num_barriers = 0 - for datum in circ.data: - if datum[0].name == "barrier": - num_barriers += 1 - self.assertEqual(5, num_barriers) - - def test_pauli_randomize(self): - """Test that the number of layers is correct depending on whether - pauli_randomize is set to True or False by counting the number of barriers.""" - exp = rb.MirrorRB( - qubits=(0,), - lengths=[2], - seed=126, - backend=self.backend, - num_samples=1, - local_clifford=False, - pauli_randomize=True, - two_qubit_gate_density=0.2, - inverting_pauli_layer=False, - ) - circ = exp.circuits()[0] - num_barriers = 0 - for datum in circ.data: - if datum[0].name == "barrier": - num_barriers += 1 - self.assertEqual(6, num_barriers) - - def test_inverting_pauli_layer(self): - """Test that a circuit with an inverting Pauli layer at the end (i.e., - a layer of Paulis before the final measurement that restores the output - to |0>^num_qubits up to a global phase) composes to the identity (up to - a global phase)""" - exp = rb.MirrorRB( - qubits=(0, 1, 2), - lengths=[2], - seed=127, - backend=self.backend, - num_samples=3, - local_clifford=True, - pauli_randomize=True, - two_qubit_gate_density=0.2, - inverting_pauli_layer=True, - ) - self.assertAllIdentity(exp.circuits()) - - @data( - { - "qubits": [3, 3], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # repeated qubits - { - "qubits": [0, 1], - "lengths": [2, 4, 6, -8, 10], - "num_samples": 1, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # negative length - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": -4, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # negative number of samples - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 0, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # zero samples - { - "qubits": [0, 1], - "lengths": [2, 6, 6, 6, 10], - "num_samples": 2, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # repeated lengths - { - "qubits": [0, 1], - "lengths": [2, 4, 5, 8, 10], - "num_samples": 2, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # odd length - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "two_qubit_gate_density": -0.1, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # negative two-qubit gate density - ) - def test_invalid_configuration(self, configs): - """Test raise error when creating experiment with invalid configs.""" - self.assertRaises(QiskitError, rb.MirrorRB, **configs) - - @data( - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "backend": None, - }, # no backend - ) - def test_no_backend(self, configs): - """Test raise error when no backend is provided for sampling circuits.""" - mirror_exp = rb.MirrorRB(**configs) - self.assertRaises(QiskitError, mirror_exp.run) - - @data( - { - "qubits": [0, 25], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "backend": AerSimulator.from_backend(FakeParis()), - }, # Uncoupled qubits to test edgegrab algorithm warning - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "two_qubit_gate_density": 0.6, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # High two-qubit gate density warning - ) - def test_warnings(self, configs): - """Test raise warnings when creating experiment.""" - mirror_exp = rb.MirrorRB(**configs) - self.assertWarns(Warning, mirror_exp.run) - - def test_experiment_config(self): - """Test converting to and from config works""" - exp = rb.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123, backend=self.backend) - loaded_exp = rb.MirrorRB.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.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123) - self.assertRoundTripSerializable(exp, self.json_equiv) - - def test_analysis_config(self): - """ "Test converting analysis to and from config works""" - analysis = RBAnalysis() - loaded = RBAnalysis.from_config(analysis.config()) - self.assertNotEqual(analysis, loaded) - self.assertEqual(analysis.config(), loaded.config()) - - def test_expdata_serialization(self): - """Test serializing experiment data works.""" - exp = rb.MirrorRB( - qubits=(0,), - lengths=list(range(2, 200, 50)), - seed=123, - backend=self.backend, - inverting_pauli_layer=False, - ) - exp.set_transpile_options(**self.transpiler_options) - expdata = exp.run() - self.assertExperimentDone(expdata) - self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) - self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) - - -@ddt -class TestStandardRB(RBTestCase): - """Test for standard RB.""" - - def test_single_qubit(self): - """Test single qubit RB.""" - 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()) - - expdata = exp.run() - self.assertExperimentDone(expdata) - - # Given we have gate number per Clifford n_gpc, we can compute EPC as - # EPC = 1 - (1 - r)^n_gpc - # where r is gate error of SX gate, i.e. dep-parameter divided by 2. - # We let transpiler use SX and RZ. - # The number of physical gate per Clifford will distribute - # 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") - - epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - - def test_two_qubit(self): - """Test two qubit RB.""" - exp = rb.StandardRB( - qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=123, - backend=self.backend, - ) - exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**self.transpiler_options) - self.assertAllIdentity(exp.circuits()) - - expdata = exp.run() - self.assertExperimentDone(expdata) - - # Given CX error is dominant and 1q error can be negligible. - # Arbitrary SU(4) can be decomposed with (0, 1, 2, 3) CX gates, the expected - # average number of CX gate per Clifford is 1.5. - # Since this is two qubit RB, the dep-parameter is factored by 3/4. - epc = expdata.analysis_results("EPC") - - # Allow for 50 percent tolerance since we ignore 1q gate contribution - epc_expected = 1 - (1 - 3 / 4 * self.p2q) ** 1.5 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) - - def test_add_more_circuit_yields_lower_variance(self): - """Test variance reduction with larger number of sampling.""" - exp1 = rb.StandardRB( - qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=123, - backend=self.backend, - num_samples=3, - ) - exp1.analysis.set_options(gate_error_ratio=None) - exp1.set_transpile_options(**self.transpiler_options) - expdata1 = exp1.run() - self.assertExperimentDone(expdata1) - - exp2 = rb.StandardRB( - qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=456, - backend=self.backend, - num_samples=5, - ) - exp2.analysis.set_options(gate_error_ratio=None) - exp2.set_transpile_options(**self.transpiler_options) - expdata2 = exp2.run() - self.assertExperimentDone(expdata2) - - self.assertLess( - expdata2.analysis_results("EPC").value.s, - expdata1.analysis_results("EPC").value.s, - ) - - def test_poor_experiment_result(self): - """Test edge case that tail of decay is not sampled. - - This is a special case that fit outcome is very sensitive to initial guess. - Perhaps generated initial guess is close to a local minima. - """ - from qiskit.providers.fake_provider import FakeVigo - - backend = AerSimulator.from_backend(FakeVigo(), seed_simulator=123) - exp = rb.StandardRB( - qubits=(0,), - lengths=[100, 200, 300, 400], - seed=123, - backend=backend, - num_samples=5, - ) - exp.set_transpile_options(basis_gates=["x", "sx", "rz"], optimization_level=1) - expdata = exp.run() - self.assertExperimentDone(expdata) - - overview = expdata.analysis_results(0).value - # This yields bad fit due to poor data points, but still fit is not completely off. - self.assertLess(overview.reduced_chisq, 10) - - def test_return_same_circuit(self): - """Test if setting the same seed returns the same circuits.""" - exp1 = rb.StandardRB( - qubits=(0, 1), - lengths=[10, 20, 30], - seed=123, - backend=self.backend, - ) - - exp2 = rb.StandardRB( - qubits=(0, 1), - lengths=[10, 20, 30], - seed=123, - backend=self.backend, - ) - - circs1 = exp1.circuits() - circs2 = exp2.circuits() - - self.assertEqual(circs1[0].decompose(), circs2[0].decompose()) - self.assertEqual(circs1[1].decompose(), circs2[1].decompose()) - self.assertEqual(circs1[2].decompose(), circs2[2].decompose()) - - def test_full_sampling(self): - """Test if full sampling generates different circuits.""" - exp1 = rb.StandardRB( - qubits=(0, 1), - lengths=[10, 20, 30], - seed=123, - backend=self.backend, - full_sampling=False, - ) - - exp2 = rb.StandardRB( - qubits=(0, 1), - 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()) - - @data( - {"qubits": [3, 3], "lengths": [1, 3, 5, 7, 9], "num_samples": 1, "seed": 100}, - {"qubits": [0, 1], "lengths": [1, 3, 5, -7, 9], "num_samples": 1, "seed": 100}, - {"qubits": [0, 1], "lengths": [1, 3, 5, 7, 9], "num_samples": -4, "seed": 100}, - {"qubits": [0, 1], "lengths": [1, 3, 5, 7, 9], "num_samples": 0, "seed": 100}, - {"qubits": [0, 1], "lengths": [1, 5, 5, 5, 9], "num_samples": 2, "seed": 100}, - ) - def test_invalid_configuration(self, configs): - """Test raise error when creating experiment with invalid configs.""" - self.assertRaises(QiskitError, rb.StandardRB, **configs) - - def test_experiment_config(self): - """Test converting to and from config works""" - 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) - self.assertRoundTripSerializable(exp, self.json_equiv) - - def test_analysis_config(self): - """ "Test converting analysis to and from config works""" - analysis = rb.RBAnalysis() - loaded = rb.RBAnalysis.from_config(analysis.config()) - self.assertNotEqual(analysis, loaded) - self.assertEqual(analysis.config(), loaded.config()) - - def test_expdata_serialization(self): - """Test serializing experiment data works.""" - exp = rb.StandardRB( - qubits=(0,), - lengths=list(range(1, 200, 50)), - seed=123, - backend=self.backend, - ) - exp.set_transpile_options(**self.transpiler_options) - expdata = exp.run() - self.assertExperimentDone(expdata) - self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) - self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) - - -@ddt -class TestInterleavedRB(RBTestCase): - """Test for interleaved RB.""" - - @data([XGate(), [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 - 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 - ) - - 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 - - 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, - ) - exp.set_transpile_options(**self.transpiler_options) - 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) - - def test_two_qubit(self): - """Test two qubit IRB.""" - exp = rb.InterleavedRB( - interleaved_element=CXGate(), - qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=123, - backend=self.backend, - ) - exp.set_transpile_options(**self.transpiler_options) - 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 = 3 / 4 * self.p2q - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - - def test_non_clifford_interleaved_element(self): - """Verifies trying to run interleaved RB with non Clifford element throws an exception""" - qubits = 1 - lengths = [1, 4, 6, 9, 13, 16] - interleaved_element = TGate() # T gate is not Clifford, this should fail - self.assertRaises( - QiskitError, - rb.InterleavedRB, - interleaved_element=interleaved_element, - qubits=qubits, - lengths=lengths, - ) - - def test_interleaving_delay(self): - """Test delay instruction can be interleaved.""" - # See qiskit-experiments/#727 for details - interleaved_element = Delay(10, unit="us") - exp = rb.InterleavedRB( - interleaved_element, - qubits=[0], - lengths=[1], - num_samples=1, - ) - # Not raises an error - _, int_circ = exp.circuits() - - # barrier, clifford, barrier, "delay", barrier, ... - self.assertEqual(int_circ.data[3][0], interleaved_element) - - def test_interleaving_circuit_with_delay(self): - """Test circuit with delay can be interleaved.""" - delay_qc = QuantumCircuit(2) - delay_qc.delay(10, [0], unit="us") - delay_qc.x(1) - - exp = rb.InterleavedRB( - interleaved_element=delay_qc, qubits=[1, 2], lengths=[1], seed=123, num_samples=1 - ) - _, int_circ = exp.circuits() - - qc = QuantumCircuit(2) - qc.x(1) - expected_inversion = Clifford(int_circ.data[1][0]).compose(qc).adjoint() - # barrier, clifford, barrier, "interleaved circuit", barrier, inversion, ... - self.assertEqual(expected_inversion, Clifford(int_circ.data[5][0])) - - 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 - ) - loaded_exp = rb.InterleavedRB.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.InterleavedRB( - interleaved_element=SXGate(), qubits=(0,), lengths=[10, 20, 30], seed=123 - ) - self.assertRoundTripSerializable(exp, self.json_equiv) - - def test_analysis_config(self): - """ "Test converting analysis to and from config works""" - analysis = rb.InterleavedRBAnalysis() - loaded = rb.InterleavedRBAnalysis.from_config(analysis.config()) - self.assertNotEqual(analysis, loaded) - self.assertEqual(analysis.config(), loaded.config()) - - def test_expdata_serialization(self): - """Test serializing experiment data works.""" - exp = rb.InterleavedRB( - interleaved_element=SXGate(), - qubits=(0,), - lengths=list(range(1, 200, 50)), - seed=123, - backend=self.backend, - ) - exp.set_transpile_options(**self.transpiler_options) - expdata = exp.run() - self.assertExperimentDone(expdata) - self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) - self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) - - -class TestEPGAnalysis(QiskitExperimentsTestCase): - """Test case for EPG colculation from EPC. - EPG and depplarizing probability p are assumed to have following relationship - EPG = (2^n - 1) / 2^n · p - This p is provided to the Aer noise model, thus we verify EPG computation - by comparing the value with the depolarizing probability. - """ - - def setUp(self): - """Setup the tests.""" - super().setUp() - - # Setup noise model, including more gate for complicated EPG computation - # Note that 1Q channel error is amplified to check 1q channel correction mechanism - x_error = depolarizing_error(0.04, 1) - h_error = depolarizing_error(0.02, 1) - s_error = depolarizing_error(0.00, 1) - cx_error = depolarizing_error(0.08, 2) - - noise_model = NoiseModel() - noise_model.add_all_qubit_quantum_error(x_error, "x") - noise_model.add_all_qubit_quantum_error(h_error, "h") - noise_model.add_all_qubit_quantum_error(s_error, "s") - noise_model.add_all_qubit_quantum_error(cx_error, "cx") - - # Need level1 for consecutive gate cancellation for reference EPC value calculation - transpiler_options = { - "basis_gates": ["x", "h", "s", "cx"], - "optimization_level": 1, - } - - # Aer simulator - backend = AerSimulator(noise_model=noise_model, seed_simulator=123) - - # Prepare experiment data and cache for analysis - exp_1qrb_q0 = rb.StandardRB( - qubits=(0,), - lengths=[1, 10, 30, 50, 80, 120, 150, 200], - seed=123, - backend=backend, - ) - 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, - ) - exp_1qrb_q1.set_transpile_options(**transpiler_options) - expdata_1qrb_q1 = exp_1qrb_q1.run(analysis=None).block_for_results(timeout=300) - - exp_2qrb = rb.StandardRB( - qubits=(0, 1), - lengths=[1, 3, 5, 10, 15, 20, 30, 50], - seed=123, - backend=backend, - ) - exp_2qrb.set_transpile_options(**transpiler_options) - expdata_2qrb = exp_2qrb.run(analysis=None).block_for_results(timeout=300) - - self.expdata_1qrb_q0 = expdata_1qrb_q0 - self.expdata_1qrb_q1 = expdata_1qrb_q1 - self.expdata_2qrb = expdata_2qrb - - def test_default_epg_ratio(self): - """Calculate EPG with default ratio dictionary. H and X have the same ratio.""" - analysis = rb.RBAnalysis() - analysis.set_options(outcome="0") - result = analysis.run(self.expdata_1qrb_q0, replace_results=False) - self.assertExperimentDone(result) - - s_epg = result.analysis_results("EPG_s") - h_epg = result.analysis_results("EPG_h") - x_epg = result.analysis_results("EPG_x") - - self.assertEqual(s_epg.value.n, 0.0) - - # H and X gate EPG are assumed to be the same, so this underestimate X and overestimate H - self.assertEqual(h_epg.value.n, x_epg.value.n) - self.assertLess(x_epg.value.n, 0.04 * 0.5) - self.assertGreater(h_epg.value.n, 0.02 * 0.5) - - def test_no_epg(self): - """Calculate no EPGs.""" - analysis = rb.RBAnalysis() - analysis.set_options(outcome="0", gate_error_ratio=None) - result = analysis.run(self.expdata_1qrb_q0, replace_results=False) - self.assertExperimentDone(result) - - with self.assertRaises(DbExperimentEntryNotFound): - result.analysis_results("EPG_s") - - with self.assertRaises(DbExperimentEntryNotFound): - result.analysis_results("EPG_h") - - with self.assertRaises(DbExperimentEntryNotFound): - result.analysis_results("EPG_x") - - def test_with_custom_epg_ratio(self): - """Calculate no EPGs with custom EPG ratio dictionary.""" - analysis = rb.RBAnalysis() - analysis.set_options(outcome="0", gate_error_ratio={"x": 2, "h": 1, "s": 0}) - result = analysis.run(self.expdata_1qrb_q0, replace_results=False) - self.assertExperimentDone(result) - - h_epg = result.analysis_results("EPG_h") - x_epg = result.analysis_results("EPG_x") - - self.assertAlmostEqual(x_epg.value.n, 0.04 * 0.5, delta=0.005) - self.assertAlmostEqual(h_epg.value.n, 0.02 * 0.5, delta=0.005) - - def test_2q_epg(self): - """Compute 2Q EPG without correction. - Since 1Q gates are designed to have comparable EPG with CX gate, - this will overestimate the error of CX gate. - """ - analysis = rb.RBAnalysis() - analysis.set_options(outcome="00") - result = analysis.run(self.expdata_2qrb, replace_results=False) - self.assertExperimentDone(result) - - cx_epg = result.analysis_results("EPG_cx") - - self.assertGreater(cx_epg.value.n, 0.08 * 0.75) - - def test_correct_1q_depolarization(self): - """Compute 2Q EPG with 1Q depolarization correction.""" - analysis_1qrb_q0 = rb.RBAnalysis() - analysis_1qrb_q0.set_options(outcome="0", gate_error_ratio={"x": 2, "h": 1, "s": 0}) - result_q0 = analysis_1qrb_q0.run(self.expdata_1qrb_q0, replace_results=False) - self.assertExperimentDone(result_q0) - - analysis_1qrb_q1 = rb.RBAnalysis() - analysis_1qrb_q1.set_options(outcome="0", gate_error_ratio={"x": 2, "h": 1, "s": 0}) - result_q1 = analysis_1qrb_q1.run(self.expdata_1qrb_q1, replace_results=False) - self.assertExperimentDone(result_q1) - - analysis_2qrb = rb.RBAnalysis() - analysis_2qrb.set_options( - outcome="00", - epg_1_qubit=result_q0.analysis_results() + result_q1.analysis_results(), - ) - result_2qrb = analysis_2qrb.run(self.expdata_2qrb) - self.assertExperimentDone(result_2qrb) - - cx_epg = result_2qrb.analysis_results("EPG_cx") - self.assertAlmostEqual(cx_epg.value.n, 0.08 * 0.75, delta=0.006) From 961068d44e15f9b9649cb2aee094618c0d01a961 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Mon, 13 Mar 2023 22:53:19 -0400 Subject: [PATCH 28/56] update docs and remove edgegrab from utils --- docs/conf.py | 1 + .../mirror_randomized_benchmarking.rst | 108 +- .../randomized_benchmarking/clifford_utils.py | 90 +- .../mirror_rb_analysis.py | 16 +- .../mirror_rb_experiment.py | 187 ++- .../randomized_benchmarking/rb_experiment.py | 13 +- .../randomized_benchmarking/sampling_utils.py | 13 +- .../test_randomized_benchmarking.py | 1285 +++++++++-------- 8 files changed, 881 insertions(+), 832 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a2bf64b712..ed5738c50e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -192,6 +192,7 @@ intersphinx_mapping = { "matplotlib": ("https://matplotlib.org/stable/", None), "qiskit": ("https://qiskit.org/documentation/", None), + "pygsti": ("https://pygsti.readthedocs.io/en/latest/", None), } diff --git a/docs/tutorials/mirror_randomized_benchmarking.rst b/docs/tutorials/mirror_randomized_benchmarking.rst index dda59919be..48d666d2bf 100644 --- a/docs/tutorials/mirror_randomized_benchmarking.rst +++ b/docs/tutorials/mirror_randomized_benchmarking.rst @@ -19,20 +19,15 @@ Because the Clifford gates are only one- and two-qubit, unlike in standard RB, w requires the implementation of n-qubit Cliffords, mirror RB ????. Mirror RB can also be generalized to universal gatesets beyond the Cliffords [2]_. -Running a Mirror RB experiment ------------------------------- - -Even though a `MirrorRB` experiment can be instantiated without a backend, the -backend must be specified when the circuits are sampled because :math:`\Omega` -depends on the backend's connectivity. +Output metrics +-------------- -In standard and interleaved RB, $n$-qubit circuits of varying lengths -:math:`\ell` that compose to the identity are run on a device, and the -**success probability** $P$, the probability that the circuit's output bit -string equals the input bit string, is estimated for each circuit length by -running several circuits at each length. The :math:`P`-versus-:math:`\ell` -curve is fit to the function :math:`A\alpha^\ell + b`, and the error per -Clifford (EPC) (the average infidelity) is estimated using +In standard and interleaved RB, :math:`n`-qubit circuits of varying lengths :math:`\ell` +that compose to the identity are run on a device, and the **success probability** +:math:`P`, the probability that the circuit's output bit string equals the input bit +string, is estimated for each circuit length by running several circuits at each length. +The :math:`P`-versus-:math:`\ell` curve is fit to the function :math:`A\alpha^\ell + b`, +and the error per Clifford (EPC) (the average infidelity) is estimated using .. math:: @@ -75,50 +70,62 @@ related by \epsilon_e = \left(1 + \frac{1}{2^n}\right) \epsilon_a, -where :math:`n` is the number of qubits (see Ref. [7]). +where :math:`n` is the number of qubits (see [2]_). -Running a one-qubit mirror RB experiment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Running a mirror RB experiment +------------------------------ + +The distribution for sampling layers, :math:`\Omega`, must be specified by the user when +instantiating a mirror RB experiment. A commonly used :math:`\Omega` is one generated by +the **edge grab** algorithm [3]_. The Clifford layers in :math:`\mathbb{L}` are +constructed from a gate set consisting of one-qubit Clifford gates and a single +two-qubit Clifford gate (e.g., CX) that can be applied to any two connected qubits. The +user can specify an expected two-qubit gate density :math:`\xi \in \left[0, +\frac{1}{2}\right]`, and each intermediate Clifford layer will have approximately +:math:`n \xi` CXs on average. + +Even though a :class:`.MirrorRB` experiment can be instantiated without a backend, the +backend must be specified when the circuits are sampled because :math:`\Omega` depends +on the backend's connectivity. Here is a typical way to instantiate and run the +experiment: .. jupyter-execute:: + import numpy as np + from qiskit_experiments.library import MirrorRB + from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler + lengths = np.arange(2, 810, 200) num_samples = 30 seed = 1010 qubits = (0,) - # Run a MRB experiment on qubit 0 + exp_2q = MirrorRB((0,1), + lengths=[4], + backend=backend, + num_samples=1, + seed=1010, + two_qubit_gate_density=.4, + distribution=EdgeGrabSampler) + exp_1q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) expdata_1q = exp_1q.run(backend).block_for_results() results_1q = expdata_1q.analysis_results() .. jupyter-execute:: - # View result data print("Gate error ratio: %s" % expdata_1q.experiment.analysis.options.gate_error_ratio) display(expdata_1q.figure(0)) for result in results_1q: print(result) -Running a two-qubit mirror RB experiment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In MRB experiments with :math:`n > 1` qubits, intermediate Clifford layers -are sampled according to the **edge grab** algorithm [3]_. The Clifford layers -in :math:`\mathbb{L}` are constructed from a gate set consisting of -one-qubit Clifford gates and a single two-qubit Clifford gate (e.g., -CX) that can be applied to any two connected qubits. The user can specify -an expected two-qubit gate density -:math:`\xi \in \left[0, \frac{1}{2}\right]`, and each intermediate Clifford -layer will have approximately :math:`n \xi` CXs on average. - .. jupyter-execute:: # Two-qubit circuit example exp_2q_circ = MirrorRB((0,1), lengths=[4], backend=backend, num_samples=1, seed=1010, two_qubit_gate_density=.4) - qc2 = exp_2q_circ.circuits()[0].decompose()#gates_to_decompose=['Clifford*','circuit*']) + qc2 = exp_2q_circ.circuits()[0].decompose() qc2.draw() .. jupyter-execute:: @@ -141,10 +148,20 @@ layer will have approximately :math:`n \xi` CXs on average. for result in results_2q: print(result) +Using your own custom :math:`\Omega` +------------------------------------ + +To use your own :math:`\Omega`, you have to implement your own subclass of the abstract +:class:`.MirrorRBSampler` class. + Selecting :math:`y`-axis values ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You can set what you want to use as the :math:`y`-axis metric for fitting by setting +the ``y-axis`` analysis option. Here's an example of plotting the success probability +instead of the default + .. jupyter-execute:: lengths = [2, 52, 102, 152] @@ -173,7 +190,7 @@ Selecting :math:`y`-axis values Mirror RB user options ~~~~~~~~~~~~~~~~~~~~~~ -Circuit generation options can be specified when a ``MirrorRB`` experiment +Circuit generation options can be specified when a :class:`.MirrorRB` experiment object is instantiated: - ``local_clifford`` (default ``True``): if ``True``, begin the circuit with @@ -197,11 +214,12 @@ Let's look at how these options change the circuit: Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``pyGSTi`` implementation of Mirror RB can be used for testing and -comparison. We note however that ``pyGSTi`` transpiles circuits slightly -differently, producing small discrepancies in fit parameters between the two -codes. To illustrate, consider the two circuits below, both of which were -generated in ``pyGSTi``. The first circuit was transpiled in ``pyGSTi``, +The :mod:`pygsti` implementation of Mirror RB, +:class:`~.pygsti.protocols.rb.MirrorRBDesign`, can be used for testing and comparison. +We note however that ``pyGSTi`` transpiles circuits slightly differently, producing +small discrepancies in fit parameters between the two codes. To illustrate, consider the +two circuits below, both of which were generated in ``pyGSTi``. The first circuit was +transpiled in ``pyGSTi``. .. image:: pygsti-data-pygsti-transpiled-circ.png @@ -215,14 +233,14 @@ qubit 0 in the fifth layer. References ---------- -[1]_ Timothy Proctor, Stefan Seritan, Kenneth Rudinger, Erik Nielsen, Robin -Blume-Kohout, Kevin Young, *Scalable randomized benchmarking of quantum -computers using mirror circuits*, https://arxiv.org/pdf/2112.09853.pdf +.. [1] Timothy Proctor, Stefan Seritan, Kenneth Rudinger, Erik Nielsen, Robin + Blume-Kohout, Kevin Young, *Scalable randomized benchmarking of quantum + computers using mirror circuits*, https://arxiv.org/pdf/2112.09853.pdf -[2]_ Hines, Jordan, et al. *Demonstrating scalable randomized benchmarking of universal gate -sets*, arXiv preprint arXiv:2207.07272 (2022). +.. [2] Hines, Jordan, et al. *Demonstrating scalable randomized benchmarking of + universal gate sets*, https://arxiv.org/abs/2207.07272 -[3]_ Timothy Proctor, Kenneth Rudinger, Kevin Young, Erik Nielsen, and Robin -Blume-Kohout, *Measuring the Capabilities of Quantum Computers*, -https://arxiv.org/pdf/2008.11294.pdf +.. [3] Timothy Proctor, Kenneth Rudinger, Kevin Young, Erik Nielsen, and Robin + Blume-Kohout, *Measuring the Capabilities of Quantum Computers*, + https://arxiv.org/pdf/2008.11294.pdf diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index dcd4028e3a..fa625b64a6 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -244,100 +244,12 @@ def random_clifford_circuits( return [random_clifford(num_qubits, seed=rng).to_circuit() for _ in range(size)] @classmethod - def random_edgegrab_clifford_circuits( - self, - qubits: Sequence[int], - coupling_map: list, - two_qubit_gate_density: float = 0.2, - size: int = 1, - rng: Optional[Union[int, Generator]] = None, - ) -> List[QuantumCircuit]: - """Generate a list of random Clifford circuits sampled using the edgegrab algorithm - - Args: - qubits: Sequence of integers representing the physical qubits - coupling_map: List of edges, where an edge is a list of 2 integers - two_qubit_gate_density: :math:`1/2` times the expected fraction of qubits with CX gates - size: length of RB sequence - rng: Random seed - - Raises: - Warning: If device has no connectivity or two_qubit_gate_density is too high - - Returns: - List of QuantumCircuits - - Ref: arXiv:2008.11294v2 - """ - num_qubits = len(qubits) - # if circuit has one qubit, call random_clifford_circuits() - if num_qubits == 1: - return self.random_clifford_circuits(num_qubits, size, rng) - - if rng is None: - rng = default_rng() - - if isinstance(rng, int): - rng = default_rng(rng) - - qc_list = [] - for _ in list(range(size)): - all_edges = coupling_map[:] # make copy of coupling map from which we pop edges - selected_edges = [] - while all_edges: - rand_edge = all_edges.pop(rng.integers(len(all_edges))) - selected_edges.append( - rand_edge - ) # move random edge from all_edges to selected_edges - old_all_edges = all_edges[:] - all_edges = [] - # only keep edges in all_edges that do not share a vertex with rand_edge - for edge in old_all_edges: - if rand_edge[0] not in edge and rand_edge[1] not in edge: - all_edges.append(edge) - - qr = QuantumRegister(num_qubits) - qc = QuantumCircuit(qr) - two_qubit_prob = 0 - try: - two_qubit_prob = num_qubits * two_qubit_gate_density / len(selected_edges) - except ZeroDivisionError: - warnings.warn( - "Device has no connectivity. All cliffords will be single-qubit Cliffords" - ) - if two_qubit_prob > 1: - warnings.warn( - "Mean number of two-qubit gates is higher than number of selected edges for CNOTs. " - + "Actual density of two-qubit gates will likely be lower than input density" - ) - selected_edges_logical = [ - [np.where(q == np.asarray(qubits))[0][0] for q in edge] for edge in selected_edges - ] - # selected_edges_logical is selected_edges with logical qubit labels rather than physical - # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] - # ==> selected_edges_logical = [[1,0],[4,2]] - put_1_qubit_clifford = np.arange(num_qubits) - # put_1_qubit_clifford is a list of qubits that aren't assigned to a 2-qubit Clifford - # 1-qubit Clifford will be assigned to these edges - for edge in selected_edges_logical: - if rng.random() < two_qubit_prob: - # with probability two_qubit_prob, place CNOT on edge in selected_edges - qc.cx(edge[0], edge[1]) - # remove these qubits from put_1_qubit_clifford - put_1_qubit_clifford = np.setdiff1d(put_1_qubit_clifford, edge) - for q in put_1_qubit_clifford: - clifford1q = self.clifford_1_qubit_circuit(rng.integers(24)) - insts = [datum[0] for datum in clifford1q.data] - for inst in insts: - qc.compose(inst, [q], inplace=True) - qc_list.append(qc) - return qc_list - @lru_cache(maxsize=24) def clifford_1_qubit_circuit(cls, num, basis_gates: Optional[Tuple[str, ...]] = None): """Return the 1-qubit clifford circuit corresponding to `num` where `num` is between 0 and 23. """ + print("1-qubit", num) unpacked = cls._unpack_num(num, cls.CLIFFORD_1_QUBIT_SIG) i, j, p = unpacked[0], unpacked[1], unpacked[2] qc = QuantumCircuit(1, name=f"Clifford-1Q({num})") diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index 0e2ca48c12..bedace05d6 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -120,7 +120,21 @@ def __init__(self): @classmethod def _default_options(cls): - """Default analysis options.""" + """Default analysis options. + + Analysis Options: + y_axis (str): Set the metric to plot on the y-axis. Must be one of + "Effective Polarization" (default), "Success Probability", or "Adjusted + Success Probability". + gate_error_ratio (Optional[Dict[str, float]]): A dictionary with gate name keys + and error ratio values used when calculating EPG from the estimated EPC. + The default value will use standard gate error ratios. + If you don't know accurate error ratio between your basis gates, + you can skip analysis of EPGs by setting this options to ``None``. + epg_1_qubit (List[AnalysisResult]): Analysis results from previous RB experiments + for individual single qubit gates. If this is provided, EPC of + 2Q RB is corrected to exclude the depolarization of underlying 1Q channels. + """ default_options = super()._default_options() # Set labels of axes diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 619e8b35c5..a8f99dc092 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -36,10 +36,11 @@ class MirrorRB(StandardRB): - """Mirror randomized benchmarking experiment. + """An experiment to measure gate infidelity using random mirrored layers of Clifford + and Pauli gates. # section: overview - Mirror Randomized Benchmarking (RB) is a method to estimate the average + Mirror randomized benchmarking (mirror RB) is a method to estimate the average error-rate of quantum gates that is more scalable than the standard RB methods. A mirror RB experiment generates circuits of layers of Cliffords interleaved @@ -49,12 +50,11 @@ class MirrorRB(StandardRB): a backend, various quantities (success probability, adjusted success probability, and effective polarization) are computed and used to fit an exponential decay curve and calculate the EPC (error per Clifford, also - referred to as the average gate infidelity) and entanglement infidelity. Find - more on adjusted success probability, effective polarization, and - entanglement infidelity in Refs. [1, 2, 3]. + referred to as the average gate infidelity) and entanglement infidelity (see + references for more info). # section: analysis_ref - :py:class:`MirrorRBAnalysis` + :class:`MirrorRBAnalysis` # section: reference .. ref_arxiv:: 1 2112.09853 @@ -83,25 +83,24 @@ def __init__( physical_qubits: A list of physical qubits for the experiment. lengths: A list of RB sequences lengths. distribution: The probability distribution over the layer set to sample. + Defaults to the :class:`.EdgeGrabSampler`. local_clifford: If True, begin the circuit with uniformly random 1-qubit - Cliffords and end the circuit with their inverses. + Cliffords and end the circuit with their inverses. pauli_randomize: If True, surround each inner Clifford layer with - uniformly random Paulis. + uniformly random Paulis. two_qubit_gate_density: Expected proportion of qubits with CNOTs based on - the backend coupling map. + the backend coupling map. backend: The backend to run the experiment on. - num_samples: Number of samples to generate for each - sequence length. + num_samples: Number of samples to generate for each sequence length. seed: Optional, seed used to initialize ``numpy.random.default_rng``. - when generating circuits. The ``default_rng`` will be initialized - with this seed value everytime :meth:`circuits` is called. + when generating circuits. The ``default_rng`` will be initialized + with this seed value everytime :meth:`circuits` is called. full_sampling: If True all Cliffords are independently sampled for - all lengths. If False for sample of lengths longer - sequences are constructed by appending additional - Clifford samples to shorter sequences. + all lengths. If False for sample of lengths longer sequences are + constructed by appending additional Clifford samples to shorter + sequences. inverting_pauli_layer: If True, a layer of Pauli gates is appended at the - end of the circuit to set all qubits to 0 (with - possibly a global phase) + end of the circuit to set all qubits to 0. Raises: QiskitError: if an odd length or a negative two qubit gate density is provided @@ -126,7 +125,12 @@ def __init__( self._clifford_utils = CliffordUtils() self._distribution = distribution() - self.set_experiment_options(distribution=distribution, local_clifford=local_clifford) + self.set_experiment_options( + distribution=distribution, + local_clifford=local_clifford, + pauli_randomize=pauli_randomize, + inverting_pauli_layer=inverting_pauli_layer, + ) self.analysis = MirrorRBAnalysis() @@ -139,6 +143,11 @@ def _default_experiment_options(cls) -> Options: Cliffords and end the circuit with their inverses. pauli_randomize (bool): Whether to surround each inner Clifford layer with uniformly random Paulis. + inverting_pauli_layer (bool): Whether to append a layer of Pauli gates at the + end of the circuit to set all qubits to 0 + two_qubit_gate_density (float): Expected proportion of two-qubit gates in + the mirror circuit layers (not counting Clifford or Pauli layers at the + start and end). lengths (List[int]): A list of RB sequences lengths. num_samples (int): Number of samples to generate for each sequence length. seed (None or int or SeedSequence or BitGenerator or Generator): A seed @@ -150,9 +159,11 @@ def _default_experiment_options(cls) -> Options: options.update_options( local_clifford=True, pauli_randomize=True, + two_qubit_gate_density=0.2, distribution=None, num_samples=None, seed=None, + inverting_pauli_layer=False, full_sampling=None, ) @@ -162,7 +173,7 @@ def circuits(self) -> List[QuantumCircuit]: """Return a list of Mirror RB circuits. Returns: - A list of :class:`QuantumCircuit`. + A list of :class:`QuantumCircuit`s. """ sequences = self._sample_sequences() circuits = self._sequences_to_circuits(sequences) @@ -182,9 +193,9 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: """Sample layers of mirror RB using the provided distribution and user options. First, layers are sampled using the distribution, then Pauli-dressed if ``pauli_randomize`` is ``True``. The inverse of the resulting circuit is - appended to the end. If ``local_clifford`` is True, then cliffords are added to - the beginning and end. If ``inverting_pauli_layer`` is ``True``, a Pauli layer - will be appended at the end to set the output bitstring to all zeros. + appended to the end. If ``local_clifford`` is ``True``, then cliffords are added + to the beginning and end. If ``inverting_pauli_layer`` is ``True``, a Pauli + layer will be appended at the end to set the output bitstring to all zeros. Raises: QiskitError: If no backend is provided. @@ -209,73 +220,44 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: for _ in range(self.experiment_options.num_samples): for length in self.experiment_options.lengths: + print("length ", length) + elements = [] # Sample Clifford layer elements for first half of mirror circuit - elements = self._distribution( - self.num_qubits, - self._two_qubit_gate_density, - self.coupling_map, - length // 2, - seed=self.experiment_options.seed, + # TODO need to adjust density if the paulis aren't in + elements.append( + self._distribution( + self.num_qubits, + self.experiment_options.two_qubit_gate_density, + self.coupling_map, + length // 2, + seed=self.experiment_options.seed, + )[0] ) # Append inverses of Clifford elements to second half of circuit for element in elements[::-1]: - elements.append(element.inverse()) + elements.append(self._adjoint_clifford(element)) # Interleave random Paulis if set by user - if self._pauli_randomize: - elements = self._pauli_dress(elements, rng) - element_lengths = [length * 2 + 1 for length in element_lengths] + if self.experiment_options.pauli_randomize: + elements = self._pauli_dress(elements) + # element_lengths = [length * 2 + 1 for length in element_lengths] # Add start and end local cliffords if set by user - if self._local_clifford: - elements = self._start_end_cliffords(elements, rng) - - mirror_circuits = self._generate_mirror(elements, element_lengths) - for circuit in mirror_circuits: - # Use "boolean arithmetic" to calculate xval correctly for each circuit - pauli_scale = self._pauli_randomize + 1 - clifford_const = self._local_clifford * 2 - circuit.metadata["xval"] = ( - circuit.metadata["xval"] - self._pauli_randomize - clifford_const - ) // pauli_scale - circuit.metadata["mirror"] = True - circuits += mirror_circuits - - sequences = [] - - # delete below - # Add start and end local cliffords if set by user - if self.experiment_options.local_clifford: - sequences = self._start_end_cliffords(sequences) - - if self.experiment_options.pauli_randomize: - elements = self._pauli_dress(elements) - - if self.experiment_options.full_sampling: - for _ in range(self.experiment_options.num_samples): - for length in self.experiment_options.lengths: - sequences.append( - self._distribution( - self.num_qubits, - self._two_qubit_gate_density, - self.coupling_map, - length // 2, - seed=self.experiment_options.seed, - ) - ) - else: - for _ in range(self.experiment_options.num_samples): - longest_seq = self._distribution( - self.num_qubits, - self.experiment_options._two_qubit_gate_density, - self.coupling_map, - max(self.experiment_options.lengths // 2), - seed=self.rng, - ) - for length in self.experiment_options.lengths: - sequences.append(longest_seq[:length]) - + if self.experiment_options.local_clifford: + elements = self._start_end_cliffords(elements) + + # mirror_circuits = self._generate_mirror(elements, element_lengths) + # for circuit in mirror_circuits: + # # Use "boolean arithmetic" to calculate xval correctly for each circuit + # pauli_scale = self._pauli_randomize + 1 + # clifford_const = self._local_clifford * 2 + # circuit.metadata["xval"] = ( + # circuit.metadata["xval"] - self._pauli_randomize - clifford_const + # ) // pauli_scale + # circuit.metadata["mirror"] = True + # circuits += mirror_circuits + sequences += [elements] return sequences def _sequences_to_circuits( @@ -288,14 +270,19 @@ def _sequences_to_circuits( """ basis_gates = self._get_basis_gates() # Circuit generation + print(sequences) circuits = [] for seq in sequences: circ = QuantumCircuit(self.num_qubits) for elem in seq: - circ.append(self._to_instruction(elem, basis_gates), circ.qubits) + print("elem", elem) + if isinstance(elem, Integral) or hasattr(elem, "to_instruction"): + circ.append(self._to_instruction(elem, basis_gates, 1), circ.qubits) + else: + circ.append(elem, circ.qubits) circ.append(Barrier(self.num_qubits), circ.qubits) - if self._inverting_pauli_layer: + if self.experiment_options.inverting_pauli_layer: # Get target bitstring (ideal bitstring outputted by the circuit) target = circ.metadata["target"] @@ -320,23 +307,31 @@ def _pauli_dress(self, element_list: List) -> List: The new list of elements with the Paulis interleaved. """ # Generate random Pauli - rand_pauli = random_pauli( - self._num_qubits, seed=self.experiment_options.seed - ).to_instruction() - rand_pauli_op = Clifford(rand_pauli) - new_element_list = [(rand_pauli, rand_pauli_op)] + # rand_pauli = random_pauli( + # self._num_qubits, seed=self.experiment_options.seed + # ).to_instruction() + # rand_pauli_op = Clifford(rand_pauli) + # new_element_list = [(rand_pauli, rand_pauli_op)] + # for element in element_list: + # new_element_list.append(element) + # rand_pauli = random_pauli( + # self._num_qubits, seed=self.experiment_options.seed + # ).to_instruction() + # rand_pauli_op = Clifford(rand_pauli) + # new_element_list.append((rand_pauli, rand_pauli_op)) + # return new_element_list + + rand_pauli = random_pauli(self._num_qubits, seed=self.experiment_options.seed) + new_element_list = [rand_pauli] for element in element_list: new_element_list.append(element) - rand_pauli = random_pauli( - self._num_qubits, seed=self.experiment_options.seed - ).to_instruction() - rand_pauli_op = Clifford(rand_pauli) - new_element_list.append((rand_pauli, rand_pauli_op)) + rand_pauli = random_pauli(self._num_qubits, seed=self.experiment_options.seed) + new_element_list.append(rand_pauli) return new_element_list def _start_end_cliffords(self, elements: Iterable[Clifford]) -> List[QuantumCircuit]: - """Add a layer of uniformly random 1-qubit Cliffords to the beginning of the list - and its inverse to the end of the list + """Add a layer of uniformly random 1-qubit Cliffords to the beginning of the list + and its inverse to the end of the list. Args: element_list: The list of elements we add the Clifford layers to @@ -345,6 +340,8 @@ def _start_end_cliffords(self, elements: Iterable[Clifford]) -> List[QuantumCirc Returns: The new list of elements with the start and end local (1-qubit) Cliffords. """ + # rng = default_rng(seed=self.experiment_options.seed) + # rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=self.experiment_options.num_qubits) rand_clifford = [ random_clifford(1, seed=self.experiment_options.seed) for _ in self.physical_qubits diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index f329436bd8..510123d27f 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -279,7 +279,7 @@ def _sequences_to_circuits( # Compute inverse, compute only the difference from the previous shorter sequence prev_elem = self.__compose_clifford_seq(prev_elem, seq[len(prev_seq) :]) prev_seq = seq - inv = self.__adjoint_clifford(prev_elem) + inv = self._adjoint_clifford(prev_elem) circ.append(self._to_instruction(inv, basis_gates), circ.qubits) circ.measure_all() # includes insertion of the barrier before measurement @@ -297,13 +297,16 @@ def __sample_sequence(self, length: int, rng: Generator) -> Sequence[SequenceEle return [random_clifford(self.num_qubits, rng).to_circuit() for _ in range(length)] def _to_instruction( - self, elem: SequenceElementType, basis_gates: Optional[Tuple[str, ...]] = None + self, + elem: SequenceElementType, + basis_gates: Optional[Tuple[str, ...]] = None, + gate_size=None, ) -> Instruction: # Switching for speed up if isinstance(elem, Integral): - if self.num_qubits == 1: + if self.num_qubits == 1 or gate_size == 1: return _clifford_1q_int_to_instruction(elem, basis_gates) - if self.num_qubits == 2: + if self.num_qubits == 2 or gate_size == 1: return _clifford_2q_int_to_instruction(elem, basis_gates) return elem.to_instruction() @@ -326,7 +329,7 @@ def __compose_clifford_seq( circ.compose(elem, inplace=True) return base_elem.compose(Clifford.from_circuit(circ)) - def __adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: + def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: if self.num_qubits == 1: return inverse_1q(op) if self.num_qubits == 2: diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 54ef4ffb3b..7f213fd889 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -64,12 +64,12 @@ class EdgeGrabSampler(MirrorRBSampler): graph, and the desired two-qubit gate density :math:`\xi`, outputs a layer as follows: - 1. Begin with the empty set :math:`E` and :math:`E_r`, the set of all - edges in the connectivity graph. Select an edge from :math:`E_r` at random - and add it to :math:`E`, removing all edges that share a qubit with the edge + 1. Begin with the empty set :math:`E` and :math:`E_r`, the set of all edges + in the connectivity graph. Select an edge from :math:`E_r` at random and + add it to :math:`E`, removing all edges that share a qubit with the edge from :math:`E_r`. - 2. Select edges from :math:`E` with the probability :math:`w\xi/|E|`. These edges will - have two-qubit gates in the output layer. + 2. Select edges from :math:`E` with the probability :math:`w\xi/|E|`. These + edges will have two-qubit gates in the output layer. This produces a layer with an expected two-qubit gate density :math:`2\xi`. Accounting for all the layers in mirror RB, this means the overall two-qubit gate @@ -106,7 +106,8 @@ def __call__( seed: Seed for random generation. Raises: - Warning: If device has no connectivity or two_qubit_gate_density is too high + Warning: If device has no connectivity or ``two_qubit_gate_density`` is too + high. TypeError: If invalid gate set(s) are specified. Returns: diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index d421297994..d421bc47b4 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -21,11 +21,13 @@ from qiskit.circuit import Delay, QuantumCircuit, Parameter, Gate from qiskit.circuit.library import SXGate, CXGate, TGate, CZGate from qiskit.exceptions import QiskitError -from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington +from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington, FakeParis from qiskit.pulse import Schedule, InstructionScheduleMap from qiskit.quantum_info import Operator from qiskit_aer import AerSimulator from qiskit_aer.noise import NoiseModel, depolarizing_error +from qiskit.transpiler.basepasses import TransformationPass +from qiskit.transpiler import Layout, PassManager, CouplingMap from qiskit_experiments.database_service.exceptions import ExperimentEntryNotFound from qiskit_experiments.framework.composite import ParallelExperiment from qiskit_experiments.library import randomized_benchmarking as rb @@ -472,34 +474,58 @@ def test_interleaving_cnot_gate_with_non_supported_direction(self): self.assertEqual(inst.qubits, expected_qubits) -class NoiseSimulator(AerSimulator): - """Quantum device simulator that has nonlocal CX errors""" +class RBRunTestCase(QiskitExperimentsTestCase, RBTestMixin): + """Base test case for running RB experiments defining a common noise model.""" - def run(self, circuits, validate=False, parameter_binds=None, **run_options): - """Applies transpiler pass NonlocalCXDepError to circuits run on this backend""" - pm = PassManager() - cm = CouplingMap(couplinglist=self.configuration().coupling_map) - pm.append([NonlocalCXDepError(cm)]) - noise_circuits = pm.run(circuits) - return super().run( - noise_circuits, validate=validate, parameter_binds=parameter_binds, **run_options - ) + def setUp(self): + """Setup the tests.""" + super().setUp() + # depolarizing error + self.p1q = 0.02 + self.p2q = 0.10 + self.pvz = 0.0 + self.pcz = 0.15 -@ddt -class TestMirrorRB(RBTestCase): - """Test for mirror RB.""" + # basis gates + self.basis_gates = ["rz", "sx", "cx"] + + # setup noise model + sx_error = depolarizing_error(self.p1q, 1) + rz_error = depolarizing_error(self.pvz, 1) + cx_error = depolarizing_error(self.p2q, 2) + cz_error = depolarizing_error(self.pcz, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + noise_model.add_all_qubit_quantum_error(cz_error, "cz") + + self.noise_model = noise_model + + # Need level1 for consecutive gate cancellation for reference EPC value calculation + self.transpiler_options = { + "basis_gates": self.basis_gates, + "optimization_level": 1, + } + + # Aer simulator + self.backend = AerSimulator(noise_model=noise_model, seed_simulator=123) + + +class TestRunStandardRB(RBRunTestCase): + """Test for running StandardRB.""" def test_single_qubit(self): - """Test single qubit mirror RB.""" - exp = rb.MirrorRB( - qubits=(0,), - lengths=list(range(2, 300, 20)), - seed=124, + """Test single qubit RB.""" + exp = rb.StandardRB( + physical_qubits=(0,), + lengths=list(range(1, 300, 30)), + seed=123, backend=self.backend, - num_samples=30, ) - # exp.analysis.set_options(gate_error_ratio=None) + exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) self.assertAllIdentity(exp.circuits()) @@ -513,183 +539,80 @@ def test_single_qubit(self): # The number of physical gate per Clifford will distribute # 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. - # But for mirror RB, we must also add the SX gate number per Pauli n_gpp, - # which is 2 for X and Y gates and 0 for I and Z gates (average = 1.0). So the - # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 epc = expdata.analysis_results("EPC") - epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 + epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) def test_two_qubit(self): - """Test two qubit RB.""" - two_qubit_gate_density = 0.2 - exp = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 300, 20)), + """Test two qubit RB. Use default basis gates.""" + exp = rb.StandardRB( + physical_qubits=(0, 1), + lengths=list(range(1, 30, 3)), seed=123, backend=self.backend, - num_samples=30, - two_qubit_gate_density=two_qubit_gate_density, ) exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**self.transpiler_options) + transpiler_options = {"optimization_level": 1} + exp.set_transpile_options(**transpiler_options) self.assertAllIdentity(exp.circuits()) expdata = exp.run() self.assertExperimentDone(expdata) - # Given a two qubit gate density xi and an n qubit circuit, a Clifford - # layer has n*xi two-qubit gates. Obviously a Pauli has no two-qubit - # gates, so on aveage, a Clifford + Pauli layer has n*xi two-qubit gates - # and 2*n - 2*n*xi one-qubit gates (two layers have 2*n lattice sites, - # 2*n*xi of which are occupied by two-qubit gates). For two-qubit - # mirrored RB, the average infidelity is ((2^2 - 1)/2^2 = 3/4) times - # the two-qubit depolarizing parameter + # Given CX error is dominant and 1q error can be negligible. + # Arbitrary SU(4) can be decomposed with (0, 1, 2, 3) CX gates, the expected + # average number of CX gate per Clifford is 1.5. + # Since this is two qubit RB, the dep-parameter is factored by 3/4. epc = expdata.analysis_results("EPC") - cx_factor = (1 - 3 * self.p2q / 4) ** (2 * two_qubit_gate_density) - sx_factor = (1 - self.p1q / 2) ** (2 * 2 * (1 - two_qubit_gate_density)) - epc_expected = 1 - cx_factor * sx_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - - def test_two_qubit_nonlocal_noise(self): - """Test for 2 qubit Mirrored RB with a nonlocal noise model""" - # depolarizing error - p1q = 0.0 - p2q = 0.01 - pvz = 0.0 - - # setup noise model - sx_error = depolarizing_error(p1q, 1) - rz_error = depolarizing_error(pvz, 1) - cx_error = depolarizing_error(p2q, 2) - - noise_model = NoiseModel() - noise_model.add_all_qubit_quantum_error(sx_error, "sx") - noise_model.add_all_qubit_quantum_error(rz_error, "rz") - noise_model.add_all_qubit_quantum_error(cx_error, "cx") - - basis_gates = ["id", "sx", "rz", "cx"] - # Need level1 for consecutive gate cancellation for reference EPC value calculation - transpiler_options = { - "basis_gates": basis_gates, - "optimization_level": 1, - } - # Coupling map is 3 x 3 lattice - noise_backend = NoiseSimulator( - noise_model=noise_model, - seed_simulator=123, - coupling_map=CouplingMap.from_grid(3, 3).get_edges(), - ) + # Allow for 50 percent tolerance since we ignore 1q gate contribution + epc_expected = 1 - (1 - 3 / 4 * self.p2q) ** 1.5 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) - two_qubit_gate_density = 0.2 - exp = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 110, 20)), + def test_three_qubit(self): + """Test two qubit RB. Use default basis gates.""" + exp = rb.StandardRB( + physical_qubits=(0, 1, 2), + lengths=list(range(1, 30, 3)), seed=123, - backend=noise_backend, - num_samples=20, - two_qubit_gate_density=two_qubit_gate_density, + backend=self.backend, ) exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**transpiler_options) + exp.set_transpile_options(**self.transpiler_options) self.assertAllIdentity(exp.circuits()) - expdata = exp.run(noise_backend) - self.assertExperimentDone(expdata) - - epc = expdata.analysis_results("EPC") - # Compared to expected EPC in two-qubit test without nonlocal noise above, - # we include an extra factor for the nonlocal CX error. This nonlocal - # error is modeled by a one-qubit depolarizing channel on each qubit after - # each CX, so the expected number of one-qubit depolarizing channels - # induced by CXs is (number of CXs) * (number of qubits) = (two qubit gate - # density) * (number of qubits) * (number of qubits). - num_q = 2 - cx_factor = (1 - 3 * p2q / 4) ** (num_q * two_qubit_gate_density) - sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) - cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) - epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - - def test_three_qubit_nonlocal_noise(self): - """Test three-qubit mirrored RB on a nonlocal noise model""" - # depolarizing error - p1q = 0.001 - p2q = 0.01 - pvz = 0.0 - - # setup noise modelle - sx_error = depolarizing_error(p1q, 1) - rz_error = depolarizing_error(pvz, 1) - cx_error = depolarizing_error(p2q, 2) - - noise_model = NoiseModel() - noise_model.add_all_qubit_quantum_error(sx_error, "sx") - noise_model.add_all_qubit_quantum_error(rz_error, "rz") - noise_model.add_all_qubit_quantum_error(cx_error, "cx") - - basis_gates = ["id", "sx", "rz", "cx"] - # Need level1 for consecutive gate cancellation for reference EPC value calculation - transpiler_options = { - "basis_gates": basis_gates, - "optimization_level": 1, - } - noise_backend = NoiseSimulator( - noise_model=noise_model, - seed_simulator=123, - coupling_map=CouplingMap.from_grid(3, 3).get_edges(), - ) - two_qubit_gate_density = 0.2 - exp = rb.MirrorRB( - qubits=(0, 1, 2), - lengths=list(range(2, 110, 50)), - seed=123, - backend=noise_backend, - num_samples=20, - two_qubit_gate_density=two_qubit_gate_density, - ) - exp.analysis.set_options(gate_error_ratio=None) - exp.set_transpile_options(**transpiler_options) - self.assertAllIdentity(exp.circuits()) - expdata = exp.run(noise_backend) + expdata = exp.run() self.assertExperimentDone(expdata) + # Given CX error is dominant and 1q error can be negligible. + # Arbitrary SU(8) can be decomposed with [0,...,7] CX gates, the expected + # average number of CX gate per Clifford is 3.5. + # Since this is three qubit RB, the dep-parameter is factored by 7/8. epc = expdata.analysis_results("EPC") - # The expected EPC was computed in simulations not presented here. - # Method: - # 1. Sample N Clifford layers according to the edgegrab algorithm - # in clifford_utils. - # 2. Transpile these into SX, RZ, and CX gates. - # 3. Replace each SX and CX with one- and two-qubit depolarizing - # channels, respectively, and remove RZ gates. - # 4. Use qiskit.quantum_info.average_gate_fidelity on these N layers - # to compute 1 - EPC for each layer, and average over the N layers. - epc_expected = 0.0124 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + # Allow for 50 percent tolerance since we ignore 1q gate contribution + epc_expected = 1 - (1 - 7 / 8 * self.p2q) ** 3.5 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) def test_add_more_circuit_yields_lower_variance(self): """Test variance reduction with larger number of sampling.""" - exp1 = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 30, 4)), + exp1 = rb.StandardRB( + physical_qubits=(0, 1), + lengths=list(range(1, 30, 3)), seed=123, backend=self.backend, num_samples=3, - inverting_pauli_layer=False, ) exp1.analysis.set_options(gate_error_ratio=None) exp1.set_transpile_options(**self.transpiler_options) expdata1 = exp1.run() self.assertExperimentDone(expdata1) - exp2 = rb.MirrorRB( - qubits=(0, 1), - lengths=list(range(2, 30, 4)), + exp2 = rb.StandardRB( + physical_qubits=(0, 1), + lengths=list(range(1, 30, 3)), seed=456, backend=self.backend, - num_samples=10, - inverting_pauli_layer=False, + num_samples=5, ) exp2.analysis.set_options(gate_error_ratio=None) exp2.set_transpile_options(**self.transpiler_options) @@ -701,21 +624,342 @@ def test_add_more_circuit_yields_lower_variance(self): expdata1.analysis_results("EPC").value.s, ) - def test_return_same_circuit(self): - """Test if setting the same seed returns the same circuits.""" - lengths = [10, 20] - exp1 = rb.MirrorRB( - qubits=(0, 1), - lengths=lengths, - seed=123, - backend=self.backend, - ) + def test_poor_experiment_result(self): + """Test edge case that tail of decay is not sampled. - exp2 = rb.MirrorRB( - qubits=(0, 1), - lengths=lengths, - seed=123, - backend=self.backend, + This is a special case that fit outcome is very sensitive to initial guess. + Perhaps generated initial guess is close to a local minima. + """ + from qiskit.providers.fake_provider import FakeVigoV2 + + backend = FakeVigoV2() + backend.set_options(seed_simulator=123) + # TODO: this test no longer makes sense (yields small reduced_chisq) + # after fixing how to call fake backend v2 (by adding the next line) + # Need to call target before running fake backend v2 to load correct data + self.assertLess(backend.target["sx"][(0,)].error, 0.001) + + exp = rb.StandardRB( + physical_qubits=(0,), + lengths=[100, 200, 300], + seed=123, + backend=backend, + num_samples=5, + ) + exp.set_transpile_options(basis_gates=["x", "sx", "rz"], optimization_level=1) + + expdata = exp.run() + self.assertExperimentDone(expdata) + overview = expdata.analysis_results(0).value + # This yields bad fit due to poor data points, but still fit is not completely off. + self.assertLess(overview.reduced_chisq, 14) + + def test_expdata_serialization(self): + """Test serializing experiment data works.""" + exp = rb.StandardRB( + physical_qubits=(0,), + lengths=list(range(1, 200, 50)), + seed=123, + backend=self.backend, + ) + exp.set_transpile_options(**self.transpiler_options) + expdata = exp.run() + self.assertExperimentDone(expdata) + 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.""" + physical_qubits = [0, 2] + lengths = list(range(1, 300, 30)) + exps = [] + for qubit in physical_qubits: + exp = rb.StandardRB( + physical_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(**self.transpiler_options) + + 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") + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_two_qubit_parallel(self): + """Test two qubit RB in parallel.""" + qubit_pairs = [[0, 1], [2, 3]] + lengths = list(range(5, 100, 5)) + exps = [] + for pair in qubit_pairs: + exp = rb.StandardRB( + physical_qubits=pair, 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(**self.transpiler_options) + + par_expdata = par_exp.run(backend=self.backend) + self.assertExperimentDone(par_expdata) + epc_expected = 1 - (1 - 3 / 4 * self.p2q) ** 1.5 + for i in range(2): + epc = par_expdata.child_data(i).analysis_results("EPC") + # Allow for 20 percent tolerance since we ignore 1q gate contribution + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + + def test_two_qubit_with_cz(self): + """Test two qubit RB.""" + transpiler_options = { + "basis_gates": ["sx", "rz", "cz"], + "optimization_level": 1, + } + + exp = rb.StandardRB( + physical_qubits=(0, 1), + lengths=list(range(1, 50, 5)), + seed=123, + backend=self.backend, + ) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**transpiler_options) + + expdata = exp.run() + self.assertAllIdentity(exp.circuits()) + self.assertExperimentDone(expdata) + + # Given CX error is dominant and 1q error can be negligible. + # Arbitrary SU(4) can be decomposed with (0, 1, 2, 3) CZ gates, the expected + # average number of CZ gate per Clifford is 1.5. + # Since this is two qubit RB, the dep-parameter is factored by 3/4. + epc = expdata.analysis_results("EPC") + + # Allow for 50 percent tolerance since we ignore 1q gate contribution + epc_expected = 1 - (1 - 3 / 4 * self.pcz) ** 1.5 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) + + +class TestRunInterleavedRB(RBRunTestCase): + """Test for running InterleavedRB.""" + + def test_single_qubit(self): + """Test single qubit IRB.""" + exp = rb.InterleavedRB( + interleaved_element=SXGate(), + physical_qubits=(0,), + lengths=list(range(1, 300, 30)), + seed=123, + backend=self.backend, + ) + exp.set_transpile_options(**self.transpiler_options) + 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) + + def test_two_qubit(self): + """Test two qubit IRB.""" + exp = rb.InterleavedRB( + interleaved_element=CXGate(), + physical_qubits=(0, 1), + lengths=list(range(1, 30, 3)), + seed=123, + backend=self.backend, + ) + exp.set_transpile_options(**self.transpiler_options) + 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 = 3 / 4 * self.p2q + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + + def test_two_qubit_with_cz(self): + """Test two qubit IRB.""" + transpiler_options = { + "basis_gates": ["sx", "rz", "cz"], + "optimization_level": 1, + } + exp = rb.InterleavedRB( + interleaved_element=CZGate(), + physical_qubits=(0, 1), + lengths=list(range(1, 30, 3)), + seed=1234, + backend=self.backend, + ) + exp.set_transpile_options(**transpiler_options) + 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 = 3 / 4 * self.pcz + self.assertAlmostEqual(epc.value.n, epc_expected, delta=3 * epc.value.std_dev) + + def test_expdata_serialization(self): + """Test serializing experiment data works.""" + exp = rb.InterleavedRB( + interleaved_element=SXGate(), + physical_qubits=(0,), + lengths=list(range(1, 200, 50)), + seed=123, + backend=self.backend, + ) + exp.set_transpile_options(**self.transpiler_options) + expdata = exp.run() + self.assertExperimentDone(expdata) + self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) + self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) + + + +class NonlocalCXDepError(TransformationPass): + """Transpiler pass for simulating nonlocal errors in a quantum device""" + + def __init__(self, coupling_map, initial_layout=None): + """Maps a DAGCircuit onto a `coupling_map` using swap gates. + Args: + coupling_map (CouplingMap): Directed graph represented a coupling map. + initial_layout (Layout): initial layout of qubits in mapping + """ + super().__init__() + self.coupling_map = coupling_map + self.initial_layout = initial_layout + + def run(self, dag): + """Runs the NonlocalCXDepError pass on `dag` + + Args: + dag (DAGCircuit): DAG to map. + + Returns: + DAGCircuit: A mapped DAG. + + Raises: + TranspilerError: initial layout and coupling map do not have the + same size + """ + + if self.initial_layout is None: + if self.property_set["layout"]: + self.initial_layout = self.property_set["layout"] + else: + self.initial_layout = Layout.generate_trivial_layout(*dag.qregs.values()) + + if len(dag.qubits) != len(self.initial_layout): + raise TranspilerError("The layout does not match the amount of qubits in the DAG") + + if len(self.coupling_map.physical_qubits) != len(self.initial_layout): + raise TranspilerError( + "Mappers require to have the layout to be the same size as the coupling map" + ) + + canonical_register = dag.qregs["q"] + trivial_layout = Layout.generate_trivial_layout(canonical_register) + current_layout = trivial_layout.copy() + + subdags = [] + for layer in dag.layers(): + graph = layer["graph"] + cxs = graph.op_nodes(op=CXGate) + if len(cxs) > 0: + for cx in cxs: + qubit_1 = current_layout[cx.qargs[0]] + qubit_2 = current_layout[cx.qargs[1]] + for qubit in range(dag.num_qubits()): + dep_param = decr_dep_param(qubit, qubit_1, qubit_2, self.coupling_map) + graph.apply_operation_back( + depolarizing_error(dep_param, 1).to_instruction(), + qargs=[canonical_register[qubit]], + cargs=[], + ) + subdags.append(graph) + + err_dag = dag.copy_empty_like() + for subdag in subdags: + err_dag.compose(subdag) + + return err_dag + + +class NoiseSimulator(AerSimulator): + """Quantum device simulator that has nonlocal CX errors""" + + def run(self, circuits, validate=False, parameter_binds=None, **run_options): + """Applies transpiler pass NonlocalCXDepError to circuits run on this backend""" + pm = PassManager() + cm = CouplingMap(couplinglist=self.configuration().coupling_map) + pm.append([NonlocalCXDepError(cm)]) + noise_circuits = pm.run(circuits) + return super().run( + noise_circuits, validate=validate, parameter_binds=parameter_binds, **run_options + ) + + +@ddt +class TestMirrorRB(QiskitExperimentsTestCase, RBTestMixin): + """Test for mirror RB.""" + + def setUp(self): + """Setup the tests.""" + super().setUp() + self.backend = FakeParis() + + self.basis_gates = ["sx", "rz", "cx"] + + self.transpiler_options = { + "basis_gates": self.basis_gates, + "optimization_level": 1, + } + + def test_custom_distribution(self): + """Test providing a custom distribution.""" + qubits = ( + 0, + 1, + 2, + ) + exp = rb.MirrorRB( + physical_qubits=qubits, + distribution=rb.RandomEdgeGrabDistribution, + two_qubit_gate_density=0.5, + lengths=list(range(2, 300, 20)), + seed=124, + backend=self.backend, + num_samples=30, + ) + # test that feeding the circuit from edge grab into discrete yields the same answer(?) + + def test_return_same_circuit(self): + """Test if setting the same seed returns the same circuits.""" + lengths = [10, 20] + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=lengths, + seed=123, + backend=self.backend, + ) + + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=lengths, + seed=123, + backend=self.backend, ) circs1 = exp1.circuits() @@ -843,207 +1087,59 @@ def test_pauli_randomize(self): circ = exp.circuits()[0] num_barriers = 0 for datum in circ.data: - if datum[0].name == "barrier": - num_barriers += 1 - self.assertEqual(6, num_barriers) - - def test_inverting_pauli_layer(self): - """Test that a circuit with an inverting Pauli layer at the end (i.e., - a layer of Paulis before the final measurement that restores the output - to |0>^num_qubits up to a global phase) composes to the identity (up to - a global phase)""" - exp = rb.MirrorRB( - qubits=(0, 1, 2), - lengths=[2], - seed=127, - backend=self.backend, - num_samples=3, - local_clifford=True, - pauli_randomize=True, - two_qubit_gate_density=0.2, - inverting_pauli_layer=True, - ) - self.assertAllIdentity(exp.circuits()) - - @data( - { - "qubits": [3, 3], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # repeated qubits - { - "qubits": [0, 1], - "lengths": [2, 4, 6, -8, 10], - "num_samples": 1, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # negative length - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": -4, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # negative number of samples - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 0, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # zero samples - { - "qubits": [0, 1], - "lengths": [2, 6, 6, 6, 10], - "num_samples": 2, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # repeated lengths - { - "qubits": [0, 1], - "lengths": [2, 4, 5, 8, 10], - "num_samples": 2, - "seed": 100, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # odd length - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "two_qubit_gate_density": -0.1, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # negative two-qubit gate density - ) - def test_invalid_configuration(self, configs): - """Test raise error when creating experiment with invalid configs.""" - self.assertRaises(QiskitError, rb.MirrorRB, **configs) - - @data( - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "backend": None, - }, # no backend - ) - def test_no_backend(self, configs): - """Test raise error when no backend is provided for sampling circuits.""" - mirror_exp = rb.MirrorRB(**configs) - self.assertRaises(QiskitError, mirror_exp.run) - - @data( - { - "qubits": [0, 25], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "backend": AerSimulator.from_backend(FakeParis()), - }, # Uncoupled qubits to test edgegrab algorithm warning - { - "qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "two_qubit_gate_density": 0.6, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # High two-qubit gate density warning - ) - def test_warnings(self, configs): - """Test raise warnings when creating experiment.""" - mirror_exp = rb.MirrorRB(**configs) - self.assertWarns(Warning, mirror_exp.run) - - def test_experiment_config(self): - """Test converting to and from config works""" - exp = rb.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123, backend=self.backend) - loaded_exp = rb.MirrorRB.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.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123) - self.assertRoundTripSerializable(exp, self.json_equiv) - - def test_analysis_config(self): - """ "Test converting analysis to and from config works""" - analysis = RBAnalysis() - loaded = RBAnalysis.from_config(analysis.config()) - self.assertNotEqual(analysis, loaded) - self.assertEqual(analysis.config(), loaded.config()) - - def test_expdata_serialization(self): - """Test serializing experiment data works.""" - exp = rb.MirrorRB( - qubits=(0,), - lengths=list(range(2, 200, 50)), - seed=123, - backend=self.backend, - inverting_pauli_layer=False, - ) - exp.set_transpile_options(**self.transpiler_options) - expdata = exp.run() - self.assertExperimentDone(expdata) - self.assertRoundTripSerializable(expdata, check_func=self.experiment_data_equiv) - self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) - - -class RBRunTestCase(QiskitExperimentsTestCase, RBTestMixin): - """Base test case for running RB experiments defining a common noise model.""" - - def setUp(self): - """Setup the tests.""" - super().setUp() - - # depolarizing error - self.p1q = 0.02 - self.p2q = 0.10 - self.pvz = 0.0 - self.pcz = 0.15 - - # basis gates - self.basis_gates = ["rz", "sx", "cx"] - - # setup noise model - sx_error = depolarizing_error(self.p1q, 1) - rz_error = depolarizing_error(self.pvz, 1) - cx_error = depolarizing_error(self.p2q, 2) - cz_error = depolarizing_error(self.pcz, 2) - - noise_model = NoiseModel() - noise_model.add_all_qubit_quantum_error(sx_error, "sx") - noise_model.add_all_qubit_quantum_error(rz_error, "rz") - noise_model.add_all_qubit_quantum_error(cx_error, "cx") - noise_model.add_all_qubit_quantum_error(cz_error, "cz") + if datum[0].name == "barrier": + num_barriers += 1 + self.assertEqual(6, num_barriers) - self.noise_model = noise_model + def test_inverting_pauli_layer(self): + """Test that a circuit with an inverting Pauli layer at the end (i.e., + a layer of Paulis before the final measurement that restores the output + to |0>^num_qubits up to a global phase) composes to the identity (up to + a global phase)""" + exp = rb.MirrorRB( + qubits=(0, 1, 2), + lengths=[2], + seed=127, + backend=self.backend, + num_samples=3, + local_clifford=True, + pauli_randomize=True, + two_qubit_gate_density=0.2, + inverting_pauli_layer=True, + ) + self.assertAllIdentity(exp.circuits()) - # Need level1 for consecutive gate cancellation for reference EPC value calculation - self.transpiler_options = { - "basis_gates": self.basis_gates, - "optimization_level": 1, - } + def test_experiment_config(self): + """Test converting to and from config works""" + exp = rb.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123, backend=self.backend) + loaded_exp = rb.MirrorRB.from_config(exp.config()) + self.assertNotEqual(exp, loaded_exp) + self.assertTrue(self.json_equiv(exp, loaded_exp)) - # Aer simulator - self.backend = AerSimulator(noise_model=noise_model, seed_simulator=123) + def test_roundtrip_serializable(self): + """Test round trip JSON serialization""" + exp = rb.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123) + self.assertRoundTripSerializable(exp, self.json_equiv) + def test_analysis_config(self): + """ "Test converting analysis to and from config works""" + analysis = rb.RBAnalysis() + loaded = rb.RBAnalysis.from_config(analysis.config()) + self.assertNotEqual(analysis, loaded) + self.assertEqual(analysis.config(), loaded.config()) -class TestRunStandardRB(RBRunTestCase): - """Test for running StandardRB.""" +class TestRunMirrorRB(RBRunTestCase): def test_single_qubit(self): - """Test single qubit RB.""" - exp = rb.StandardRB( + """Test single qubit mirror RB.""" + exp = rb.MirrorRB( physical_qubits=(0,), - lengths=list(range(1, 300, 30)), - seed=123, + lengths=list(range(2, 300, 20)), + seed=124, backend=self.backend, + num_samples=30, ) - exp.analysis.set_options(gate_error_ratio=None) + # exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) self.assertAllIdentity(exp.circuits()) @@ -1057,43 +1153,23 @@ def test_single_qubit(self): # The number of physical gate per Clifford will distribute # 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. + # But for mirror RB, we must also add the SX gate number per Pauli n_gpp, + # which is 2 for X and Y gates and 0 for I and Z gates (average = 1.0). So the + # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 epc = expdata.analysis_results("EPC") - - epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 + epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) def test_two_qubit(self): - """Test two qubit RB. Use default basis gates.""" - exp = rb.StandardRB( - physical_qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=123, - backend=self.backend, - ) - exp.analysis.set_options(gate_error_ratio=None) - transpiler_options = {"optimization_level": 1} - exp.set_transpile_options(**transpiler_options) - self.assertAllIdentity(exp.circuits()) - - expdata = exp.run() - self.assertExperimentDone(expdata) - - # Given CX error is dominant and 1q error can be negligible. - # Arbitrary SU(4) can be decomposed with (0, 1, 2, 3) CX gates, the expected - # average number of CX gate per Clifford is 1.5. - # Since this is two qubit RB, the dep-parameter is factored by 3/4. - epc = expdata.analysis_results("EPC") - # Allow for 50 percent tolerance since we ignore 1q gate contribution - epc_expected = 1 - (1 - 3 / 4 * self.p2q) ** 1.5 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) - - def test_three_qubit(self): - """Test two qubit RB. Use default basis gates.""" - exp = rb.StandardRB( - physical_qubits=(0, 1, 2), - lengths=list(range(1, 30, 3)), + """Test two qubit RB.""" + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 300, 20)), seed=123, backend=self.backend, + num_samples=30, + two_qubit_gate_density=two_qubit_gate_density, ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) @@ -1102,241 +1178,268 @@ def test_three_qubit(self): expdata = exp.run() self.assertExperimentDone(expdata) - # Given CX error is dominant and 1q error can be negligible. - # Arbitrary SU(8) can be decomposed with [0,...,7] CX gates, the expected - # average number of CX gate per Clifford is 3.5. - # Since this is three qubit RB, the dep-parameter is factored by 7/8. + # Given a two qubit gate density xi and an n qubit circuit, a Clifford + # layer has n*xi two-qubit gates. Obviously a Pauli has no two-qubit + # gates, so on aveage, a Clifford + Pauli layer has n*xi two-qubit gates + # and 2*n - 2*n*xi one-qubit gates (two layers have 2*n lattice sites, + # 2*n*xi of which are occupied by two-qubit gates). For two-qubit + # mirrored RB, the average infidelity is ((2^2 - 1)/2^2 = 3/4) times + # the two-qubit depolarizing parameter epc = expdata.analysis_results("EPC") - # Allow for 50 percent tolerance since we ignore 1q gate contribution - epc_expected = 1 - (1 - 7 / 8 * self.p2q) ** 3.5 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) - - def test_add_more_circuit_yields_lower_variance(self): - """Test variance reduction with larger number of sampling.""" - exp1 = rb.StandardRB( - physical_qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=123, - backend=self.backend, - num_samples=3, - ) - exp1.analysis.set_options(gate_error_ratio=None) - exp1.set_transpile_options(**self.transpiler_options) - expdata1 = exp1.run() - self.assertExperimentDone(expdata1) - - exp2 = rb.StandardRB( - physical_qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=456, - backend=self.backend, - num_samples=5, - ) - exp2.analysis.set_options(gate_error_ratio=None) - exp2.set_transpile_options(**self.transpiler_options) - expdata2 = exp2.run() - self.assertExperimentDone(expdata2) - - self.assertLess( - expdata2.analysis_results("EPC").value.s, - expdata1.analysis_results("EPC").value.s, - ) - - def test_poor_experiment_result(self): - """Test edge case that tail of decay is not sampled. - - This is a special case that fit outcome is very sensitive to initial guess. - Perhaps generated initial guess is close to a local minima. - """ - from qiskit.providers.fake_provider import FakeVigoV2 - - backend = FakeVigoV2() - backend.set_options(seed_simulator=123) - # TODO: this test no longer makes sense (yields small reduced_chisq) - # after fixing how to call fake backend v2 (by adding the next line) - # Need to call target before running fake backend v2 to load correct data - self.assertLess(backend.target["sx"][(0,)].error, 0.001) - - exp = rb.StandardRB( - physical_qubits=(0,), - lengths=[100, 200, 300], - seed=123, - backend=backend, - num_samples=5, - ) - exp.set_transpile_options(basis_gates=["x", "sx", "rz"], optimization_level=1) - - expdata = exp.run() - self.assertExperimentDone(expdata) - overview = expdata.analysis_results(0).value - # This yields bad fit due to poor data points, but still fit is not completely off. - self.assertLess(overview.reduced_chisq, 14) - - def test_expdata_serialization(self): - """Test serializing experiment data works.""" - exp = rb.StandardRB( - physical_qubits=(0,), - lengths=list(range(1, 200, 50)), - seed=123, - backend=self.backend, - ) - exp.set_transpile_options(**self.transpiler_options) - expdata = exp.run() - self.assertExperimentDone(expdata) - 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.""" - physical_qubits = [0, 2] - lengths = list(range(1, 300, 30)) - exps = [] - for qubit in physical_qubits: - exp = rb.StandardRB( - physical_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(**self.transpiler_options) - - 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") - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + cx_factor = (1 - 3 * self.p2q / 4) ** (2 * two_qubit_gate_density) + sx_factor = (1 - self.p1q / 2) ** (2 * 2 * (1 - two_qubit_gate_density)) + epc_expected = 1 - cx_factor * sx_factor + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - def test_two_qubit_parallel(self): - """Test two qubit RB in parallel.""" - qubit_pairs = [[0, 1], [2, 3]] - lengths = list(range(5, 100, 5)) - exps = [] - for pair in qubit_pairs: - exp = rb.StandardRB( - physical_qubits=pair, lengths=lengths, seed=123, backend=self.backend - ) - exp.analysis.set_options(gate_error_ratio=None, plot_raw_data=False) - exps.append(exp) + def test_two_qubit_nonlocal_noise(self): + """Test for 2 qubit Mirrored RB with a nonlocal noise model""" + # depolarizing error + p1q = 0.0 + p2q = 0.01 + pvz = 0.0 - par_exp = ParallelExperiment(exps) - par_exp.set_transpile_options(**self.transpiler_options) + # setup noise model + sx_error = depolarizing_error(p1q, 1) + rz_error = depolarizing_error(pvz, 1) + cx_error = depolarizing_error(p2q, 2) - par_expdata = par_exp.run(backend=self.backend) - self.assertExperimentDone(par_expdata) - epc_expected = 1 - (1 - 3 / 4 * self.p2q) ** 1.5 - for i in range(2): - epc = par_expdata.child_data(i).analysis_results("EPC") - # Allow for 20 percent tolerance since we ignore 1q gate contribution - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") - def test_two_qubit_with_cz(self): - """Test two qubit RB.""" + basis_gates = ["id", "sx", "rz", "cx"] + # Need level1 for consecutive gate cancellation for reference EPC value calculation transpiler_options = { - "basis_gates": ["sx", "rz", "cz"], + "basis_gates": basis_gates, "optimization_level": 1, } + # Coupling map is 3 x 3 lattice + noise_backend = NoiseSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=CouplingMap.from_grid(3, 3).get_edges(), + ) - exp = rb.StandardRB( - physical_qubits=(0, 1), - lengths=list(range(1, 50, 5)), + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 110, 20)), seed=123, - backend=self.backend, + backend=noise_backend, + num_samples=20, + two_qubit_gate_density=two_qubit_gate_density, ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**transpiler_options) - - expdata = exp.run() self.assertAllIdentity(exp.circuits()) + expdata = exp.run(noise_backend) self.assertExperimentDone(expdata) - # Given CX error is dominant and 1q error can be negligible. - # Arbitrary SU(4) can be decomposed with (0, 1, 2, 3) CZ gates, the expected - # average number of CZ gate per Clifford is 1.5. - # Since this is two qubit RB, the dep-parameter is factored by 3/4. epc = expdata.analysis_results("EPC") + # Compared to expected EPC in two-qubit test without nonlocal noise above, + # we include an extra factor for the nonlocal CX error. This nonlocal + # error is modeled by a one-qubit depolarizing channel on each qubit after + # each CX, so the expected number of one-qubit depolarizing channels + # induced by CXs is (number of CXs) * (number of qubits) = (two qubit gate + # density) * (number of qubits) * (number of qubits). + num_q = 2 + cx_factor = (1 - 3 * p2q / 4) ** (num_q * two_qubit_gate_density) + sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) + cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) + epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) - # Allow for 50 percent tolerance since we ignore 1q gate contribution - epc_expected = 1 - (1 - 3 / 4 * self.pcz) ** 1.5 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.5 * epc_expected) + def test_three_qubit_nonlocal_noise(self): + """Test three-qubit mirrored RB on a nonlocal noise model""" + # depolarizing error + p1q = 0.001 + p2q = 0.01 + pvz = 0.0 + # setup noise modelle + sx_error = depolarizing_error(p1q, 1) + rz_error = depolarizing_error(pvz, 1) + cx_error = depolarizing_error(p2q, 2) -class TestRunInterleavedRB(RBRunTestCase): - """Test for running InterleavedRB.""" + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") - def test_single_qubit(self): - """Test single qubit IRB.""" - exp = rb.InterleavedRB( - interleaved_element=SXGate(), - physical_qubits=(0,), - lengths=list(range(1, 300, 30)), + basis_gates = ["id", "sx", "rz", "cx"] + # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { + "basis_gates": basis_gates, + "optimization_level": 1, + } + noise_backend = NoiseSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=CouplingMap.from_grid(3, 3).get_edges(), + ) + + two_qubit_gate_density = 0.2 + exp = rb.MirrorRB( + qubits=(0, 1, 2), + lengths=list(range(2, 110, 50)), seed=123, - backend=self.backend, + backend=noise_backend, + num_samples=20, + two_qubit_gate_density=two_qubit_gate_density, ) - exp.set_transpile_options(**self.transpiler_options) + exp.analysis.set_options(gate_error_ratio=None) + exp.set_transpile_options(**transpiler_options) self.assertAllIdentity(exp.circuits()) - - expdata = exp.run() + expdata = exp.run(noise_backend) 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) + # The expected EPC was computed in simulations not presented here. + # Method: + # 1. Sample N Clifford layers according to the edgegrab algorithm + # in clifford_utils. + # 2. Transpile these into SX, RZ, and CX gates. + # 3. Replace each SX and CX with one- and two-qubit depolarizing + # channels, respectively, and remove RZ gates. + # 4. Use qiskit.quantum_info.average_gate_fidelity on these N layers + # to compute 1 - EPC for each layer, and average over the N layers. + epc_expected = 0.0124 + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) - def test_two_qubit(self): - """Test two qubit IRB.""" - exp = rb.InterleavedRB( - interleaved_element=CXGate(), - physical_qubits=(0, 1), - lengths=list(range(1, 30, 3)), + def test_add_more_circuit_yields_lower_variance(self): + """Test variance reduction with larger number of sampling.""" + exp1 = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 30, 4)), seed=123, backend=self.backend, + num_samples=3, + inverting_pauli_layer=False, ) - exp.set_transpile_options(**self.transpiler_options) - 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 = 3 / 4 * self.p2q - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + exp1.analysis.set_options(gate_error_ratio=None) + exp1.set_transpile_options(**self.transpiler_options) + expdata1 = exp1.run() + self.assertExperimentDone(expdata1) - def test_two_qubit_with_cz(self): - """Test two qubit IRB.""" - transpiler_options = { - "basis_gates": ["sx", "rz", "cz"], - "optimization_level": 1, - } - exp = rb.InterleavedRB( - interleaved_element=CZGate(), - physical_qubits=(0, 1), - lengths=list(range(1, 30, 3)), - seed=1234, + exp2 = rb.MirrorRB( + qubits=(0, 1), + lengths=list(range(2, 30, 4)), + seed=456, backend=self.backend, + num_samples=10, + inverting_pauli_layer=False, ) - exp.set_transpile_options(**transpiler_options) - self.assertAllIdentity(exp.circuits()) + exp2.analysis.set_options(gate_error_ratio=None) + exp2.set_transpile_options(**self.transpiler_options) + expdata2 = exp2.run() + self.assertExperimentDone(expdata2) - expdata = exp.run() - self.assertExperimentDone(expdata) + self.assertLess( + expdata2.analysis_results("EPC").value.s, + expdata1.analysis_results("EPC").value.s, + ) - # Since this is interleaved, we can directly compare values, i.e. n_gpc = 1 - epc = expdata.analysis_results("EPC") - epc_expected = 3 / 4 * self.pcz - self.assertAlmostEqual(epc.value.n, epc_expected, delta=3 * epc.value.std_dev) + @data( + { + "qubits": [3, 3], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # repeated qubits + { + "qubits": [0, 1], + "lengths": [2, 4, 6, -8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative length + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": -4, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative number of samples + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 0, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # zero samples + { + "qubits": [0, 1], + "lengths": [2, 6, 6, 6, 10], + "num_samples": 2, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # repeated lengths + { + "qubits": [0, 1], + "lengths": [2, 4, 5, 8, 10], + "num_samples": 2, + "seed": 100, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # odd length + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "two_qubit_gate_density": -0.1, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # negative two-qubit gate density + ) + def test_invalid_configuration(self, configs): + """Test raise error when creating experiment with invalid configs.""" + self.assertRaises(QiskitError, rb.MirrorRB, **configs) + + @data( + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": None, + }, # no backend + ) + def test_no_backend(self, configs): + """Test raise error when no backend is provided for sampling circuits.""" + mirror_exp = rb.MirrorRB(**configs) + self.assertRaises(QiskitError, mirror_exp.run) + + @data( + { + "qubits": [0, 4], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "backend": AerSimulator.from_backend(FakeManila()), + }, # Uncoupled qubits to test edgegrab algorithm warning + { + "qubits": [0, 1], + "lengths": [2, 4, 6, 8, 10], + "num_samples": 1, + "seed": 100, + "two_qubit_gate_density": 0.6, + "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), + }, # High two-qubit gate density warning + ) + def test_warnings(self, configs): + """Test raise warnings when creating experiment.""" + mirror_exp = rb.MirrorRB(**configs) + self.assertWarns(Warning, mirror_exp.run) def test_expdata_serialization(self): """Test serializing experiment data works.""" - exp = rb.InterleavedRB( - interleaved_element=SXGate(), - physical_qubits=(0,), - lengths=list(range(1, 200, 50)), + exp = rb.MirrorRB( + qubits=(0,), + lengths=list(range(2, 200, 50)), seed=123, backend=self.backend, + inverting_pauli_layer=False, ) exp.set_transpile_options(**self.transpiler_options) expdata = exp.run() From 7d79339791d251bc8930da49d6d77c8dcdd075f6 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Wed, 15 Mar 2023 17:46:30 -0400 Subject: [PATCH 29/56] changed 1Q from integer to clifford the default integer method wasn't working with the later `Clifford()` invocation. --- .../randomized_benchmarking/clifford_utils.py | 33 ++++---- .../mirror_rb_experiment.py | 75 ++++++++++--------- .../randomized_benchmarking/sampling_utils.py | 10 +-- .../notes/mirror-rb-ec4d695a9a923971.yaml | 7 +- 4 files changed, 64 insertions(+), 61 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index fa625b64a6..1f35a36218 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -300,6 +300,22 @@ def _unpack_num(num, sig): num //= k return res + @staticmethod + def compute_target_bitstring(circuit: QuantumCircuit) -> str: + """For a Clifford circuit C, compute C|0>. + Args: + circuit: A Clifford QuantumCircuit. + Returns: + Target bitstring. + """ + # convert circuit to Boolean phase vector of stabilizer table + phase_vector = Clifford(circuit).table.phase + n = circuit.num_qubits + + # target string has a 1 for each True in the stabilizer half of the phase vector + target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) + return target + # Constant mapping from 1Q single Clifford gate to 1Q Clifford numerical identifier. # This table must be generated using `data.generate_clifford_data.gen_cliff_single_1q_gate_map`, or, @@ -586,20 +602,3 @@ def _layer_indices_from_num(num: Integral) -> Tuple[Integral, Integral, Integral idx1 = num % _NUM_LAYER_1 idx0 = num // _NUM_LAYER_1 return idx0, idx1, idx2 - - -def compute_target_bitstring(self, circuit: QuantumCircuit) -> str: - """For a Clifford circuit C, compute C|0>. - Args: - circuit: A Clifford QuantumCircuit - Returns: - Target bit string - """ - - # convert circuit to Boolean phase vector of stabilizer table - phase_vector = Clifford(circuit).table.phase - n = circuit.num_qubits - - # target string has a 1 for each True in the stabilizer half of the phase vector - target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) - return target diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index a8f99dc092..7335d06794 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -29,7 +29,7 @@ from .rb_experiment import StandardRB from .mirror_rb_analysis import MirrorRBAnalysis -from .clifford_utils import CliffordUtils +from .clifford_utils import CliffordUtils, _decompose_clifford_ops from .sampling_utils import MirrorRBSampler, EdgeGrabSampler SequenceElementType = Union[Clifford, Integral, QuantumCircuit] @@ -173,20 +173,11 @@ def circuits(self) -> List[QuantumCircuit]: """Return a list of Mirror RB circuits. Returns: - A list of :class:`QuantumCircuit`s. + A list of :class:`QuantumCircuit`. """ sequences = self._sample_sequences() circuits = self._sequences_to_circuits(sequences) - for circ, seq in zip(circuits, sequences): - circ.metadata = { - "experiment_type": self._type, - "xval": len(seq), - "group": "Clifford", - "physical_qubits": self.physical_qubits, - "target": self._clifford_utils.compute_target_bitstring(circ), - "inverting_pauli_layer": self._inverting_pauli_layer, - } return circuits def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: @@ -201,7 +192,8 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: QiskitError: If no backend is provided. Returns: - A list of mirror RB sequences. Each element is a full circuit layer. + A list of mirror RB sequences. Each element is a list of layers with length + matching the corresponding element in ``lengths``. """ if not self._backend: raise QiskitError("A backend must be provided.") @@ -216,22 +208,24 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append(edge) + # adjust the density based on whether the pauli layers are in + if self.experiment_options.pauli_randomize: + adjusted_2q_density = self.experiment_options.two_qubit_gate_density * 2 + else: + adjusted_2q_density = self.experiment_options.two_qubit_gate_density + sequences = [] for _ in range(self.experiment_options.num_samples): for length in self.experiment_options.lengths: - print("length ", length) - elements = [] + # Sample Clifford layer elements for first half of mirror circuit - # TODO need to adjust density if the paulis aren't in - elements.append( - self._distribution( - self.num_qubits, - self.experiment_options.two_qubit_gate_density, - self.coupling_map, - length // 2, - seed=self.experiment_options.seed, - )[0] + elements = self._distribution( + self.num_qubits, + adjusted_2q_density, + self.coupling_map, + length // 2, + seed=self.experiment_options.seed, ) # Append inverses of Clifford elements to second half of circuit @@ -257,29 +251,35 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # ) // pauli_scale # circuit.metadata["mirror"] = True # circuits += mirror_circuits - sequences += [elements] + sequences.append(elements) return sequences + def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: + if isinstance(op, QuantumCircuit): + return Clifford.from_circuit(op).adjoint() + return op.adjoint() + def _sequences_to_circuits( self, sequences: List[Sequence[SequenceElementType]] ) -> List[QuantumCircuit]: """Convert Mirror RB sequences into mirror circuits. + Args: + sequences: List of sequences whose elements are full circuit layers. + Returns: A list of RB circuits. """ basis_gates = self._get_basis_gates() - # Circuit generation - print(sequences) circuits = [] + print(len(sequences)) for seq in sequences: circ = QuantumCircuit(self.num_qubits) for elem in seq: - print("elem", elem) - if isinstance(elem, Integral) or hasattr(elem, "to_instruction"): - circ.append(self._to_instruction(elem, basis_gates, 1), circ.qubits) - else: - circ.append(elem, circ.qubits) + # if isinstance(elem, Integral) or hasattr(elem, "to_instruction"): + # circ.append(self._to_instruction(elem, basis_gates, 1), circ.qubits) + # else: + circ.append(elem, circ.qubits) circ.append(Barrier(self.num_qubits), circ.qubits) if self.experiment_options.inverting_pauli_layer: @@ -292,6 +292,14 @@ def _sequences_to_circuits( label = "".join(["X" if char == "1" else "I" for char in target]) circ.append(Pauli(label), list(range(self._num_qubits))) + circ.metadata = { + "experiment_type": self._type, + "xval": len(seq), + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "target": self._clifford_utils.compute_target_bitstring(circ), + "inverting_pauli_layer": self.experiment_options.inverting_pauli_layer, + } circ.measure_all() # includes insertion of the barrier before measurement circuits.append(circ) return circuits @@ -340,9 +348,6 @@ def _start_end_cliffords(self, elements: Iterable[Clifford]) -> List[QuantumCirc Returns: The new list of elements with the start and end local (1-qubit) Cliffords. """ - # rng = default_rng(seed=self.experiment_options.seed) - # rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=self.experiment_options.num_qubits) - rand_clifford = [ random_clifford(1, seed=self.experiment_options.seed) for _ in self.physical_qubits ] @@ -366,7 +371,7 @@ def _generate_mirror( lengths: A list of RB sequences lengths. Returns: - A list of :class:`QuantumCircuit`s. + A list of :class:`QuantumCircuit`. Additional information: The circuits are constructed iteratively; each circuit is obtained diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 7f213fd889..6c6bd4d41d 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -72,7 +72,8 @@ class EdgeGrabSampler(MirrorRBSampler): edges will have two-qubit gates in the output layer. This produces a layer with an expected two-qubit gate density :math:`2\xi`. - Accounting for all the layers in mirror RB, this means the overall two-qubit gate + In the default mirror RB configuration where these layers are dressed with + single-qubit Pauli layers, this means the overall two-qubit gate density will be :math:`\xi`. The overall average density will converge to :math:`\xi` as the circuit size increases. @@ -111,8 +112,7 @@ def __call__( TypeError: If invalid gate set(s) are specified. Returns: - List of sampled QuantumCircuit layers with length ``length``. Integers are - returned for one-qubit Cliffords for speed. + List of sampled QuantumCircuit layers with length ``length``. """ rng = default_rng(seed=seed) @@ -124,7 +124,8 @@ def __call__( if num_qubits == 1: if one_qubit_gate_set.casefold() == "clifford": - return rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) + # return rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) + return [random_clifford(1, rng) for i in range(length)] else: return rng.choice(one_qubit_gate_set, size=length) @@ -168,7 +169,6 @@ def __call__( # with probability two_qubit_prob, place a two-qubit gate from the # gate set on edge in selected_edges try: - print(edge[0], edge[1]) getattr(qc, rng.choice(two_qubit_gate_set))(edge[0], edge[1]) except AttributeError: raise QiskitError("Invalid two-qubit gate set specified.") diff --git a/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml index bf6f4ad6f7..4b4d833e51 100644 --- a/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml +++ b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml @@ -1,7 +1,6 @@ --- features: - | - A new experiment class :class:`.MirrorRB` is - introduced. This class implements mirror randomized benchmarking, a version - of RB that uses mirror circuits. It is more scalable than other RB protocols and - can consequently be used to detect crosstalk errors. + A new experiment class :class:`.MirrorRB` is introduced. This class implements + mirror randomized benchmarking, a variant of randomized benchmarking that measures + the fidelity of user-defined ensembles of randomized mirror circuits. From e3c9b617511ca1b294f5282bd43527638aef689a Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Wed, 15 Mar 2023 23:58:09 -0400 Subject: [PATCH 30/56] fixed circuit length --- .../pygsti-data-pygsti-transpiled-circ.png | Bin .../pygsti-data-qiskit-transpiled-circ.png | Bin .../benchmarking/mirror_rb.rst} | 4 +-- .../randomized_benchmarking/clifford_utils.py | 1 - .../mirror_rb_experiment.py | 34 +++--------------- .../randomized_benchmarking/sampling_utils.py | 11 +++--- 6 files changed, 12 insertions(+), 38 deletions(-) rename docs/{tutorials => manuals/benchmarking/images}/pygsti-data-pygsti-transpiled-circ.png (100%) rename docs/{tutorials => manuals/benchmarking/images}/pygsti-data-qiskit-transpiled-circ.png (100%) rename docs/{tutorials/mirror_randomized_benchmarking.rst => manuals/benchmarking/mirror_rb.rst} (98%) diff --git a/docs/tutorials/pygsti-data-pygsti-transpiled-circ.png b/docs/manuals/benchmarking/images/pygsti-data-pygsti-transpiled-circ.png similarity index 100% rename from docs/tutorials/pygsti-data-pygsti-transpiled-circ.png rename to docs/manuals/benchmarking/images/pygsti-data-pygsti-transpiled-circ.png diff --git a/docs/tutorials/pygsti-data-qiskit-transpiled-circ.png b/docs/manuals/benchmarking/images/pygsti-data-qiskit-transpiled-circ.png similarity index 100% rename from docs/tutorials/pygsti-data-qiskit-transpiled-circ.png rename to docs/manuals/benchmarking/images/pygsti-data-qiskit-transpiled-circ.png diff --git a/docs/tutorials/mirror_randomized_benchmarking.rst b/docs/manuals/benchmarking/mirror_rb.rst similarity index 98% rename from docs/tutorials/mirror_randomized_benchmarking.rst rename to docs/manuals/benchmarking/mirror_rb.rst index 48d666d2bf..ac4a9e6400 100644 --- a/docs/tutorials/mirror_randomized_benchmarking.rst +++ b/docs/manuals/benchmarking/mirror_rb.rst @@ -221,11 +221,11 @@ small discrepancies in fit parameters between the two codes. To illustrate, cons two circuits below, both of which were generated in ``pyGSTi``. The first circuit was transpiled in ``pyGSTi``. -.. image:: pygsti-data-pygsti-transpiled-circ.png +.. image:: images/pygsti-data-pygsti-transpiled-circ.png and the second was transpiled in Qiskit. -.. image:: pygsti-data-qiskit-transpiled-circ.png +.. image:: images/pygsti-data-qiskit-transpiled-circ.png Note the different implementations of the same Clifford on qubit 0 in the fifth layer. diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index e7dcefe9b3..5b81017949 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -249,7 +249,6 @@ def clifford_1_qubit_circuit(cls, num, basis_gates: Optional[Tuple[str, ...]] = """Return the 1-qubit clifford circuit corresponding to `num` where `num` is between 0 and 23. """ - print("1-qubit", num) unpacked = cls._unpack_num(num, cls.CLIFFORD_1_QUBIT_SIG) i, j, p = unpacked[0], unpacked[1], unpacked[2] qc = QuantumCircuit(1, name=f"Clifford-1Q({num})") diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 7335d06794..ed07c74495 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -227,7 +227,6 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: length // 2, seed=self.experiment_options.seed, ) - # Append inverses of Clifford elements to second half of circuit for element in elements[::-1]: elements.append(self._adjoint_clifford(element)) @@ -241,17 +240,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if self.experiment_options.local_clifford: elements = self._start_end_cliffords(elements) - # mirror_circuits = self._generate_mirror(elements, element_lengths) - # for circuit in mirror_circuits: - # # Use "boolean arithmetic" to calculate xval correctly for each circuit - # pauli_scale = self._pauli_randomize + 1 - # clifford_const = self._local_clifford * 2 - # circuit.metadata["xval"] = ( - # circuit.metadata["xval"] - self._pauli_randomize - clifford_const - # ) // pauli_scale - # circuit.metadata["mirror"] = True - # circuits += mirror_circuits - sequences.append(elements) + sequences.append(elements) return sequences def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: @@ -272,14 +261,13 @@ def _sequences_to_circuits( """ basis_gates = self._get_basis_gates() circuits = [] - print(len(sequences)) - for seq in sequences: + for i, seq in enumerate(sequences): circ = QuantumCircuit(self.num_qubits) for elem in seq: # if isinstance(elem, Integral) or hasattr(elem, "to_instruction"): # circ.append(self._to_instruction(elem, basis_gates, 1), circ.qubits) # else: - circ.append(elem, circ.qubits) + circ.append(elem.to_instruction(), circ.qubits) circ.append(Barrier(self.num_qubits), circ.qubits) if self.experiment_options.inverting_pauli_layer: @@ -294,7 +282,7 @@ def _sequences_to_circuits( circ.metadata = { "experiment_type": self._type, - "xval": len(seq), + "xval": self.experiment_options.lengths[i % len(self.experiment_options.lengths)], "group": "Clifford", "physical_qubits": self.physical_qubits, "target": self._clifford_utils.compute_target_bitstring(circ), @@ -314,20 +302,6 @@ def _pauli_dress(self, element_list: List) -> List: Returns: The new list of elements with the Paulis interleaved. """ - # Generate random Pauli - # rand_pauli = random_pauli( - # self._num_qubits, seed=self.experiment_options.seed - # ).to_instruction() - # rand_pauli_op = Clifford(rand_pauli) - # new_element_list = [(rand_pauli, rand_pauli_op)] - # for element in element_list: - # new_element_list.append(element) - # rand_pauli = random_pauli( - # self._num_qubits, seed=self.experiment_options.seed - # ).to_instruction() - # rand_pauli_op = Clifford(rand_pauli) - # new_element_list.append((rand_pauli, rand_pauli_op)) - # return new_element_list rand_pauli = random_pauli(self._num_qubits, seed=self.experiment_options.seed) new_element_list = [rand_pauli] diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 6c6bd4d41d..b62db0a9cd 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -96,8 +96,8 @@ def __call__( Args: num_qubits: The number of qubits to generate layers for. - one_qubit_gate_set: The one qubit gate set to sample from. Can be either a list - of gates or "clifford". + one_qubit_gate_set: The one qubit gate set to sample from. Can be either a + list of gates or "clifford". two_qubit_gate_set: The two qubit gate set to sample from. Can be either a list of gates or one of "cx", "cy", "cz", or "csx". two_qubit_gate_density: the expected fraction of two-qubit gates in the @@ -107,12 +107,13 @@ def __call__( seed: Seed for random generation. Raises: - Warning: If device has no connectivity or ``two_qubit_gate_density`` is too - high. + Warning: If the coupling map has no connectivity or + ``two_qubit_gate_density`` is too high. TypeError: If invalid gate set(s) are specified. Returns: - List of sampled QuantumCircuit layers with length ``length``. + ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over + ``num_qubits`` qubits. """ rng = default_rng(seed=seed) From e66a58d6e7d361fe3f6938645d81b6c0709253a7 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Thu, 16 Mar 2023 01:39:10 -0400 Subject: [PATCH 31/56] fix rng and force default transpile --- .../mirror_rb_experiment.py | 46 +++++++++---------- .../randomized_benchmarking/rb_experiment.py | 5 +- .../randomized_benchmarking/sampling_utils.py | 17 +++---- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index ed07c74495..3e0b9b18a6 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -29,7 +29,7 @@ from .rb_experiment import StandardRB from .mirror_rb_analysis import MirrorRBAnalysis -from .clifford_utils import CliffordUtils, _decompose_clifford_ops +from .clifford_utils import CliffordUtils, _decompose_clifford_ops, _clifford_1q_int_to_instruction from .sampling_utils import MirrorRBSampler, EdgeGrabSampler SequenceElementType = Union[Clifford, Integral, QuantumCircuit] @@ -130,8 +130,11 @@ def __init__( local_clifford=local_clifford, pauli_randomize=pauli_randomize, inverting_pauli_layer=inverting_pauli_layer, + two_qubit_gate_density=two_qubit_gate_density, ) + # self.set_transpile_options(optimization_level=1) + self.analysis = MirrorRBAnalysis() @classmethod @@ -195,6 +198,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: A list of mirror RB sequences. Each element is a list of layers with length matching the corresponding element in ``lengths``. """ + rng = default_rng(seed=self.experiment_options.seed) if not self._backend: raise QiskitError("A backend must be provided.") @@ -223,9 +227,9 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: elements = self._distribution( self.num_qubits, adjusted_2q_density, - self.coupling_map, + experiment_coupling_map, length // 2, - seed=self.experiment_options.seed, + seed=rng, ) # Append inverses of Clifford elements to second half of circuit for element in elements[::-1]: @@ -233,12 +237,12 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Interleave random Paulis if set by user if self.experiment_options.pauli_randomize: - elements = self._pauli_dress(elements) + elements = self._pauli_dress(elements, rng) # element_lengths = [length * 2 + 1 for length in element_lengths] # Add start and end local cliffords if set by user if self.experiment_options.local_clifford: - elements = self._start_end_cliffords(elements) + elements = self._start_end_cliffords(elements, rng) sequences.append(elements) return sequences @@ -264,9 +268,6 @@ def _sequences_to_circuits( for i, seq in enumerate(sequences): circ = QuantumCircuit(self.num_qubits) for elem in seq: - # if isinstance(elem, Integral) or hasattr(elem, "to_instruction"): - # circ.append(self._to_instruction(elem, basis_gates, 1), circ.qubits) - # else: circ.append(elem.to_instruction(), circ.qubits) circ.append(Barrier(self.num_qubits), circ.qubits) @@ -292,7 +293,7 @@ def _sequences_to_circuits( circuits.append(circ) return circuits - def _pauli_dress(self, element_list: List) -> List: + def _pauli_dress(self, element_list: List, rng) -> List: """Interleaving layers of random Paulis inside the element list. Args: @@ -302,16 +303,18 @@ def _pauli_dress(self, element_list: List) -> List: Returns: The new list of elements with the Paulis interleaved. """ - - rand_pauli = random_pauli(self._num_qubits, seed=self.experiment_options.seed) + rand_pauli = random_pauli(self._num_qubits, seed=rng) new_element_list = [rand_pauli] for element in element_list: new_element_list.append(element) - rand_pauli = random_pauli(self._num_qubits, seed=self.experiment_options.seed) + rand_pauli = random_pauli(self._num_qubits, seed=rng) new_element_list.append(rand_pauli) return new_element_list - def _start_end_cliffords(self, elements: Iterable[Clifford]) -> List[QuantumCircuit]: + def _transpiled_circuits(self) -> List[QuantumCircuit]: + return super()._transpiled_circuits(custom_transpile=True) + + def _start_end_cliffords(self, elements: Iterable[Clifford], rng) -> List[QuantumCircuit]: """Add a layer of uniformly random 1-qubit Cliffords to the beginning of the list and its inverse to the end of the list. @@ -322,17 +325,14 @@ def _start_end_cliffords(self, elements: Iterable[Clifford]) -> List[QuantumCirc Returns: The new list of elements with the start and end local (1-qubit) Cliffords. """ - rand_clifford = [ - random_clifford(1, seed=self.experiment_options.seed) for _ in self.physical_qubits - ] - - # Assemble the n-qubit Clifford layer - tensor_op = rand_clifford[0] - for cliff in rand_clifford[1:]: - tensor_op = tensor_op ^ cliff - tensor_circ = tensor_op.to_circuit() + basis_gates = self._get_basis_gates() + rand_clifford = rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=self.num_qubits) + circ = QuantumCircuit(self.num_qubits) + for i, cliff in enumerate(rand_clifford): + circ.append(self._to_instruction(cliff, basis_gates, gate_size=1), [circ.qubits[i]]) + circ.append(Barrier(self.num_qubits), circ.qubits) - return [tensor_circ] + elements + [tensor_circ.inverse()] + return [circ] + elements + [circ.inverse()] def _generate_mirror( self, elements: Iterable[Clifford], lengths: Iterable[int] diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 56ebb7c0df..354c6d472c 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -306,7 +306,7 @@ def _to_instruction( if isinstance(elem, Integral): if self.num_qubits == 1 or gate_size == 1: return _clifford_1q_int_to_instruction(elem, basis_gates) - if self.num_qubits == 2 or gate_size == 1: + if self.num_qubits == 2 or gate_size == 2: return _clifford_2q_int_to_instruction(elem, basis_gates) return elem.to_instruction() @@ -338,11 +338,12 @@ def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: return Clifford.from_circuit(op).adjoint() return op.adjoint() - def _transpiled_circuits(self) -> List[QuantumCircuit]: + def _transpiled_circuits(self, custom_transpile=False) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" has_custom_transpile_option = ( not set(vars(self.transpile_options)).issubset({"basis_gates", "optimization_level"}) or self.transpile_options.get("optimization_level", 0) != 0 + or custom_transpile ) has_no_undirected_2q_basis = self._get_basis_gates() is None if self.num_qubits > 2 or has_custom_transpile_option or has_no_undirected_2q_basis: diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index b62db0a9cd..8fc885531b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -61,21 +61,21 @@ class EdgeGrabSampler(MirrorRBSampler): # section: overview The edge grab sampler, given a list of :math:`w` qubits, their connectivity - graph, and the desired two-qubit gate density :math:`\xi`, outputs a layer + graph, and the desired two-qubit gate density :math:`\xi_s`, outputs a layer as follows: 1. Begin with the empty set :math:`E` and :math:`E_r`, the set of all edges in the connectivity graph. Select an edge from :math:`E_r` at random and add it to :math:`E`, removing all edges that share a qubit with the edge from :math:`E_r`. - 2. Select edges from :math:`E` with the probability :math:`w\xi/|E|`. These + 2. Select edges from :math:`E` with the probability :math:`w\xi/2|E|`. These edges will have two-qubit gates in the output layer. - This produces a layer with an expected two-qubit gate density :math:`2\xi`. - In the default mirror RB configuration where these layers are dressed with - single-qubit Pauli layers, this means the overall two-qubit gate - density will be :math:`\xi`. The overall average density will converge to - :math:`\xi` as the circuit size increases. + This produces a layer with an expected two-qubit gate density :math:`\xi`. In + the default mirror RB configuration where these layers are dressed with + single-qubit Pauli layers, this means the overall two-qubit gate density will be + :math:`\xi_s/2=\xi`. The overall density will converge to :math:`\xi` as the + circuit size increases. # section: reference .. ref_arxiv:: 1 2008.11294 @@ -150,7 +150,8 @@ def __call__( qc = QuantumCircuit(qr) two_qubit_prob = 0 try: - two_qubit_prob = num_qubits * two_qubit_gate_density / len(selected_edges) + # need to divide by 2 since each two-qubit gate spans two lattice sites + two_qubit_prob = num_qubits * two_qubit_gate_density / 2 / len(selected_edges) except ZeroDivisionError: warnings.warn("Device has no connectivity. All gates will be single-qubit.") if two_qubit_prob > 1: From 52ce46be43028e9719e387520b750af424c18160 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Fri, 17 Mar 2023 02:46:19 -0400 Subject: [PATCH 32/56] fix bugs to pass tests --- .../randomized_benchmarking/clifford_utils.py | 28 +-- .../mirror_rb_experiment.py | 192 +++++++----------- .../randomized_benchmarking/sampling_utils.py | 7 +- .../test_clifford_utils.py | 14 ++ .../test_randomized_benchmarking.py | 82 +++----- 5 files changed, 135 insertions(+), 188 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 5b81017949..eea3d05922 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -299,21 +299,21 @@ def _unpack_num(num, sig): num //= k return res - @staticmethod - def compute_target_bitstring(circuit: QuantumCircuit) -> str: - """For a Clifford circuit C, compute C|0>. - Args: - circuit: A Clifford QuantumCircuit. - Returns: - Target bitstring. - """ - # convert circuit to Boolean phase vector of stabilizer table - phase_vector = Clifford(circuit).table.phase - n = circuit.num_qubits - # target string has a 1 for each True in the stabilizer half of the phase vector - target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) - return target +def compute_target_bitstring(circuit: QuantumCircuit) -> str: + """For a Clifford circuit C, compute C|0>. + Args: + circuit: A Clifford QuantumCircuit. + Returns: + Target bitstring. + """ + # convert circuit to Boolean phase vector of stabilizer table + phase_vector = Clifford(circuit).table.phase + n = circuit.num_qubits + + # target string has a 1 for each True in the stabilizer half of the phase vector + target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) + return target # Constant mapping from 1Q single Clifford gate to 1Q Clifford numerical identifier. diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 3e0b9b18a6..84b1a4af5a 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -26,10 +26,16 @@ from qiskit.providers.backend import Backend from qiskit.providers.options import Options from qiskit.transpiler.basepasses import TransformationPass +from qiskit_experiments.warnings import deprecate_arguments from .rb_experiment import StandardRB from .mirror_rb_analysis import MirrorRBAnalysis -from .clifford_utils import CliffordUtils, _decompose_clifford_ops, _clifford_1q_int_to_instruction +from .clifford_utils import ( + CliffordUtils, + _decompose_clifford_ops, + _clifford_1q_int_to_instruction, + compute_target_bitstring, +) from .sampling_utils import MirrorRBSampler, EdgeGrabSampler SequenceElementType = Union[Clifford, Integral, QuantumCircuit] @@ -63,6 +69,7 @@ class MirrorRB(StandardRB): """ + @deprecate_arguments({"qubits": "physical_qubits"}, "0.5") def __init__( self, physical_qubits: Sequence[int], @@ -105,13 +112,12 @@ def __init__( Raises: QiskitError: if an odd length or a negative two qubit gate density is provided """ - # All lengths must be even + if not all(length % 2 == 0 for length in lengths): raise QiskitError("All lengths must be even") - # Two-qubit density must be non-negative - if two_qubit_gate_density < 0: - raise QiskitError("Two-qubit gate density must be non-negative") + if two_qubit_gate_density < 0 or two_qubit_gate_density > 1: + raise QiskitError("Two-qubit gate density must be between 0 and 1.") super().__init__( physical_qubits, @@ -122,7 +128,6 @@ def __init__( full_sampling=full_sampling, ) - self._clifford_utils = CliffordUtils() self._distribution = distribution() self.set_experiment_options( @@ -133,8 +138,6 @@ def __init__( two_qubit_gate_density=two_qubit_gate_density, ) - # self.set_transpile_options(optimization_level=1) - self.analysis = MirrorRBAnalysis() @classmethod @@ -151,12 +154,7 @@ def _default_experiment_options(cls) -> Options: two_qubit_gate_density (float): Expected proportion of two-qubit gates in the mirror circuit layers (not counting Clifford or Pauli layers at the start and end). - lengths (List[int]): A list of RB sequences lengths. num_samples (int): Number of samples to generate for each sequence length. - seed (None or int or SeedSequence or BitGenerator or Generator): A seed - used to initialize ``numpy.random.default_rng`` when generating circuits. - The ``default_rng`` will be initialized with this seed value everytime - :meth:`circuits` is called. """ options = super()._default_experiment_options() options.update_options( @@ -164,10 +162,7 @@ def _default_experiment_options(cls) -> Options: pauli_randomize=True, two_qubit_gate_density=0.2, distribution=None, - num_samples=None, - seed=None, inverting_pauli_layer=False, - full_sampling=None, ) return options @@ -204,11 +199,11 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Coupling map is full connectivity by default. If backend has a coupling map, # get backend coupling map and create coupling map for physical qubits - self.coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) - if self._backend.configuration().coupling_map: - self.coupling_map = self._backend.configuration().coupling_map + coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) + if self._backend_data.coupling_map: + coupling_map = self._backend_data.coupling_map experiment_coupling_map = [] - for edge in self.coupling_map: + for edge in coupling_map: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append(edge) @@ -220,31 +215,60 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: sequences = [] - for _ in range(self.experiment_options.num_samples): - for length in self.experiment_options.lengths: - - # Sample Clifford layer elements for first half of mirror circuit - elements = self._distribution( + if self.experiment_options.full_sampling: + for _ in range(self.experiment_options.num_samples): + for length in self.experiment_options.lengths: + # Sample Clifford layer elements for first half of mirror circuit + elements = self._distribution( + self.num_qubits, + adjusted_2q_density, + experiment_coupling_map, + length // 2, + seed=rng, + ) + # Append inverses of Clifford elements to second half of circuit + for element in elements[::-1]: + elements.append(self._adjoint_clifford(element)) + + # Interleave random Paulis if set by user + if self.experiment_options.pauli_randomize: + elements = self._pauli_dress(elements, rng) + + # Add start and end local cliffords if set by user + if self.experiment_options.local_clifford: + elements = self._start_end_cliffords(elements, rng) + + sequences.append(elements) + else: + for _ in range(self.experiment_options.num_samples): + longest_seq = self._distribution( self.num_qubits, adjusted_2q_density, experiment_coupling_map, - length // 2, + max(self.experiment_options.lengths) // 2, seed=rng, ) - # Append inverses of Clifford elements to second half of circuit - for element in elements[::-1]: - elements.append(self._adjoint_clifford(element)) + element_lengths = self.experiment_options.lengths + # Append inverses of Clifford elements to second half of circuit + for element in longest_seq[::-1]: + longest_seq.append(self._adjoint_clifford(element)) # Interleave random Paulis if set by user if self.experiment_options.pauli_randomize: - elements = self._pauli_dress(elements, rng) - # element_lengths = [length * 2 + 1 for length in element_lengths] + longest_seq = self._pauli_dress(longest_seq, rng) + element_lengths = [length * 2 + 1 for length in element_lengths] # Add start and end local cliffords if set by user if self.experiment_options.local_clifford: - elements = self._start_end_cliffords(elements, rng) + longest_seq = self._start_end_cliffords(longest_seq, rng) + element_lengths = [length + 2 for length in element_lengths] + + # Construct the remaining sequences from the longest + for real_length in element_lengths: + sequences.append( + longest_seq[: real_length // 2] + longest_seq[-real_length // 2 :] + ) - sequences.append(elements) return sequences def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: @@ -271,6 +295,14 @@ def _sequences_to_circuits( circ.append(elem.to_instruction(), circ.qubits) circ.append(Barrier(self.num_qubits), circ.qubits) + circ.metadata = { + "xval": self.experiment_options.lengths[i % len(self.experiment_options.lengths)], + "group": "Clifford", + "physical_qubits": self.physical_qubits, + "target": compute_target_bitstring(circ), + "inverting_pauli_layer": self.experiment_options.inverting_pauli_layer, + } + if self.experiment_options.inverting_pauli_layer: # Get target bitstring (ideal bitstring outputted by the circuit) target = circ.metadata["target"] @@ -281,24 +313,16 @@ def _sequences_to_circuits( label = "".join(["X" if char == "1" else "I" for char in target]) circ.append(Pauli(label), list(range(self._num_qubits))) - circ.metadata = { - "experiment_type": self._type, - "xval": self.experiment_options.lengths[i % len(self.experiment_options.lengths)], - "group": "Clifford", - "physical_qubits": self.physical_qubits, - "target": self._clifford_utils.compute_target_bitstring(circ), - "inverting_pauli_layer": self.experiment_options.inverting_pauli_layer, - } circ.measure_all() # includes insertion of the barrier before measurement circuits.append(circ) return circuits - def _pauli_dress(self, element_list: List, rng) -> List: + def _pauli_dress(self, element_list: List, rng: Generator) -> List: """Interleaving layers of random Paulis inside the element list. Args: element_list: The list of elements we add the interleaved Paulis to. - rng: (Seed for) random number generator + rng: Randomness generator Returns: The new list of elements with the Paulis interleaved. @@ -314,85 +338,25 @@ def _pauli_dress(self, element_list: List, rng) -> List: def _transpiled_circuits(self) -> List[QuantumCircuit]: return super()._transpiled_circuits(custom_transpile=True) - def _start_end_cliffords(self, elements: Iterable[Clifford], rng) -> List[QuantumCircuit]: + def _start_end_cliffords( + self, elements: Iterable[Clifford], rng: Generator + ) -> List[QuantumCircuit]: """Add a layer of uniformly random 1-qubit Cliffords to the beginning of the list and its inverse to the end of the list. Args: element_list: The list of elements we add the Clifford layers to - rng: (Seed for) random number generator + rng: Randomness generator Returns: The new list of elements with the start and end local (1-qubit) Cliffords. """ - basis_gates = self._get_basis_gates() - rand_clifford = rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=self.num_qubits) - circ = QuantumCircuit(self.num_qubits) - for i, cliff in enumerate(rand_clifford): - circ.append(self._to_instruction(cliff, basis_gates, gate_size=1), [circ.qubits[i]]) - circ.append(Barrier(self.num_qubits), circ.qubits) - - return [circ] + elements + [circ.inverse()] - def _generate_mirror( - self, elements: Iterable[Clifford], lengths: Iterable[int] - ) -> List[QuantumCircuit]: - """Return the RB circuits constructed from the given element list with the second - half as the inverse of the first half - - Args: - elements: A list of Clifford elements - lengths: A list of RB sequences lengths. + rand_clifford = [random_clifford(1, rng) for i in range(self.num_qubits)] + tensor_op = rand_clifford[0] + for cliff in rand_clifford[1:]: + tensor_op = tensor_op ^ cliff + tensor_circ = tensor_op.to_circuit() - Returns: - A list of :class:`QuantumCircuit`. - - Additional information: - The circuits are constructed iteratively; each circuit is obtained - by extending the previous circuit (without the inversion and measurement gates) - """ - qubits = list(range(self.num_qubits)) - circuits = [] - - circs = [QuantumCircuit(self.num_qubits) for _ in range(len(lengths))] - - for current_length, group_elt_circ in enumerate(elements[: (len(elements) // 2)]): - if isinstance(group_elt_circ, tuple): - group_elt_gate = group_elt_circ[0] - else: - group_elt_gate = group_elt_circ - - if not isinstance(group_elt_gate, Instruction): - group_elt_gate = group_elt_gate.to_instruction() - for circ in circs: - circ.barrier(qubits) - circ.append(group_elt_gate, qubits) - - double_current_length = ( - (current_length + 1) * 2 + 1 if len(elements) % 2 == 1 else (current_length + 1) * 2 - ) - if double_current_length in lengths: - rb_circ = circs.pop() - inv_start = ( - (-(current_length + 1) - 1) if len(elements) % 2 == 1 else -(current_length + 1) - ) - for inv in elements[inv_start:]: - if isinstance(inv, tuple): - group_elt_gate = inv[0] - else: - group_elt_gate = inv - - if not isinstance(group_elt_gate, Instruction): - group_elt_gate = group_elt_gate.to_instruction() - rb_circ.barrier(qubits) - rb_circ.append(group_elt_gate, qubits) - rb_circ.metadata = { - "experiment_type": self._type, - "xval": double_current_length, - "group": "Clifford", - "physical_qubits": self.physical_qubits, - "target": self._clifford_utils.compute_target_bitstring(rb_circ), - "inverting_pauli_layer": self._inverting_pauli_layer, - } - circuits.append(rb_circ) - return circuits + rand_clifford = random_clifford(self.num_qubits, seed=rng).to_circuit() + return [tensor_circ] + elements + [tensor_circ.inverse()] diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 8fc885531b..98ee8283d0 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -41,8 +41,6 @@ from qiskit.converters import circuit_to_dag from .clifford_utils import CliffordUtils -# SequenceElementType = Union[Clifford, Integral, QuantumCircuit] - class MirrorRBSampler(ABC): """Sampling distribution for the mirror randomized benchmarking experiment.""" @@ -52,7 +50,8 @@ def __init__(self): @abstractmethod def __call__(self, num_qubits, seed=None, **params): - self.num_qubits = num_qubits + """Samplers should define this method so that it returns a single sampled layer.""" + pass class EdgeGrabSampler(MirrorRBSampler): @@ -112,7 +111,7 @@ def __call__( TypeError: If invalid gate set(s) are specified. Returns: - ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over + A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over ``num_qubits`` qubits. """ diff --git a/test/library/randomized_benchmarking/test_clifford_utils.py b/test/library/randomized_benchmarking/test_clifford_utils.py index 000ed3c36c..ab0ceea675 100644 --- a/test/library/randomized_benchmarking/test_clifford_utils.py +++ b/test/library/randomized_benchmarking/test_clifford_utils.py @@ -195,3 +195,17 @@ def test_num_from_layer(self): circ.compose(_CLIFFORD_LAYER[layer][idx], inplace=True) layered = Clifford(circ) self.assertEqual(standard, layered) + + def test_target_bitstring(self, qubits): + """Test if correct target bitstring is returned.""" + qc = QuantumCircuit(9) + qc.z(0) + qc.y(1) + qc.y(2) + qc.z(3) + qc.y(4) + qc.x(7) + qc.y(8) + expected_tb = compute_target_bitstring(qc) + actual_tb = "110010110" + self.assertEqual(expected_tb, actual_tb) diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index d421bc47b4..cf8484c11b 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -31,6 +31,9 @@ from qiskit_experiments.database_service.exceptions import ExperimentEntryNotFound from qiskit_experiments.framework.composite import ParallelExperiment from qiskit_experiments.library import randomized_benchmarking as rb +from qiskit_experiments.library.randomized_benchmarking.clifford_utils import ( + compute_target_bitstring, +) class RBTestMixin: @@ -827,7 +830,6 @@ def test_expdata_serialization(self): self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) - class NonlocalCXDepError(TransformationPass): """Transpiler pass for simulating nonlocal errors in a quantum device""" @@ -927,36 +929,18 @@ def setUp(self): "optimization_level": 1, } - def test_custom_distribution(self): - """Test providing a custom distribution.""" - qubits = ( - 0, - 1, - 2, - ) - exp = rb.MirrorRB( - physical_qubits=qubits, - distribution=rb.RandomEdgeGrabDistribution, - two_qubit_gate_density=0.5, - lengths=list(range(2, 300, 20)), - seed=124, - backend=self.backend, - num_samples=30, - ) - # test that feeding the circuit from edge grab into discrete yields the same answer(?) - def test_return_same_circuit(self): """Test if setting the same seed returns the same circuits.""" lengths = [10, 20] exp1 = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=lengths, seed=123, backend=self.backend, ) exp2 = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=lengths, seed=123, backend=self.backend, @@ -971,7 +955,7 @@ def test_return_same_circuit(self): def test_full_sampling(self): """Test if full sampling generates different circuits.""" exp1 = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=[10, 20], seed=123, backend=self.backend, @@ -980,7 +964,7 @@ def test_full_sampling(self): ) exp2 = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=[10, 20], seed=123, backend=self.backend, @@ -997,26 +981,11 @@ def test_full_sampling(self): # top of previous length self.assertNotEqual(circs1[1].decompose(), circs2[1].decompose()) - def test_target_bitstring(self): - """Test if correct target bitstring is returned.""" - qc = QuantumCircuit(9) - qc.z(0) - qc.y(1) - qc.y(2) - qc.z(3) - qc.y(4) - qc.x(7) - qc.y(8) - exp = rb.MirrorRB(qubits=[0], lengths=[2], backend=self.backend) - expected_tb = exp._clifford_utils.compute_target_bitstring(qc) - actual_tb = "110010110" - self.assertEqual(expected_tb, actual_tb) - def test_zero_2q_gate_density(self): """Test that there are no two-qubit gates when the two-qubit gate density is set to 0.""" exp = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=[40], seed=124, backend=self.backend, @@ -1035,7 +1004,7 @@ def test_max_2q_gate_density(self): connectivity).""" backend = AerSimulator(coupling_map=CouplingMap.from_full(4).get_edges()) exp = rb.MirrorRB( - qubits=(0, 1, 2, 3), + physical_qubits=(0, 1, 2, 3), lengths=[40], seed=125, backend=backend, @@ -1053,7 +1022,7 @@ def test_local_clifford(self): """Test that the number of layers is correct depending on whether local_clifford is set to True or False by counting the number of barriers.""" exp = rb.MirrorRB( - qubits=(0,), + physical_qubits=(0,), lengths=[2], seed=126, backend=self.backend, @@ -1074,7 +1043,7 @@ def test_pauli_randomize(self): """Test that the number of layers is correct depending on whether pauli_randomize is set to True or False by counting the number of barriers.""" exp = rb.MirrorRB( - qubits=(0,), + physical_qubits=(0,), lengths=[2], seed=126, backend=self.backend, @@ -1092,12 +1061,10 @@ def test_pauli_randomize(self): self.assertEqual(6, num_barriers) def test_inverting_pauli_layer(self): - """Test that a circuit with an inverting Pauli layer at the end (i.e., - a layer of Paulis before the final measurement that restores the output - to |0>^num_qubits up to a global phase) composes to the identity (up to - a global phase)""" + """Test that a circuit with an inverting Pauli layer at the end generates + an all-zero output.""" exp = rb.MirrorRB( - qubits=(0, 1, 2), + physical_qubits=(0, 1, 2), lengths=[2], seed=127, backend=self.backend, @@ -1107,18 +1074,21 @@ def test_inverting_pauli_layer(self): two_qubit_gate_density=0.2, inverting_pauli_layer=True, ) - self.assertAllIdentity(exp.circuits()) + self.assertEqual( + compute_target_bitstring(exp.circuits()[0].remove_final_measurements(inplace=False)), + "000", + ) def test_experiment_config(self): """Test converting to and from config works""" - exp = rb.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123, backend=self.backend) + exp = rb.MirrorRB([0], lengths=[10, 20, 30], seed=123, backend=self.backend) loaded_exp = rb.MirrorRB.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.MirrorRB(qubits=(0,), lengths=[10, 20, 30], seed=123) + exp = rb.MirrorRB([0], lengths=[10, 20, 30], seed=123) self.assertRoundTripSerializable(exp, self.json_equiv) def test_analysis_config(self): @@ -1164,7 +1134,7 @@ def test_two_qubit(self): """Test two qubit RB.""" two_qubit_gate_density = 0.2 exp = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=list(range(2, 300, 20)), seed=123, backend=self.backend, @@ -1223,7 +1193,7 @@ def test_two_qubit_nonlocal_noise(self): two_qubit_gate_density = 0.2 exp = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=list(range(2, 110, 20)), seed=123, backend=noise_backend, @@ -1281,7 +1251,7 @@ def test_three_qubit_nonlocal_noise(self): two_qubit_gate_density = 0.2 exp = rb.MirrorRB( - qubits=(0, 1, 2), + physical_qubits=(0, 1, 2), lengths=list(range(2, 110, 50)), seed=123, backend=noise_backend, @@ -1310,7 +1280,7 @@ def test_three_qubit_nonlocal_noise(self): def test_add_more_circuit_yields_lower_variance(self): """Test variance reduction with larger number of sampling.""" exp1 = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=list(range(2, 30, 4)), seed=123, backend=self.backend, @@ -1323,7 +1293,7 @@ def test_add_more_circuit_yields_lower_variance(self): self.assertExperimentDone(expdata1) exp2 = rb.MirrorRB( - qubits=(0, 1), + physical_qubits=(0, 1), lengths=list(range(2, 30, 4)), seed=456, backend=self.backend, @@ -1435,7 +1405,7 @@ def test_warnings(self, configs): def test_expdata_serialization(self): """Test serializing experiment data works.""" exp = rb.MirrorRB( - qubits=(0,), + physical_qubits=(0,), lengths=list(range(2, 200, 50)), seed=123, backend=self.backend, From f06dbc9f10f379b64c12150cc93f16b888fd643f Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Fri, 17 Mar 2023 03:51:54 -0400 Subject: [PATCH 33/56] restored some RB changes and fixed tests --- .../randomized_benchmarking/clifford_utils.py | 3 +- .../mirror_rb_experiment.py | 11 +-- .../randomized_benchmarking/rb_experiment.py | 10 +-- .../test_clifford_utils.py | 3 + .../test_randomized_benchmarking.py | 82 +++++++++++++++---- 5 files changed, 75 insertions(+), 34 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index eea3d05922..f034c8562d 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -15,10 +15,9 @@ import itertools import os -import warnings from functools import lru_cache from numbers import Integral -from typing import Optional, Union, Tuple, Sequence, List +from typing import Optional, Union, Tuple, Sequence import numpy as np import scipy.sparse diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 84b1a4af5a..5cba68a06c 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -28,18 +28,11 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit_experiments.warnings import deprecate_arguments -from .rb_experiment import StandardRB +from .rb_experiment import StandardRB, SequenceElementType from .mirror_rb_analysis import MirrorRBAnalysis -from .clifford_utils import ( - CliffordUtils, - _decompose_clifford_ops, - _clifford_1q_int_to_instruction, - compute_target_bitstring, -) +from .clifford_utils import compute_target_bitstring from .sampling_utils import MirrorRBSampler, EdgeGrabSampler -SequenceElementType = Union[Clifford, Integral, QuantumCircuit] - class MirrorRB(StandardRB): """An experiment to measure gate infidelity using random mirrored layers of Clifford diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 354c6d472c..824941cb60 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -279,7 +279,7 @@ def _sequences_to_circuits( # Compute inverse, compute only the difference from the previous shorter sequence prev_elem = self.__compose_clifford_seq(prev_elem, seq[len(prev_seq) :]) prev_seq = seq - inv = self._adjoint_clifford(prev_elem) + inv = self.__adjoint_clifford(prev_elem) circ.append(self._to_instruction(inv, basis_gates), circ.qubits) circ.measure_all() # includes insertion of the barrier before measurement @@ -300,13 +300,12 @@ def _to_instruction( self, elem: SequenceElementType, basis_gates: Optional[Tuple[str, ...]] = None, - gate_size=None, ) -> Instruction: # Switching for speed up if isinstance(elem, Integral): - if self.num_qubits == 1 or gate_size == 1: + if self.num_qubits == 1: return _clifford_1q_int_to_instruction(elem, basis_gates) - if self.num_qubits == 2 or gate_size == 2: + if self.num_qubits == 2: return _clifford_2q_int_to_instruction(elem, basis_gates) return elem.to_instruction() @@ -329,7 +328,7 @@ def __compose_clifford_seq( circ.compose(elem, inplace=True) return base_elem.compose(Clifford.from_circuit(circ)) - def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: + def __adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: if self.num_qubits == 1: return inverse_1q(op) if self.num_qubits == 2: @@ -338,6 +337,7 @@ def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: return Clifford.from_circuit(op).adjoint() return op.adjoint() + # pyline: disable=arguments-differ def _transpiled_circuits(self, custom_transpile=False) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" has_custom_transpile_option = ( diff --git a/test/library/randomized_benchmarking/test_clifford_utils.py b/test/library/randomized_benchmarking/test_clifford_utils.py index ab0ceea675..8d656eaf2e 100644 --- a/test/library/randomized_benchmarking/test_clifford_utils.py +++ b/test/library/randomized_benchmarking/test_clifford_utils.py @@ -44,6 +44,9 @@ _layer_indices_from_num, _CLIFFORD_LAYER, ) +from qiskit_experiments.library.randomized_benchmarking.clifford_utils import ( + compute_target_bitstring, +) @ddt diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index cf8484c11b..e6d3303627 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -24,10 +24,13 @@ from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington, FakeParis from qiskit.pulse import Schedule, InstructionScheduleMap from qiskit.quantum_info import Operator -from qiskit_aer import AerSimulator -from qiskit_aer.noise import NoiseModel, depolarizing_error from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler import Layout, PassManager, CouplingMap +from qiskit.transpiler.exceptions import TranspilerError + +from qiskit_aer import AerSimulator +from qiskit_aer.noise import NoiseModel, depolarizing_error + from qiskit_experiments.database_service.exceptions import ExperimentEntryNotFound from qiskit_experiments.framework.composite import ParallelExperiment from qiskit_experiments.library import randomized_benchmarking as rb @@ -545,6 +548,7 @@ def test_single_qubit(self): epc = expdata.analysis_results("EPC") epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 1.0 + print(epc.value.n) self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) def test_two_qubit(self): @@ -1099,19 +1103,59 @@ def test_analysis_config(self): self.assertEqual(analysis.config(), loaded.config()) +@ddt class TestRunMirrorRB(RBRunTestCase): + """Class for testing execution of mirror RB experiments.""" + + def setUp(self): + """Setup the tests.""" + super().setUp() + + # depolarizing error + self.p1q = 0.02 + self.p2q = 0.10 + self.pvz = 0.0 + + # basis gates + self.basis_gates = ["sx", "rz", "cx", "id"] + + # setup noise model + sx_error = depolarizing_error(self.p1q, 1) + rz_error = depolarizing_error(self.pvz, 1) + cx_error = depolarizing_error(self.p2q, 2) + + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(sx_error, "sx") + noise_model.add_all_qubit_quantum_error(rz_error, "rz") + noise_model.add_all_qubit_quantum_error(cx_error, "cx") + + self.noise_model = noise_model + self.basis_gates = noise_model.basis_gates + + # Need level1 for consecutive gate cancellation for reference EPC value calculation + self.transpiler_options = { + "basis_gates": self.basis_gates, + "optimization_level": 1, + } + + # Aer simulator + self.backend = AerSimulator( + noise_model=noise_model, + seed_simulator=123, + coupling_map=AerSimulator.from_backend(FakeParis()).configuration().coupling_map, + ) + def test_single_qubit(self): """Test single qubit mirror RB.""" exp = rb.MirrorRB( physical_qubits=(0,), - lengths=list(range(2, 300, 20)), + lengths=list(range(2, 300, 40)), seed=124, backend=self.backend, - num_samples=30, + num_samples=20, ) - # exp.analysis.set_options(gate_error_ratio=None) + exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) - self.assertAllIdentity(exp.circuits()) expdata = exp.run() self.assertExperimentDone(expdata) @@ -1128,6 +1172,8 @@ def test_single_qubit(self): # formula should be EPC = 1 - (1 - r)^(n_gpc + n_gpp) = 1 - (1 - r)^2 epc = expdata.analysis_results("EPC") epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 + + print(epc.value.n) self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) def test_two_qubit(self): @@ -1135,10 +1181,10 @@ def test_two_qubit(self): two_qubit_gate_density = 0.2 exp = rb.MirrorRB( physical_qubits=(0, 1), - lengths=list(range(2, 300, 20)), + lengths=list(range(2, 300, 40)), seed=123, backend=self.backend, - num_samples=30, + num_samples=20, two_qubit_gate_density=two_qubit_gate_density, ) exp.analysis.set_options(gate_error_ratio=None) @@ -1312,49 +1358,49 @@ def test_add_more_circuit_yields_lower_variance(self): @data( { - "qubits": [3, 3], + "physical_qubits": [3, 3], "lengths": [2, 4, 6, 8, 10], "num_samples": 1, "seed": 100, "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), }, # repeated qubits { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 4, 6, -8, 10], "num_samples": 1, "seed": 100, "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), }, # negative length { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 4, 6, 8, 10], "num_samples": -4, "seed": 100, "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), }, # negative number of samples { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 4, 6, 8, 10], "num_samples": 0, "seed": 100, "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), }, # zero samples { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 6, 6, 6, 10], "num_samples": 2, "seed": 100, "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), }, # repeated lengths { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 4, 5, 8, 10], "num_samples": 2, "seed": 100, "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), }, # odd length { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 4, 6, 8, 10], "num_samples": 1, "seed": 100, @@ -1368,7 +1414,7 @@ def test_invalid_configuration(self, configs): @data( { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 4, 6, 8, 10], "num_samples": 1, "seed": 100, @@ -1382,14 +1428,14 @@ def test_no_backend(self, configs): @data( { - "qubits": [0, 4], + "physical_qubits": [0, 4], "lengths": [2, 4, 6, 8, 10], "num_samples": 1, "seed": 100, "backend": AerSimulator.from_backend(FakeManila()), }, # Uncoupled qubits to test edgegrab algorithm warning { - "qubits": [0, 1], + "physical_qubits": [0, 1], "lengths": [2, 4, 6, 8, 10], "num_samples": 1, "seed": 100, From e69701d44455b9880ba0448e1c09ad7a74f7c7d9 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Fri, 17 Mar 2023 04:56:42 -0400 Subject: [PATCH 34/56] updated manual --- docs/conf.py | 1 + docs/manuals/benchmarking/mirror_rb.rst | 80 ++++++++----------- .../mirror_rb_analysis.py | 6 +- .../test_randomized_benchmarking.py | 27 +------ 4 files changed, 38 insertions(+), 76 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f9834b2f1b..c970be3852 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,6 +97,7 @@ "manuals/benchmarking/quantum_volume": "_images/quantum_volume_2_0.png", "manuals/measurement/readout_mitigation": "_images/readout_mitigation_4_0.png", "manuals/benchmarking/randomized_benchmarking": "_images/randomized_benchmarking_3_1.png", + "manuals/benchmarking/mirror_rb": "_images/mirror_rb_1_1.png", "manuals/measurement/restless_measurements": "_images/restless_shots.png", "manuals/benchmarking/state_tomography": "_images/state_tomography_3_0.png", "manuals/characterization/t1": "_images/t1_0_0.png", diff --git a/docs/manuals/benchmarking/mirror_rb.rst b/docs/manuals/benchmarking/mirror_rb.rst index ac4a9e6400..44cdf0b4f0 100644 --- a/docs/manuals/benchmarking/mirror_rb.rst +++ b/docs/manuals/benchmarking/mirror_rb.rst @@ -15,8 +15,8 @@ randomized Clifford mirror circuit [1]_ consists of: - a layer of uniformly random one-qubit Cliffords at the beginning and the end of the circuit. -Because the Clifford gates are only one- and two-qubit, unlike in standard RB, which -requires the implementation of n-qubit Cliffords, mirror RB ????. Mirror RB can also be +Note that the Clifford gates are only one- and two-qubit, unlike in standard RB, which +requires the implementation of n-qubit Cliffords. Mirror RB can also be generalized to universal gatesets beyond the Cliffords [2]_. Output metrics @@ -87,7 +87,9 @@ user can specify an expected two-qubit gate density :math:`\xi \in \left[0, Even though a :class:`.MirrorRB` experiment can be instantiated without a backend, the backend must be specified when the circuits are sampled because :math:`\Omega` depends -on the backend's connectivity. Here is a typical way to instantiate and run the +on the backend's connectivity. To use your own :math:`\Omega`, you have to implement +your own subclass of the abstract :class:`.MirrorRBSampler` class, but here we will use +the built-in :class:`.EdgeGrabSampler`. Here's how to instantiate and run the experiment: .. jupyter-execute:: @@ -96,8 +98,13 @@ experiment: from qiskit_experiments.library import MirrorRB from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler + from qiskit_aer import AerSimulator + from qiskit.providers.fake_provider import FakeParis + + backend = AerSimulator.from_backend(FakeParis()) + lengths = np.arange(2, 810, 200) - num_samples = 30 + num_samples = 5 seed = 1010 qubits = (0,) @@ -109,33 +116,6 @@ experiment: two_qubit_gate_density=.4, distribution=EdgeGrabSampler) - exp_1q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) - expdata_1q = exp_1q.run(backend).block_for_results() - results_1q = expdata_1q.analysis_results() - -.. jupyter-execute:: - - print("Gate error ratio: %s" % expdata_1q.experiment.analysis.options.gate_error_ratio) - display(expdata_1q.figure(0)) - for result in results_1q: - print(result) - - -.. jupyter-execute:: - - # Two-qubit circuit example - exp_2q_circ = MirrorRB((0,1), lengths=[4], backend=backend, num_samples=1, seed=1010, two_qubit_gate_density=.4) - qc2 = exp_2q_circ.circuits()[0].decompose() - qc2.draw() - -.. jupyter-execute:: - - lengths = np.arange(2, 810, 200) - num_samples = 30 - seed = 1011 - qubits = (0,1) - - # Run a MRB experiment on qubits 0, 1 exp_2q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) expdata_2q = exp_2q.run(backend).block_for_results() results_2q = expdata_2q.analysis_results() @@ -148,24 +128,17 @@ experiment: for result in results_2q: print(result) -Using your own custom :math:`\Omega` ------------------------------------- - -To use your own :math:`\Omega`, you have to implement your own subclass of the abstract -:class:`.MirrorRBSampler` class. - - Selecting :math:`y`-axis values ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can set what you want to use as the :math:`y`-axis metric for fitting by setting the ``y-axis`` analysis option. Here's an example of plotting the success probability -instead of the default +instead of the default: .. jupyter-execute:: lengths = [2, 52, 102, 152] - num_samples = 30 + num_samples = 5 seed = 42 qubits = (0,) @@ -173,8 +146,7 @@ instead of the default # select y-axis exp.analysis.set_options(y_axis="Success Probability") # or "Adjusted Success Probability" or "Effective Polarization" # y-axis label must be set separately - exp.analysis.options.curve_drawer.set_options( - # xlabel="Clifford Length", + exp.analysis.options.plotter.set_figure_options( ylabel="Success Probability", ) expdata = exp.run(backend).block_for_results() @@ -202,14 +174,32 @@ object is instantiated: - ``two_qubit_gate_density`` (default ``0.2``): expected fraction of two-qubit gates in each intermediate Clifford layer -- ``inverting_pauli_layer`` (default ``False``): if ``True``, put a layer of +- ``inverting_pauli_layer`` (default ``False``): if ``True``, add a layer of Paulis at the end of the circuit to set the output to :math:`\left\vert0\right\rangle^{\otimes n}`, up to a global phase -Let's look at how these options change the circuit: +Let's look at how these options change the circuit. First, the default with Pauli +layers between Cliffords and single-qubit Cliffords at the start and end: -## insert draw stuff here +.. jupyter-execute:: + + exp = MirrorRB((0,1,2), + lengths=[2], + backend=backend, + num_samples=1) + exp.circuits()[0].decompose().draw("mpl") + +And now with both options turned off: + +.. jupyter-execute:: + exp = MirrorRB((0,1,2), + lengths=[2], + backend=backend, + num_samples=1, + local_clifford=False, + pauli_randomize=False) + exp.circuits()[0].decompose().draw("mpl") Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index bedace05d6..dde7e8a95f 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -108,11 +108,7 @@ class MirrorRBAnalysis(curve.CurveAnalysis): def __init__(self): super().__init__( - models=[ - lmfit.models.ExpressionModel( - expr="a * alpha ** x + b", name="mirror", data_sort_key={"mirror": True} - ) - ] + models=[lmfit.models.ExpressionModel(expr="a * alpha ** x + b", name="mirror")] ) self._gate_counts_per_clifford = None self._physical_qubits = None diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index e6d3303627..9d910f587c 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -37,6 +37,7 @@ from qiskit_experiments.library.randomized_benchmarking.clifford_utils import ( compute_target_bitstring, ) +from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler class RBTestMixin: @@ -1173,7 +1174,6 @@ def test_single_qubit(self): epc = expdata.analysis_results("EPC") epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 - print(epc.value.n) self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) def test_two_qubit(self): @@ -1189,7 +1189,6 @@ def test_two_qubit(self): ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**self.transpiler_options) - self.assertAllIdentity(exp.circuits()) expdata = exp.run() self.assertExperimentDone(expdata) @@ -1248,7 +1247,6 @@ def test_two_qubit_nonlocal_noise(self): ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**transpiler_options) - self.assertAllIdentity(exp.circuits()) expdata = exp.run(noise_backend) self.assertExperimentDone(expdata) @@ -1306,7 +1304,6 @@ def test_three_qubit_nonlocal_noise(self): ) exp.analysis.set_options(gate_error_ratio=None) exp.set_transpile_options(**transpiler_options) - self.assertAllIdentity(exp.circuits()) expdata = exp.run(noise_backend) self.assertExperimentDone(expdata) @@ -1426,28 +1423,6 @@ def test_no_backend(self, configs): mirror_exp = rb.MirrorRB(**configs) self.assertRaises(QiskitError, mirror_exp.run) - @data( - { - "physical_qubits": [0, 4], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "backend": AerSimulator.from_backend(FakeManila()), - }, # Uncoupled qubits to test edgegrab algorithm warning - { - "physical_qubits": [0, 1], - "lengths": [2, 4, 6, 8, 10], - "num_samples": 1, - "seed": 100, - "two_qubit_gate_density": 0.6, - "backend": AerSimulator(coupling_map=[[0, 1], [1, 0]]), - }, # High two-qubit gate density warning - ) - def test_warnings(self, configs): - """Test raise warnings when creating experiment.""" - mirror_exp = rb.MirrorRB(**configs) - self.assertWarns(Warning, mirror_exp.run) - def test_expdata_serialization(self): """Test serializing experiment data works.""" exp = rb.MirrorRB( From e6f8a07c4c6acf644cfb174317352973a2c820bd Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Sat, 18 Mar 2023 23:46:51 -0400 Subject: [PATCH 35/56] replaced missing function --- .../test_randomized_benchmarking.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 9d910f587c..520bb3aff1 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -835,6 +835,13 @@ def test_expdata_serialization(self): self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) +def decr_dep_param(q, q_1, q_2, coupling_map): + """Helper function to generate a one-qubit depolarizing channel whose + parameter depends on coupling map distance in a backend""" + d = min(coupling_map.distance(q, q_1), coupling_map.distance(q, q_2)) + return 0.0035 * 0.999**d + + class NonlocalCXDepError(TransformationPass): """Transpiler pass for simulating nonlocal errors in a quantum device""" @@ -1103,6 +1110,26 @@ def test_analysis_config(self): self.assertNotEqual(analysis, loaded) self.assertEqual(analysis.config(), loaded.config()) + def test_backend_with_directed_basis_gates(self): + """Test if correct circuits are generated from backend with directed basis gates.""" + my_backend = copy.deepcopy(self.backend) + del my_backend.target["cx"][(1, 2)] # make cx on {1, 2} one-sided + + exp = rb.MirrorRB( + physical_qubits=(1, 2), + two_qubit_gate_density=1, + lengths=[3], + num_samples=4, + backend=my_backend, + ) + transpiled = exp._transpiled_circuits() + for qc in transpiled: + self.assertTrue(qc.count_ops().get("cx", 0) > 0) + expected_qubits = (qc.qubits[2], qc.qubits[1]) + for inst in qc: + if inst.operation.name == "cx": + self.assertEqual(inst.qubits, expected_qubits) + @ddt class TestRunMirrorRB(RBRunTestCase): From 76517986bb3102a7425272e6df8a3706c7f97a33 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 21 Mar 2023 16:09:34 -0400 Subject: [PATCH 36/56] rewrote circuit generation logic and sampler the sampler now outputs tuples of indices and elements instead of circuit layers. 1q cliffords are kept as integers through the entire sampling process. performance has improved a lot. --- .../randomized_benchmarking/__init__.py | 3 +- .../mirror_rb_experiment.py | 183 ++++++++++-------- .../randomized_benchmarking/sampling_utils.py | 155 +++++++++++---- .../test_clifford_utils.py | 2 +- 4 files changed, 228 insertions(+), 115 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index af22cf54fc..19eafd78aa 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -48,12 +48,13 @@ RBUtils MirrorRBSampler EdgeGrabSampler + SingleQubitSampler """ from .rb_experiment import StandardRB from .interleaved_rb_experiment import InterleavedRB from .mirror_rb_experiment import MirrorRB -from .sampling_utils import MirrorRBSampler, EdgeGrabSampler +from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler from .rb_analysis import RBAnalysis from .interleaved_rb_analysis import InterleavedRBAnalysis from .mirror_rb_analysis import MirrorRBAnalysis diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 5cba68a06c..9ac48e2628 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -12,10 +12,10 @@ """ Mirror RB Experiment class. """ -from typing import Union, Iterable, Optional, List, Sequence +from typing import Union, Iterable, Optional, List, Sequence, Tuple from numbers import Integral -from itertools import permutations - +import itertools +from time import time from numpy.random import Generator, BitGenerator, SeedSequence, default_rng @@ -30,8 +30,21 @@ from .rb_experiment import StandardRB, SequenceElementType from .mirror_rb_analysis import MirrorRBAnalysis -from .clifford_utils import compute_target_bitstring -from .sampling_utils import MirrorRBSampler, EdgeGrabSampler +from .clifford_utils import compute_target_bitstring, CliffordUtils, inverse_1q +from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler + + +def timer_func(func): + # This function shows the execution time of + # the function object passed + def wrap_func(*args, **kwargs): + t1 = time() + result = func(*args, **kwargs) + t2 = time() + print(f"Function {func.__name__!r} executed in {(t2-t1):.4f}s") + return result + + return wrap_func class MirrorRB(StandardRB): @@ -67,7 +80,7 @@ def __init__( self, physical_qubits: Sequence[int], lengths: Iterable[int], - distribution: MirrorRBSampler = EdgeGrabSampler, + distribution: RBSampler = EdgeGrabSampler, local_clifford: bool = True, pauli_randomize: bool = True, two_qubit_gate_density: float = 0.2, @@ -171,6 +184,25 @@ def circuits(self) -> List[QuantumCircuit]: return circuits + def _inverse_layer(self, layer) -> List[Tuple[Union[int, Tuple], int]]: + """Generates the inverse layer of a Clifford mirror RB layer by inverting the + single-qubit Cliffords and keeping the CXs identical. See + :class:`.RBSampler` for the format of the layer. + + Raises: + QiskitError: If the layer has invalid format. + """ + inverse_layer = [] + for elem in layer: + if isinstance(elem[0], int): + inverse_layer.append((elem[0], inverse_1q(elem[1]))) + elif isinstance(elem[0], tuple): + inverse_layer.append(elem) + else: + raise QiskitError("Invalid layer from sampler.") + return tuple(inverse_layer) + + @timer_func def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: """Sample layers of mirror RB using the provided distribution and user options. First, layers are sampled using the distribution, then Pauli-dressed if @@ -186,13 +218,12 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: A list of mirror RB sequences. Each element is a list of layers with length matching the corresponding element in ``lengths``. """ - rng = default_rng(seed=self.experiment_options.seed) if not self._backend: - raise QiskitError("A backend must be provided.") + raise QiskitError("A backend must be provided for circuit generation.") # Coupling map is full connectivity by default. If backend has a coupling map, # get backend coupling map and create coupling map for physical qubits - coupling_map = list(permutations(range(max(self.physical_qubits) + 1), 2)) + coupling_map = list(itertools.permutations(range(max(self.physical_qubits) + 1), 2)) if self._backend_data.coupling_map: coupling_map = self._backend_data.coupling_map experiment_coupling_map = [] @@ -200,75 +231,74 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append(edge) - # adjust the density based on whether the pauli layers are in + rng = default_rng(seed=self.experiment_options.seed) + + sequences = [] + + # Adjust the density based on whether the pauli layers are in if self.experiment_options.pauli_randomize: adjusted_2q_density = self.experiment_options.two_qubit_gate_density * 2 else: adjusted_2q_density = self.experiment_options.two_qubit_gate_density - sequences = [] + # Sequence of lengths to sample for + if not self.experiment_options.full_sampling: + seqlens = (max(self.experiment_options.lengths),) + build_seq_lengths = self.experiment_options.lengths + else: + seqlens = self.experiment_options.lengths - if self.experiment_options.full_sampling: - for _ in range(self.experiment_options.num_samples): - for length in self.experiment_options.lengths: - # Sample Clifford layer elements for first half of mirror circuit - elements = self._distribution( + for _ in range(self.experiment_options.num_samples): + for seqlen in seqlens: + seq = [] + layers = list( + self._distribution( self.num_qubits, adjusted_2q_density, experiment_coupling_map, - length // 2, + seqlen // 2, seed=rng, ) - # Append inverses of Clifford elements to second half of circuit - for element in elements[::-1]: - elements.append(self._adjoint_clifford(element)) - - # Interleave random Paulis if set by user - if self.experiment_options.pauli_randomize: - elements = self._pauli_dress(elements, rng) - - # Add start and end local cliffords if set by user - if self.experiment_options.local_clifford: - elements = self._start_end_cliffords(elements, rng) - - sequences.append(elements) - else: - for _ in range(self.experiment_options.num_samples): - longest_seq = self._distribution( - self.num_qubits, - adjusted_2q_density, - experiment_coupling_map, - max(self.experiment_options.lengths) // 2, - seed=rng, ) - element_lengths = self.experiment_options.lengths + seq.extend(layers) + + # Add the second half mirror layers + for i in range(len(list(layers))): + seq.append(self._inverse_layer(layers[-i - 1])) - # Append inverses of Clifford elements to second half of circuit - for element in longest_seq[::-1]: - longest_seq.append(self._adjoint_clifford(element)) # Interleave random Paulis if set by user if self.experiment_options.pauli_randomize: - longest_seq = self._pauli_dress(longest_seq, rng) - element_lengths = [length * 2 + 1 for length in element_lengths] + sampler = SingleQubitSampler() + pauli_layers = sampler(self.num_qubits, seqlen + 1, "pauli", rng) + seq = list(itertools.chain(*zip(pauli_layers[:-1], seq))) + seq.append(pauli_layers[-1]) + if not self.experiment_options.full_sampling: + build_seq_lengths = [length * 2 + 1 for length in build_seq_lengths] # Add start and end local cliffords if set by user if self.experiment_options.local_clifford: - longest_seq = self._start_end_cliffords(longest_seq, rng) - element_lengths = [length + 2 for length in element_lengths] - - # Construct the remaining sequences from the longest - for real_length in element_lengths: - sequences.append( - longest_seq[: real_length // 2] + longest_seq[-real_length // 2 :] - ) + cseq = [] + sampler = SingleQubitSampler() + clifford_layers = sampler(self.num_qubits, 1, "clifford", rng) + cseq.append(clifford_layers[0]) + cseq.extend(seq) + cseq.append(self._inverse_layer(clifford_layers[0])) + if not self.experiment_options.full_sampling: + build_seq_lengths = [length + 2 for length in build_seq_lengths] + seq = cseq + + if self.experiment_options.full_sampling: + sequences.append(seq) + + # Construct the rest of the sequences from the longest if `full_sampling` is + # off + if not self.experiment_options.full_sampling: + for real_length in build_seq_lengths: + sequences.append(seq[: real_length // 2] + seq[-real_length // 2 :]) return sequences - def _adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: - if isinstance(op, QuantumCircuit): - return Clifford.from_circuit(op).adjoint() - return op.adjoint() - + @timer_func def _sequences_to_circuits( self, sequences: List[Sequence[SequenceElementType]] ) -> List[QuantumCircuit]: @@ -282,34 +312,30 @@ def _sequences_to_circuits( """ basis_gates = self._get_basis_gates() circuits = [] + for i, seq in enumerate(sequences): circ = QuantumCircuit(self.num_qubits) - for elem in seq: - circ.append(elem.to_instruction(), circ.qubits) + # Hack to get target bitstrings until qiskit-terra#9475 is resolved + circ_target = QuantumCircuit(self.num_qubits) + for layer in seq: + for elem in layer: + circ.append(self._to_instruction(elem[1], basis_gates), [elem[0]]) + circ_target.append(self._to_instruction(elem[1]), [elem[0]]) circ.append(Barrier(self.num_qubits), circ.qubits) - + circ_target.append(Barrier(self.num_qubits), circ_target.qubits) circ.metadata = { "xval": self.experiment_options.lengths[i % len(self.experiment_options.lengths)], "group": "Clifford", "physical_qubits": self.physical_qubits, - "target": compute_target_bitstring(circ), + "target": compute_target_bitstring(circ_target), "inverting_pauli_layer": self.experiment_options.inverting_pauli_layer, } - if self.experiment_options.inverting_pauli_layer: - # Get target bitstring (ideal bitstring outputted by the circuit) - target = circ.metadata["target"] - - # Pauli gates to apply to each qubit to reset each to the state 0. - # E.g., if the ideal bitstring is 01001, the Pauli label is IXIIX, - # which sets all qubits to 0 (up to a global phase) - label = "".join(["X" if char == "1" else "I" for char in target]) - circ.append(Pauli(label), list(range(self._num_qubits))) - - circ.measure_all() # includes insertion of the barrier before measurement + circ.measure_all() circuits.append(circ) return circuits + @timer_func def _pauli_dress(self, element_list: List, rng: Generator) -> List: """Interleaving layers of random Paulis inside the element list. @@ -328,9 +354,11 @@ def _pauli_dress(self, element_list: List, rng: Generator) -> List: new_element_list.append(rand_pauli) return new_element_list + @timer_func def _transpiled_circuits(self) -> List[QuantumCircuit]: - return super()._transpiled_circuits(custom_transpile=True) + return super()._transpiled_circuits() + @timer_func def _start_end_cliffords( self, elements: Iterable[Clifford], rng: Generator ) -> List[QuantumCircuit]: @@ -338,18 +366,21 @@ def _start_end_cliffords( and its inverse to the end of the list. Args: - element_list: The list of elements we add the Clifford layers to + elements: The list of elements we add the Clifford layers to rng: Randomness generator Returns: The new list of elements with the start and end local (1-qubit) Cliffords. """ - rand_clifford = [random_clifford(1, rng) for i in range(self.num_qubits)] + rand_clifford = [ + CliffordUtils.clifford_1_qubit(rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT)) + for _ in range(self.num_qubits) + ] + tensor_op = rand_clifford[0] for cliff in rand_clifford[1:]: tensor_op = tensor_op ^ cliff tensor_circ = tensor_op.to_circuit() - rand_clifford = random_clifford(self.num_qubits, seed=rng).to_circuit() return [tensor_circ] + elements + [tensor_circ.inverse()] diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 98ee8283d0..47e43f0a64 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -15,46 +15,88 @@ import warnings from abc import ABC, abstractmethod -from typing import Optional, Union, Sequence, List, Tuple +from typing import Optional, Union, Sequence, List, Tuple, TypeVar from numbers import Integral import numpy as np from numpy.random import Generator, default_rng, BitGenerator, SeedSequence +from functools import lru_cache -from qiskit import QuantumCircuit, QuantumRegister +from qiskit import QuantumCircuit, QuantumRegister, Operator from qiskit.exceptions import QiskitError from qiskit.circuit import Gate -from qiskit.circuit.library import ( - IGate, - XGate, - YGate, - ZGate, - CXGate, - CYGate, - SGate, - SdgGate, - SXGate, - SXdgGate, -) -from qiskit.quantum_info import random_unitary, random_clifford, Pauli +from qiskit.quantum_info.operators.base_operator import BaseOperator +from qiskit.quantum_info import random_unitary, Pauli, random_pauli from qiskit.extensions import UnitaryGate from qiskit.converters import circuit_to_dag -from .clifford_utils import CliffordUtils +from .clifford_utils import CliffordUtils, _clifford_1q_int_to_instruction +from .rb_experiment import SequenceElementType +from time import time -class MirrorRBSampler(ABC): - """Sampling distribution for the mirror randomized benchmarking experiment.""" +Idx = TypeVar("Idx", int, Tuple[int, ...]) +Gate = TypeVar("Gate", Instruction, Operator, QuantumCircuit, BaseOperator) + + +def timer_func(func): + # This function shows the execution time of + # the function object passed + def wrap_func(*args, **kwargs): + t1 = time() + result = func(*args, **kwargs) + t2 = time() + print(f"Function {func.__name__!r} executed in {(t2-t1):.4f}s") + return result + + return wrap_func + + +class RBSampler(ABC): + """Sampling distribution for randomized benchmarking experiments. + Subclasses must implement the ``__call__()`` method.""" def __init__(self): pass @abstractmethod - def __call__(self, num_qubits, seed=None, **params): - """Samplers should define this method so that it returns a single sampled layer.""" + def __call__(self, num_qubits, seed=None, **params) -> Tuple[Tuple[Idx, Gate], ...]: + """Samplers should define this method such that it returns sampled layers + given the input parameters. Each layer is represented by a list of size-2 tuples + where the first element is a qubit index or a tuple of indices, and the second + element represents the gate that should be applied.""" pass -class EdgeGrabSampler(MirrorRBSampler): +class SingleQubitSampler(RBSampler): + def __call__( + self, + num_qubits, + length, + gate_set: Optional[Union[str, List]] = "clifford", + seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, + ) -> Tuple[Tuple[Idx, Gate], ...]: + """Samples a layer of random single-qubit gates from a specified gate set. + + Returns: + For two qubits and length 3, a possible output would be + (((0,20),(1,14)),((0,11),(1,4)),((0,2),(1,9))) + """ + rng = default_rng(seed=seed) + if gate_set == "clifford": + layers = [] + for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=(length, num_qubits)): + layers.append(tuple(zip((range(num_qubits)), i))) + elif gate_set == "pauli": + layers = [] + for i in range(length): + layers.append(tuple(zip(range(num_qubits), random_pauli(num_qubits, seed=rng)))) + else: + # TODO finish this + pass + return layers + + +class EdgeGrabSampler(RBSampler): r"""The edge grab algorithm for sampling one- and two-qubit layers. # section: overview @@ -81,6 +123,7 @@ class EdgeGrabSampler(MirrorRBSampler): """ + @timer_func def __call__( self, num_qubits: int, @@ -90,7 +133,7 @@ def __call__( one_qubit_gate_set: Optional[Union[str, List]] = "clifford", two_qubit_gate_set: Optional[List] = ["cx"], seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, - ): + ) -> List[List]: """Sample layers using the edge grab algorithm. Args: @@ -112,7 +155,19 @@ def __call__( Returns: A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over - ``num_qubits`` qubits. + ``num_qubits`` qubits. Each layer is represented by a list of tuples + which are of two formats: (single qubit index, single qubit gate) + represented by (int, int), or ((two qubit indices), two qubit gate) + represented by ((int, int), int). Here's an example with the default + choice of Cliffords for the single-qubit gates and CXs for the two-qubit + gates: + + .. code-block:: + (((1, 2), 0), (0, 12), (3, 20)) + + This represents a layer where the 12th Clifford is performed on qubit 0, + a CX is performed with control qubit 1 and target qubit 2, and the 20th + Clifford is performed on qubit 3. """ rng = default_rng(seed=seed) @@ -124,10 +179,17 @@ def __call__( if num_qubits == 1: if one_qubit_gate_set.casefold() == "clifford": - # return rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) - return [random_clifford(1, rng) for i in range(length)] + return ( + ((0, i),) for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) + ) else: - return rng.choice(one_qubit_gate_set, size=length) + return enumerate((0, i) for i in rng.choice(one_qubit_gate_set, size=length)) + + timed = {} + + timed["looptotal"] = time() + timed["2q"] = 0 + timed["cliffs"] = 0 qc_list = [] for _ in list(range(length)): @@ -165,23 +227,42 @@ def __call__( put_1_qubit_gates = np.arange(num_qubits) # put_1_qubit_gates is a list of qubits that aren't assigned to a 2-qubit gate # 1-qubit gates will be assigned to these edges + t1 = time() + for edge in selected_edges: if rng.random() < two_qubit_prob: # with probability two_qubit_prob, place a two-qubit gate from the # gate set on edge in selected_edges - try: - getattr(qc, rng.choice(two_qubit_gate_set))(edge[0], edge[1]) - except AttributeError: - raise QiskitError("Invalid two-qubit gate set specified.") + if two_qubit_gate_set == ["cx"]: + qc.cx(edge[0], edge[1]) + else: + try: + getattr(qc, rng.choice(two_qubit_gate_set))(edge[0], edge[1]) + except AttributeError: + raise QiskitError("Invalid two-qubit gate set specified.") # remove these qubits from put_1_qubit_gates put_1_qubit_gates = np.setdiff1d(put_1_qubit_gates, edge) + t2 = time() + + # for q in put_1_qubit_gates: + # if one_qubit_gate_set == "clifford": + # gates_1q = _clifford_1q_int_to_instruction + # gates_1q = CliffordUtils.clifford_1_qubit( + # rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT) + # ).to_instruction() + # else: + # gates_1q = rng.choice(one_qubit_gate_set).to_instruction() + # qc.compose(gates_1q, [q], inplace=True) + for q in put_1_qubit_gates: - if one_qubit_gate_set == "clifford": - gates_1q = random_clifford(1, rng).to_circuit() - else: - gates_1q = rng.choice(one_qubit_gate_set).to_circuit() - insts = [datum[0] for datum in gates_1q.data] - for inst in insts: - qc.compose(inst, [q], inplace=True) + gate_1q = rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT) + + qc.compose(_clifford_1q_int_to_instruction(gate_1q, basis_gates), [q], inplace=True) + print(qc.decompose()) qc_list.append(qc) + t3 = time() + timed["2q"] += t2 - t1 + timed["cliffs"] += t3 - t2 + timed["looptotal"] = time() - timed["looptotal"] + print(timed) return qc_list diff --git a/test/library/randomized_benchmarking/test_clifford_utils.py b/test/library/randomized_benchmarking/test_clifford_utils.py index 8d656eaf2e..8256055ef4 100644 --- a/test/library/randomized_benchmarking/test_clifford_utils.py +++ b/test/library/randomized_benchmarking/test_clifford_utils.py @@ -199,7 +199,7 @@ def test_num_from_layer(self): layered = Clifford(circ) self.assertEqual(standard, layered) - def test_target_bitstring(self, qubits): + def test_target_bitstring(self): """Test if correct target bitstring is returned.""" qc = QuantumCircuit(9) qc.z(0) From 400a9938b3bf06c326c27da3670d4a31f982be93 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 21 Mar 2023 19:20:53 -0400 Subject: [PATCH 37/56] update 2q+ code --- .../mirror_rb_experiment.py | 130 +++++++-------- .../randomized_benchmarking/rb_experiment.py | 4 +- .../randomized_benchmarking/sampling_utils.py | 150 ++++++++---------- 3 files changed, 116 insertions(+), 168 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 9ac48e2628..dd45a5710e 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -27,24 +27,17 @@ from qiskit.providers.options import Options from qiskit.transpiler.basepasses import TransformationPass from qiskit_experiments.warnings import deprecate_arguments +from qiskit.circuit.library import CXGate from .rb_experiment import StandardRB, SequenceElementType from .mirror_rb_analysis import MirrorRBAnalysis -from .clifford_utils import compute_target_bitstring, CliffordUtils, inverse_1q -from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler - - -def timer_func(func): - # This function shows the execution time of - # the function object passed - def wrap_func(*args, **kwargs): - t1 = time() - result = func(*args, **kwargs) - t2 = time() - print(f"Function {func.__name__!r} executed in {(t2-t1):.4f}s") - return result - - return wrap_func +from .clifford_utils import ( + compute_target_bitstring, + CliffordUtils, + inverse_1q, + _clifford_1q_int_to_instruction, +) +from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler, GateType class MirrorRB(StandardRB): @@ -184,39 +177,49 @@ def circuits(self) -> List[QuantumCircuit]: return circuits - def _inverse_layer(self, layer) -> List[Tuple[Union[int, Tuple], int]]: + def _inverse_layer( + self, layer: List[Tuple[Tuple[int, ...], GateType]] + ) -> List[Tuple[Tuple[int, ...], GateType]]: """Generates the inverse layer of a Clifford mirror RB layer by inverting the single-qubit Cliffords and keeping the CXs identical. See :class:`.RBSampler` for the format of the layer. + Args: + layer: The input layer. + + Returns: + The layer that performs the inverse operation to the input layer. + Raises: QiskitError: If the layer has invalid format. """ inverse_layer = [] for elem in layer: - if isinstance(elem[0], int): + if len(elem[0]) == 1: inverse_layer.append((elem[0], inverse_1q(elem[1]))) - elif isinstance(elem[0], tuple): + elif len(elem[0]) == 2: inverse_layer.append(elem) else: raise QiskitError("Invalid layer from sampler.") return tuple(inverse_layer) - @timer_func def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: """Sample layers of mirror RB using the provided distribution and user options. + First, layers are sampled using the distribution, then Pauli-dressed if ``pauli_randomize`` is ``True``. The inverse of the resulting circuit is appended to the end. If ``local_clifford`` is ``True``, then cliffords are added to the beginning and end. If ``inverting_pauli_layer`` is ``True``, a Pauli layer will be appended at the end to set the output bitstring to all zeros. - Raises: - QiskitError: If no backend is provided. - Returns: A list of mirror RB sequences. Each element is a list of layers with length - matching the corresponding element in ``lengths``. + matching the corresponding element in ``lengths``. The layers are made up + of tuples in the format ((one or more qubit indices), gate). Single-qubit + Cliffords are represented by integers for speed. + + Raises: + QiskitError: If no backend is provided. """ if not self._backend: raise QiskitError("A backend must be provided for circuit generation.") @@ -240,11 +243,9 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: adjusted_2q_density = self.experiment_options.two_qubit_gate_density * 2 else: adjusted_2q_density = self.experiment_options.two_qubit_gate_density - # Sequence of lengths to sample for if not self.experiment_options.full_sampling: seqlens = (max(self.experiment_options.lengths),) - build_seq_lengths = self.experiment_options.lengths else: seqlens = self.experiment_options.lengths @@ -260,6 +261,10 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: seed=rng, ) ) + + if not self.experiment_options.full_sampling: + build_seq_lengths = self.experiment_options.lengths + seq.extend(layers) # Add the second half mirror layers @@ -298,7 +303,6 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: return sequences - @timer_func def _sequences_to_circuits( self, sequences: List[Sequence[SequenceElementType]] ) -> List[QuantumCircuit]: @@ -319,8 +323,8 @@ def _sequences_to_circuits( circ_target = QuantumCircuit(self.num_qubits) for layer in seq: for elem in layer: - circ.append(self._to_instruction(elem[1], basis_gates), [elem[0]]) - circ_target.append(self._to_instruction(elem[1]), [elem[0]]) + circ.append(self._to_instruction(elem[1], basis_gates), elem[0]) + circ_target.append(self._to_instruction(elem[1]), elem[0]) circ.append(Barrier(self.num_qubits), circ.qubits) circ_target.append(Barrier(self.num_qubits), circ_target.qubits) circ.metadata = { @@ -331,56 +335,28 @@ def _sequences_to_circuits( "inverting_pauli_layer": self.experiment_options.inverting_pauli_layer, } + if self.experiment_options.inverting_pauli_layer: + # Get target bitstring (ideal bitstring outputted by the circuit) + target = circ.metadata["target"] + + # Pauli gates to apply to each qubit to reset each to the state 0. + # E.g., if the ideal bitstring is 01001, the Pauli label is IXIIX, + # which sets all qubits to 0 (up to a global phase) + label = "".join(["X" if char == "1" else "I" for char in target]) + circ.append(Pauli(label), list(range(self._num_qubits))) + circ.measure_all() circuits.append(circ) return circuits - @timer_func - def _pauli_dress(self, element_list: List, rng: Generator) -> List: - """Interleaving layers of random Paulis inside the element list. - - Args: - element_list: The list of elements we add the interleaved Paulis to. - rng: Randomness generator - - Returns: - The new list of elements with the Paulis interleaved. - """ - rand_pauli = random_pauli(self._num_qubits, seed=rng) - new_element_list = [rand_pauli] - for element in element_list: - new_element_list.append(element) - rand_pauli = random_pauli(self._num_qubits, seed=rng) - new_element_list.append(rand_pauli) - return new_element_list - - @timer_func - def _transpiled_circuits(self) -> List[QuantumCircuit]: - return super()._transpiled_circuits() - - @timer_func - def _start_end_cliffords( - self, elements: Iterable[Clifford], rng: Generator - ) -> List[QuantumCircuit]: - """Add a layer of uniformly random 1-qubit Cliffords to the beginning of the list - and its inverse to the end of the list. - - Args: - elements: The list of elements we add the Clifford layers to - rng: Randomness generator - - Returns: - The new list of elements with the start and end local (1-qubit) Cliffords. - """ - - rand_clifford = [ - CliffordUtils.clifford_1_qubit(rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT)) - for _ in range(self.num_qubits) - ] - - tensor_op = rand_clifford[0] - for cliff in rand_clifford[1:]: - tensor_op = tensor_op ^ cliff - tensor_circ = tensor_op.to_circuit() - - return [tensor_circ] + elements + [tensor_circ.inverse()] + def _to_instruction( + self, + elem: SequenceElementType, + basis_gates: Optional[Tuple[str, ...]] = None, + ) -> Instruction: + # Overriding the default RB, which uses ``self.num_qubits`` to assume Clifford size + if isinstance(elem, Integral): + return _clifford_1q_int_to_instruction(elem, basis_gates) + elif isinstance(elem, Instruction): + return elem + return elem.to_instruction() diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 824941cb60..4084677b4c 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -337,13 +337,11 @@ def __adjoint_clifford(self, op: SequenceElementType) -> SequenceElementType: return Clifford.from_circuit(op).adjoint() return op.adjoint() - # pyline: disable=arguments-differ - def _transpiled_circuits(self, custom_transpile=False) -> List[QuantumCircuit]: + def _transpiled_circuits(self) -> List[QuantumCircuit]: """Return a list of experiment circuits, transpiled.""" has_custom_transpile_option = ( not set(vars(self.transpile_options)).issubset({"basis_gates", "optimization_level"}) or self.transpile_options.get("optimization_level", 0) != 0 - or custom_transpile ) has_no_undirected_2q_basis = self._get_basis_gates() is None if self.num_qubits > 2 or has_custom_transpile_option or has_no_undirected_2q_basis: diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 47e43f0a64..b0f952459e 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -20,35 +20,19 @@ import numpy as np from numpy.random import Generator, default_rng, BitGenerator, SeedSequence -from functools import lru_cache -from qiskit import QuantumCircuit, QuantumRegister, Operator +from qiskit import QuantumCircuit, QuantumRegister from qiskit.exceptions import QiskitError -from qiskit.circuit import Gate +from qiskit.circuit import Instruction +from qiskit.circuit.library import CXGate from qiskit.quantum_info.operators.base_operator import BaseOperator -from qiskit.quantum_info import random_unitary, Pauli, random_pauli +from qiskit.quantum_info import random_unitary, Pauli, random_pauli, Operator from qiskit.extensions import UnitaryGate from qiskit.converters import circuit_to_dag from .clifford_utils import CliffordUtils, _clifford_1q_int_to_instruction from .rb_experiment import SequenceElementType -from time import time - -Idx = TypeVar("Idx", int, Tuple[int, ...]) -Gate = TypeVar("Gate", Instruction, Operator, QuantumCircuit, BaseOperator) - - -def timer_func(func): - # This function shows the execution time of - # the function object passed - def wrap_func(*args, **kwargs): - t1 = time() - result = func(*args, **kwargs) - t2 = time() - print(f"Function {func.__name__!r} executed in {(t2-t1):.4f}s") - return result - - return wrap_func +GateType = TypeVar("Gate", Instruction, Operator, QuantumCircuit, BaseOperator) class RBSampler(ABC): @@ -59,11 +43,11 @@ def __init__(self): pass @abstractmethod - def __call__(self, num_qubits, seed=None, **params) -> Tuple[Tuple[Idx, Gate], ...]: + def __call__(self, num_qubits, seed=None, **params) -> List[Tuple[Tuple[int, ...], GateType]]: """Samplers should define this method such that it returns sampled layers given the input parameters. Each layer is represented by a list of size-2 tuples - where the first element is a qubit index or a tuple of indices, and the second - element represents the gate that should be applied.""" + where the first element is a tuple of qubit indices, and the second + element represents the gate that should be applied to the indices.""" pass @@ -74,25 +58,43 @@ def __call__( length, gate_set: Optional[Union[str, List]] = "clifford", seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, - ) -> Tuple[Tuple[Idx, Gate], ...]: + ) -> List[Tuple[Tuple[int, ...], GateType]]: """Samples a layer of random single-qubit gates from a specified gate set. + Args: + num_qubits: The number of qubits to generate layers for. + length: The length of the sequence to output. + gate_set: The one qubit gate set to sample from. Can be either a + list of gates, "clifford", or "pauli". Default is "clifford". + seed: Seed for random generation. + Returns: - For two qubits and length 3, a possible output would be - (((0,20),(1,14)),((0,11),(1,4)),((0,2),(1,9))) + A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over + ``num_qubits`` qubits. Each layer is represented by a list of tuples which + are in the format ((one or more qubit indices), gate). Single-qubit + Cliffords are represented by integers for speed. For two qubits, length + 3, and the default Clifford gate set, an example output would be + + .. code-block:: + [(((0,), 2), ((1,), 2)), (((0,), 11), ((1,), 4)), (((0,), 17), ((1,), 17))] """ rng = default_rng(seed=seed) if gate_set == "clifford": layers = [] for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=(length, num_qubits)): - layers.append(tuple(zip((range(num_qubits)), i))) + layers.append(tuple(zip(((j,) for j in range(num_qubits)), i))) elif gate_set == "pauli": layers = [] for i in range(length): - layers.append(tuple(zip(range(num_qubits), random_pauli(num_qubits, seed=rng)))) + layers.append( + tuple( + zip(((j,) for j in range(num_qubits)), random_pauli(num_qubits, seed=rng)) + ) + ) else: - # TODO finish this - pass + layers = [] + for i in rng.integers(len(gate_set), size=(length, num_qubits)): + layers.append(tuple(zip(((j,) for j in range(num_qubits)), gate_set[i]))) return layers @@ -123,7 +125,6 @@ class EdgeGrabSampler(RBSampler): """ - @timer_func def __call__( self, num_qubits: int, @@ -131,9 +132,9 @@ def __call__( coupling_map: List[List[int]], length: int, one_qubit_gate_set: Optional[Union[str, List]] = "clifford", - two_qubit_gate_set: Optional[List] = ["cx"], + two_qubit_gate_set: Optional[Union[str, List]] = "cx", seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, - ) -> List[List]: + ) -> List[Tuple[Tuple[int, ...], GateType]]: """Sample layers using the edge grab algorithm. Args: @@ -155,43 +156,38 @@ def __call__( Returns: A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over - ``num_qubits`` qubits. Each layer is represented by a list of tuples - which are of two formats: (single qubit index, single qubit gate) - represented by (int, int), or ((two qubit indices), two qubit gate) - represented by ((int, int), int). Here's an example with the default - choice of Cliffords for the single-qubit gates and CXs for the two-qubit - gates: + ``num_qubits`` qubits. Each layer is represented by a list of tuples which + are in the format ((one or more qubit indices), gate). Single-qubit + Cliffords are represented by integers for speed. Here's an example with the + default choice of Cliffords for the single-qubit gates and CXs for the + two-qubit gates: - .. code-block:: - (((1, 2), 0), (0, 12), (3, 20)) + .. code-block:: + (((1, 2), 0), ((0,), 12), ((3,), 20)) - This represents a layer where the 12th Clifford is performed on qubit 0, - a CX is performed with control qubit 1 and target qubit 2, and the 20th - Clifford is performed on qubit 3. + This represents a layer where the 12th Clifford is performed on qubit 0, + a CX is performed with control qubit 1 and target qubit 2, and the 20th + Clifford is performed on qubit 3. """ rng = default_rng(seed=seed) - if isinstance(one_qubit_gate_set, list) or not ( - one_qubit_gate_set.casefold() == "clifford" - ): + if not isinstance(one_qubit_gate_set, list) and one_qubit_gate_set.casefold() != "clifford": raise TypeError("one_qubit_gate_set must be a list of gates or 'clifford'.") if num_qubits == 1: if one_qubit_gate_set.casefold() == "clifford": return ( - ((0, i),) for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) + (((0,), i),) + for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) ) else: - return enumerate((0, i) for i in rng.choice(one_qubit_gate_set, size=length)) - - timed = {} + return list(enumerate((0, i) for i in rng.choice(one_qubit_gate_set, size=length))) - timed["looptotal"] = time() - timed["2q"] = 0 - timed["cliffs"] = 0 + if not isinstance(two_qubit_gate_set, list) and two_qubit_gate_set.casefold() != "cx": + raise TypeError("two_qubit_gate_set must be a list of gates or 'cx'.") - qc_list = [] + layer_list = [] for _ in list(range(length)): all_edges = coupling_map[:] # make copy of coupling map from which we pop edges selected_edges = [] @@ -207,8 +203,6 @@ def __call__( if rand_edge[0] not in edge and rand_edge[1] not in edge: all_edges.append(edge) - qr = QuantumRegister(num_qubits) - qc = QuantumCircuit(qr) two_qubit_prob = 0 try: # need to divide by 2 since each two-qubit gate spans two lattice sites @@ -224,45 +218,25 @@ def __call__( # selected_edges_logical is selected_edges with logical qubit labels rather than physical # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] # ==> selected_edges_logical = [[1,0],[4,2]] - put_1_qubit_gates = np.arange(num_qubits) + put_1_qubit_gates = set(range(num_qubits)) # put_1_qubit_gates is a list of qubits that aren't assigned to a 2-qubit gate # 1-qubit gates will be assigned to these edges - t1 = time() - + layer = [] for edge in selected_edges: if rng.random() < two_qubit_prob: # with probability two_qubit_prob, place a two-qubit gate from the # gate set on edge in selected_edges - if two_qubit_gate_set == ["cx"]: - qc.cx(edge[0], edge[1]) + if two_qubit_gate_set == "cx": + layer.append((tuple(edge), CXGate())) else: try: - getattr(qc, rng.choice(two_qubit_gate_set))(edge[0], edge[1]) + layer.append(edge, rng.choice(two_qubit_gate_set)) except AttributeError: raise QiskitError("Invalid two-qubit gate set specified.") # remove these qubits from put_1_qubit_gates - put_1_qubit_gates = np.setdiff1d(put_1_qubit_gates, edge) - t2 = time() - - # for q in put_1_qubit_gates: - # if one_qubit_gate_set == "clifford": - # gates_1q = _clifford_1q_int_to_instruction - # gates_1q = CliffordUtils.clifford_1_qubit( - # rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT) - # ).to_instruction() - # else: - # gates_1q = rng.choice(one_qubit_gate_set).to_instruction() - # qc.compose(gates_1q, [q], inplace=True) - + put_1_qubit_gates.remove(edge[0]) + put_1_qubit_gates.remove(edge[1]) for q in put_1_qubit_gates: - gate_1q = rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT) - - qc.compose(_clifford_1q_int_to_instruction(gate_1q, basis_gates), [q], inplace=True) - print(qc.decompose()) - qc_list.append(qc) - t3 = time() - timed["2q"] += t2 - t1 - timed["cliffs"] += t3 - t2 - timed["looptotal"] = time() - timed["looptotal"] - print(timed) - return qc_list + layer.append(((q,), rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT))) + layer_list.append(tuple(layer)) + return layer_list From 97a746dc907466edb7b72370ce3afa30270cd10a Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 21 Mar 2023 20:29:58 -0400 Subject: [PATCH 38/56] fixed wrong indexing for general coupling maps also changed samplers to qubit list input instead of num_qubits. --- docs/manuals/benchmarking/mirror_rb.rst | 2 +- .../randomized_benchmarking/__init__.py | 2 +- .../mirror_rb_experiment.py | 14 ++-- .../randomized_benchmarking/rb_experiment.py | 4 +- .../randomized_benchmarking/sampling_utils.py | 64 +++++++++---------- .../notes/mirror-rb-ec4d695a9a923971.yaml | 6 +- .../test_randomized_benchmarking.py | 11 ++-- 7 files changed, 53 insertions(+), 50 deletions(-) diff --git a/docs/manuals/benchmarking/mirror_rb.rst b/docs/manuals/benchmarking/mirror_rb.rst index 44cdf0b4f0..6c834d0765 100644 --- a/docs/manuals/benchmarking/mirror_rb.rst +++ b/docs/manuals/benchmarking/mirror_rb.rst @@ -88,7 +88,7 @@ user can specify an expected two-qubit gate density :math:`\xi \in \left[0, Even though a :class:`.MirrorRB` experiment can be instantiated without a backend, the backend must be specified when the circuits are sampled because :math:`\Omega` depends on the backend's connectivity. To use your own :math:`\Omega`, you have to implement -your own subclass of the abstract :class:`.MirrorRBSampler` class, but here we will use +your own subclass of the abstract :class:`.RBSampler` class, but here we will use the built-in :class:`.EdgeGrabSampler`. Here's how to instantiate and run the experiment: diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index 19eafd78aa..ece3c8d29b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -46,7 +46,7 @@ :toctree: ../stubs/ RBUtils - MirrorRBSampler + RBSampler EdgeGrabSampler SingleQubitSampler diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index dd45a5710e..af70b34b70 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -225,14 +225,17 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: raise QiskitError("A backend must be provided for circuit generation.") # Coupling map is full connectivity by default. If backend has a coupling map, - # get backend coupling map and create coupling map for physical qubits + # get backend coupling map and create coupling map for physical qubits converted + # to qubits 0, 1...n coupling_map = list(itertools.permutations(range(max(self.physical_qubits) + 1), 2)) if self._backend_data.coupling_map: coupling_map = self._backend_data.coupling_map + + qmap = {self.physical_qubits[i]: i for i in range(len(self.physical_qubits))} experiment_coupling_map = [] for edge in coupling_map: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: - experiment_coupling_map.append(edge) + experiment_coupling_map.append((qmap[edge[0]], qmap[edge[1]])) rng = default_rng(seed=self.experiment_options.seed) @@ -254,7 +257,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: seq = [] layers = list( self._distribution( - self.num_qubits, + range(self.num_qubits), adjusted_2q_density, experiment_coupling_map, seqlen // 2, @@ -274,7 +277,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Interleave random Paulis if set by user if self.experiment_options.pauli_randomize: sampler = SingleQubitSampler() - pauli_layers = sampler(self.num_qubits, seqlen + 1, "pauli", rng) + pauli_layers = sampler(range(self.num_qubits), seqlen + 1, "pauli", rng) seq = list(itertools.chain(*zip(pauli_layers[:-1], seq))) seq.append(pauli_layers[-1]) if not self.experiment_options.full_sampling: @@ -284,7 +287,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if self.experiment_options.local_clifford: cseq = [] sampler = SingleQubitSampler() - clifford_layers = sampler(self.num_qubits, 1, "clifford", rng) + clifford_layers = sampler(range(self.num_qubits), 1, "clifford", rng) cseq.append(clifford_layers[0]) cseq.extend(seq) cseq.append(self._inverse_layer(clifford_layers[0])) @@ -326,7 +329,6 @@ def _sequences_to_circuits( circ.append(self._to_instruction(elem[1], basis_gates), elem[0]) circ_target.append(self._to_instruction(elem[1]), elem[0]) circ.append(Barrier(self.num_qubits), circ.qubits) - circ_target.append(Barrier(self.num_qubits), circ_target.qubits) circ.metadata = { "xval": self.experiment_options.lengths[i % len(self.experiment_options.lengths)], "group": "Clifford", diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index 4084677b4c..d48eadda6a 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -297,9 +297,7 @@ def __sample_sequence(self, length: int, rng: Generator) -> Sequence[SequenceEle return [random_clifford(self.num_qubits, rng).to_circuit() for _ in range(length)] def _to_instruction( - self, - elem: SequenceElementType, - basis_gates: Optional[Tuple[str, ...]] = None, + self, elem: SequenceElementType, basis_gates: Optional[Tuple[str, ...]] = None, ) -> Instruction: # Switching for speed up if isinstance(elem, Integral): diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index b0f952459e..fa312ff94f 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -16,21 +16,16 @@ import warnings from abc import ABC, abstractmethod from typing import Optional, Union, Sequence, List, Tuple, TypeVar -from numbers import Integral -import numpy as np from numpy.random import Generator, default_rng, BitGenerator, SeedSequence -from qiskit import QuantumCircuit, QuantumRegister +from qiskit import QuantumCircuit from qiskit.exceptions import QiskitError from qiskit.circuit import Instruction from qiskit.circuit.library import CXGate from qiskit.quantum_info.operators.base_operator import BaseOperator -from qiskit.quantum_info import random_unitary, Pauli, random_pauli, Operator -from qiskit.extensions import UnitaryGate -from qiskit.converters import circuit_to_dag -from .clifford_utils import CliffordUtils, _clifford_1q_int_to_instruction -from .rb_experiment import SequenceElementType +from qiskit.quantum_info import random_pauli, Operator +from .clifford_utils import CliffordUtils GateType = TypeVar("Gate", Instruction, Operator, QuantumCircuit, BaseOperator) @@ -43,26 +38,34 @@ def __init__(self): pass @abstractmethod - def __call__(self, num_qubits, seed=None, **params) -> List[Tuple[Tuple[int, ...], GateType]]: + def __call__(self, qubits, seed=None, **params) -> List[Tuple[Tuple[int, ...], GateType]]: """Samplers should define this method such that it returns sampled layers given the input parameters. Each layer is represented by a list of size-2 tuples where the first element is a tuple of qubit indices, and the second - element represents the gate that should be applied to the indices.""" + element represents the gate that should be applied to the indices. + + Args: + qubits: A sequence of qubits to generate layers for. + seed: Seed for random generation. + + """ pass class SingleQubitSampler(RBSampler): + """A sampler that samples layers of random single-qubit gates from a specified gate set.""" + def __call__( self, - num_qubits, + qubits, length, gate_set: Optional[Union[str, List]] = "clifford", seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, ) -> List[Tuple[Tuple[int, ...], GateType]]: - """Samples a layer of random single-qubit gates from a specified gate set. + """Samples random single-qubit gates from a specified gate set. Args: - num_qubits: The number of qubits to generate layers for. + qubits: A sequence of qubits to generate layers for. length: The length of the sequence to output. gate_set: The one qubit gate set to sample from. Can be either a list of gates, "clifford", or "pauli". Default is "clifford". @@ -75,31 +78,32 @@ def __call__( Cliffords are represented by integers for speed. For two qubits, length 3, and the default Clifford gate set, an example output would be - .. code-block:: + .. parsed-literal:: + [(((0,), 2), ((1,), 2)), (((0,), 11), ((1,), 4)), (((0,), 17), ((1,), 17))] """ rng = default_rng(seed=seed) + num_qubits = len(qubits) if gate_set == "clifford": layers = [] for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=(length, num_qubits)): - layers.append(tuple(zip(((j,) for j in range(num_qubits)), i))) + layers.append(tuple(zip(((j,) for j in qubits), i))) elif gate_set == "pauli": layers = [] for i in range(length): layers.append( - tuple( - zip(((j,) for j in range(num_qubits)), random_pauli(num_qubits, seed=rng)) - ) + tuple(zip(((j,) for j in qubits), random_pauli(num_qubits, seed=rng))) ) else: layers = [] for i in rng.integers(len(gate_set), size=(length, num_qubits)): - layers.append(tuple(zip(((j,) for j in range(num_qubits)), gate_set[i]))) + layers.append(tuple(zip(((j,) for j in qubits), gate_set[i]))) return layers class EdgeGrabSampler(RBSampler): - r"""The edge grab algorithm for sampling one- and two-qubit layers. + r"""A sampler that uses the edge grab algorithm for sampling one- and two-qubit gate + layers. # section: overview @@ -127,7 +131,7 @@ class EdgeGrabSampler(RBSampler): def __call__( self, - num_qubits: int, + qubits: int, two_qubit_gate_density: float, coupling_map: List[List[int]], length: int, @@ -138,7 +142,7 @@ def __call__( """Sample layers using the edge grab algorithm. Args: - num_qubits: The number of qubits to generate layers for. + qubits: A sequence of qubits to generate layers for. one_qubit_gate_set: The one qubit gate set to sample from. Can be either a list of gates or "clifford". two_qubit_gate_set: The two qubit gate set to sample from. Can be either a @@ -162,7 +166,8 @@ def __call__( default choice of Cliffords for the single-qubit gates and CXs for the two-qubit gates: - .. code-block:: + .. parsed-literal:: + (((1, 2), 0), ((0,), 12), ((3,), 20)) This represents a layer where the 12th Clifford is performed on qubit 0, @@ -171,6 +176,7 @@ def __call__( """ rng = default_rng(seed=seed) + num_qubits = len(qubits) if not isinstance(one_qubit_gate_set, list) and one_qubit_gate_set.casefold() != "clifford": raise TypeError("one_qubit_gate_set must be a list of gates or 'clifford'.") @@ -178,7 +184,7 @@ def __call__( if num_qubits == 1: if one_qubit_gate_set.casefold() == "clifford": return ( - (((0,), i),) + (((qubits[0],), i),) for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) ) else: @@ -215,10 +221,7 @@ def __call__( + "Actual density of two-qubit gates will likely be lower than input density." ) - # selected_edges_logical is selected_edges with logical qubit labels rather than physical - # ones. Example: qubits = (8,4,5,3,7), selected_edges = [[4,8],[7,5]] - # ==> selected_edges_logical = [[1,0],[4,2]] - put_1_qubit_gates = set(range(num_qubits)) + put_1_qubit_gates = set(qubits) # put_1_qubit_gates is a list of qubits that aren't assigned to a 2-qubit gate # 1-qubit gates will be assigned to these edges layer = [] @@ -229,10 +232,7 @@ def __call__( if two_qubit_gate_set == "cx": layer.append((tuple(edge), CXGate())) else: - try: - layer.append(edge, rng.choice(two_qubit_gate_set)) - except AttributeError: - raise QiskitError("Invalid two-qubit gate set specified.") + layer.append(edge, rng.choice(two_qubit_gate_set)) # remove these qubits from put_1_qubit_gates put_1_qubit_gates.remove(edge[0]) put_1_qubit_gates.remove(edge[1]) diff --git a/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml index 4b4d833e51..75335567d9 100644 --- a/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml +++ b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml @@ -1,6 +1,10 @@ --- features: - | - A new experiment class :class:`.MirrorRB` is introduced. This class implements + Added a new experiment class :class:`.MirrorRB`. This class implements mirror randomized benchmarking, a variant of randomized benchmarking that measures the fidelity of user-defined ensembles of randomized mirror circuits. + - | + Added a base class that samples circuit layers for randomized benchmarking experiments, + :class:`.RBSampler`. The edge grab sampler :class:`.EdgeGrabSampler` and a single + qubit gate sampler :class:`.SingleQubitSampler` are implemented. \ No newline at end of file diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 520bb3aff1..da91d617e4 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -37,7 +37,6 @@ from qiskit_experiments.library.randomized_benchmarking.clifford_utils import ( compute_target_bitstring, ) -from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler class RBTestMixin: @@ -1112,13 +1111,13 @@ def test_analysis_config(self): def test_backend_with_directed_basis_gates(self): """Test if correct circuits are generated from backend with directed basis gates.""" - my_backend = copy.deepcopy(self.backend) + my_backend = copy.deepcopy(FakeManilaV2()) del my_backend.target["cx"][(1, 2)] # make cx on {1, 2} one-sided exp = rb.MirrorRB( physical_qubits=(1, 2), - two_qubit_gate_density=1, - lengths=[3], + two_qubit_gate_density=0.5, + lengths=[4], num_samples=4, backend=my_backend, ) @@ -1208,7 +1207,7 @@ def test_two_qubit(self): two_qubit_gate_density = 0.2 exp = rb.MirrorRB( physical_qubits=(0, 1), - lengths=list(range(2, 300, 40)), + lengths=list(range(2, 80, 16)), seed=123, backend=self.backend, num_samples=20, @@ -1231,7 +1230,7 @@ def test_two_qubit(self): cx_factor = (1 - 3 * self.p2q / 4) ** (2 * two_qubit_gate_density) sx_factor = (1 - self.p1q / 2) ** (2 * 2 * (1 - two_qubit_gate_density)) epc_expected = 1 - cx_factor * sx_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) def test_two_qubit_nonlocal_noise(self): """Test for 2 qubit Mirrored RB with a nonlocal noise model""" From b32d331bfd09cd325280e8c762b7155e62bf2a21 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 21 Mar 2023 23:00:31 -0400 Subject: [PATCH 39/56] lint and improve manual --- docs/manuals/benchmarking/mirror_rb.rst | 63 +++++++++++++---- .../mirror_rb_analysis.py | 2 - .../mirror_rb_experiment.py | 69 +++++++++---------- .../randomized_benchmarking/rb_experiment.py | 2 +- requirements-dev.txt | 1 - 5 files changed, 84 insertions(+), 53 deletions(-) diff --git a/docs/manuals/benchmarking/mirror_rb.rst b/docs/manuals/benchmarking/mirror_rb.rst index 6c834d0765..aeeb470d61 100644 --- a/docs/manuals/benchmarking/mirror_rb.rst +++ b/docs/manuals/benchmarking/mirror_rb.rst @@ -122,7 +122,6 @@ experiment: .. jupyter-execute:: - # View result data print("Gate error ratio: %s" % expdata_2q.experiment.analysis.options.gate_error_ratio) display(expdata_2q.figure(0)) for result in results_2q: @@ -137,14 +136,16 @@ instead of the default: .. jupyter-execute:: - lengths = [2, 52, 102, 152] + lengths = np.arange(2,302,50) num_samples = 5 seed = 42 qubits = (0,) exp = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) - # select y-axis - exp.analysis.set_options(y_axis="Success Probability") # or "Adjusted Success Probability" or "Effective Polarization" + + # select y-axis, can also be "Adjusted Success Probability" or "Effective Polarization" + exp.analysis.set_options(y_axis="Success Probability") + # y-axis label must be set separately exp.analysis.options.plotter.set_figure_options( ylabel="Success Probability", @@ -162,29 +163,60 @@ instead of the default: Mirror RB user options ~~~~~~~~~~~~~~~~~~~~~~ -Circuit generation options can be specified when a :class:`.MirrorRB` experiment -object is instantiated: +There are several options that change the composition of the mirror RB circuit layers. +One important option is ``two_qubit_gate_density`` (default ``0.2``). This is the +expected fraction of two-qubit gates in the circuit, not accounting for the optional +constant number of Clifford and Pauli layers at the start and end. This means that given +the same ``two_qubit_gate_density``, if ``pauli_randomize`` is off, the concentration of +CX gates in the Clifford layers will be halved so that the overall density doesn't +change. We'll demonstrate this by first leaving ``pauli_randomize`` on: -- ``local_clifford`` (default ``True``): if ``True``, begin the circuit with - uniformly random one-qubit Cliffords and end the circuit with their inverses +.. jupyter-execute:: + + exp = MirrorRB((0,1,2,3), + lengths=[2], + two_qubit_gate_density=0.25, + seed=100, + backend=backend, + num_samples=1) + exp.circuits()[0].draw("mpl") + +And now we remove the Pauli layers to see that the CX density in the Clifford layers +have halved: + +.. jupyter-execute:: + + exp = MirrorRB((0,1,2,3), + lengths=[2], + two_qubit_gate_density=0.25, + pauli_randomize=False, + seed=100, + backend=backend, + num_samples=1) + exp.circuits()[0].draw("mpl") + +There are three boolean options that - ``pauli_randomize`` (default ``True``): if ``True``, put layers of uniformly random Paulis between the intermediate Clifford layers -- ``two_qubit_gate_density`` (default ``0.2``): expected fraction of two-qubit - gates in each intermediate Clifford layer +- ``local_clifford`` (default ``True``): if ``True``, begin the circuit with + uniformly random one-qubit Cliffords and end the circuit with their inverses - ``inverting_pauli_layer`` (default ``False``): if ``True``, add a layer of Paulis at the end of the circuit to set the output to :math:`\left\vert0\right\rangle^{\otimes n}`, up to a global phase -Let's look at how these options change the circuit. First, the default with Pauli -layers between Cliffords and single-qubit Cliffords at the start and end: +The default settings produce the circuits in Ref [1]_. + +Let's look at how these options change the circuit. First, the default with Pauli layers +between Cliffords and single-qubit Cliffords at the start and end: .. jupyter-execute:: exp = MirrorRB((0,1,2), lengths=[2], + seed=100, backend=backend, num_samples=1) exp.circuits()[0].decompose().draw("mpl") @@ -195,12 +227,17 @@ And now with both options turned off: exp = MirrorRB((0,1,2), lengths=[2], + seed=100, backend=backend, num_samples=1, local_clifford=False, - pauli_randomize=False) + two_qubit_gate_density=0.4, + pauli_randomize=False, + inverting_pauli_layer=True) exp.circuits()[0].decompose().draw("mpl") + + Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index dde7e8a95f..1fced93803 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -80,8 +80,6 @@ class MirrorRBAnalysis(curve.CurveAnalysis): # section: fit_model The fit is based on the following decay functions: - Fit model for mirror RB - .. math:: F(x) = a \alpha^{x} + b diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index af70b34b70..6026dea8c5 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -15,25 +15,19 @@ from typing import Union, Iterable, Optional, List, Sequence, Tuple from numbers import Integral import itertools -from time import time - from numpy.random import Generator, BitGenerator, SeedSequence, default_rng -from qiskit.exceptions import QiskitError from qiskit.circuit import QuantumCircuit, Instruction, Barrier -from qiskit.quantum_info import Clifford, random_pauli, random_clifford from qiskit.quantum_info.operators import Pauli from qiskit.providers.backend import Backend from qiskit.providers.options import Options -from qiskit.transpiler.basepasses import TransformationPass -from qiskit_experiments.warnings import deprecate_arguments -from qiskit.circuit.library import CXGate +from qiskit.exceptions import QiskitError +from qiskit_experiments.warnings import deprecate_arguments from .rb_experiment import StandardRB, SequenceElementType from .mirror_rb_analysis import MirrorRBAnalysis from .clifford_utils import ( compute_target_bitstring, - CliffordUtils, inverse_1q, _clifford_1q_int_to_instruction, ) @@ -100,7 +94,7 @@ def __init__( num_samples: Number of samples to generate for each sequence length. seed: Optional, seed used to initialize ``numpy.random.default_rng``. when generating circuits. The ``default_rng`` will be initialized - with this seed value everytime :meth:`circuits` is called. + with this seed value every time :meth:`circuits` is called. full_sampling: If True all Cliffords are independently sampled for all lengths. If False for sample of lengths longer sequences are constructed by appending additional Clifford samples to shorter @@ -149,7 +143,7 @@ def _default_experiment_options(cls) -> Options: pauli_randomize (bool): Whether to surround each inner Clifford layer with uniformly random Paulis. inverting_pauli_layer (bool): Whether to append a layer of Pauli gates at the - end of the circuit to set all qubits to 0 + end of the circuit to set all qubits to 0. two_qubit_gate_density (float): Expected proportion of two-qubit gates in the mirror circuit layers (not counting Clifford or Pauli layers at the start and end). @@ -177,32 +171,6 @@ def circuits(self) -> List[QuantumCircuit]: return circuits - def _inverse_layer( - self, layer: List[Tuple[Tuple[int, ...], GateType]] - ) -> List[Tuple[Tuple[int, ...], GateType]]: - """Generates the inverse layer of a Clifford mirror RB layer by inverting the - single-qubit Cliffords and keeping the CXs identical. See - :class:`.RBSampler` for the format of the layer. - - Args: - layer: The input layer. - - Returns: - The layer that performs the inverse operation to the input layer. - - Raises: - QiskitError: If the layer has invalid format. - """ - inverse_layer = [] - for elem in layer: - if len(elem[0]) == 1: - inverse_layer.append((elem[0], inverse_1q(elem[1]))) - elif len(elem[0]) == 2: - inverse_layer.append(elem) - else: - raise QiskitError("Invalid layer from sampler.") - return tuple(inverse_layer) - def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: """Sample layers of mirror RB using the provided distribution and user options. @@ -246,6 +214,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: adjusted_2q_density = self.experiment_options.two_qubit_gate_density * 2 else: adjusted_2q_density = self.experiment_options.two_qubit_gate_density + # Sequence of lengths to sample for if not self.experiment_options.full_sampling: seqlens = (max(self.experiment_options.lengths),) @@ -255,6 +224,8 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: for _ in range(self.experiment_options.num_samples): for seqlen in seqlens: seq = [] + + # Sample the first half of the mirror layers layers = list( self._distribution( range(self.num_qubits), @@ -362,3 +333,29 @@ def _to_instruction( elif isinstance(elem, Instruction): return elem return elem.to_instruction() + + def _inverse_layer( + self, layer: List[Tuple[Tuple[int, ...], GateType]] + ) -> List[Tuple[Tuple[int, ...], GateType]]: + """Generates the inverse layer of a Clifford mirror RB layer by inverting the + single-qubit Cliffords and keeping the CXs identical. See + :class:`.RBSampler` for the format of the layer. + + Args: + layer: The input layer. + + Returns: + The layer that performs the inverse operation to the input layer. + + Raises: + QiskitError: If the layer has invalid format. + """ + inverse_layer = [] + for elem in layer: + if len(elem[0]) == 1: + inverse_layer.append((elem[0], inverse_1q(elem[1]))) + elif len(elem[0]) == 2: + inverse_layer.append(elem) + else: + raise QiskitError("Invalid layer from sampler.") + return tuple(inverse_layer) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py index d48eadda6a..3daf4e2038 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_experiment.py @@ -297,7 +297,7 @@ def __sample_sequence(self, length: int, rng: Generator) -> Sequence[SequenceEle return [random_clifford(self.num_qubits, rng).to_circuit() for _ in range(length)] def _to_instruction( - self, elem: SequenceElementType, basis_gates: Optional[Tuple[str, ...]] = None, + self, elem: SequenceElementType, basis_gates: Optional[Tuple[str, ...]] = None ) -> Instruction: # Switching for speed up if isinstance(elem, Integral): diff --git a/requirements-dev.txt b/requirements-dev.txt index 63e190a642..48296535bc 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -20,5 +20,4 @@ pylatexenc # Pin `importlib-metadata` because of a bug relating to version 5.0.0. See #931 for more. importlib-metadata==4.13.0;python_version<'3.8' scikit-learn -pygsti==0.9.10.1 sphinx-copybutton From c70e1504860711e45c17e49ff2172a33303a7743 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 21 Mar 2023 23:41:09 -0400 Subject: [PATCH 40/56] update manual --- docs/manuals/benchmarking/mirror_rb.rst | 80 ++++++++++--------- .../randomized_benchmarking/sampling_utils.py | 7 +- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/docs/manuals/benchmarking/mirror_rb.rst b/docs/manuals/benchmarking/mirror_rb.rst index aeeb470d61..cc6f564c4c 100644 --- a/docs/manuals/benchmarking/mirror_rb.rst +++ b/docs/manuals/benchmarking/mirror_rb.rst @@ -6,18 +6,19 @@ that is more scalable than standard randomized benchmarking and is suitable for characterizing crosstalk errors over a large number of qubits in a quantum device. A randomized Clifford mirror circuit [1]_ consists of: -- random layers of one- and two-qubit Cliffords and their inverses sampled - according to some distribution :math:`\Omega` over a layer set - :math:`\mathbb{L}`, +- random n-qubit Clifford layers and their inverses sampled according to some + distribution :math:`\Omega` over a layer set :math:`\mathbb{L}`, - uniformly random one-qubit Paulis between these layers, and - a layer of uniformly random one-qubit Cliffords at the beginning and the end of the circuit. -Note that the Clifford gates are only one- and two-qubit, unlike in standard RB, which -requires the implementation of n-qubit Cliffords. Mirror RB can also be -generalized to universal gatesets beyond the Cliffords [2]_. +Note that the random n-qubit Clifford layers can be realized with only one-qubit +Cliffords and a two-qubit gate such as CX, which twirl the local errors sufficiently to +produce a useful metric of gate infidelity. This is in contrast to standard RB, which +requires the implementation of n-qubit Cliffords that have much more overhead for large +n. Mirror RB can also be generalized to universal gatesets beyond the Cliffords [2]_. Output metrics -------------- @@ -41,9 +42,9 @@ Specifically, we compute the **adjusted success probability** P_0 = \sum_{k=0}^n \left(-\frac{1}{2}\right)^k h_k, -where :math:`h_k` is the probability of the actual output bit string being -Hamming distance :math:`k` away from the expected output bit string (note -:math:`h_0 = P`). We also compute the **effective polarization** +where :math:`h_k` is the probability of the actual output bit string being Hamming +distance :math:`k` away from the expected output bit string (note :math:`h_0 = P`). We +also compute the **effective polarization**, which is fitted and visualized by default: .. math:: @@ -164,36 +165,6 @@ Mirror RB user options ~~~~~~~~~~~~~~~~~~~~~~ There are several options that change the composition of the mirror RB circuit layers. -One important option is ``two_qubit_gate_density`` (default ``0.2``). This is the -expected fraction of two-qubit gates in the circuit, not accounting for the optional -constant number of Clifford and Pauli layers at the start and end. This means that given -the same ``two_qubit_gate_density``, if ``pauli_randomize`` is off, the concentration of -CX gates in the Clifford layers will be halved so that the overall density doesn't -change. We'll demonstrate this by first leaving ``pauli_randomize`` on: - -.. jupyter-execute:: - - exp = MirrorRB((0,1,2,3), - lengths=[2], - two_qubit_gate_density=0.25, - seed=100, - backend=backend, - num_samples=1) - exp.circuits()[0].draw("mpl") - -And now we remove the Pauli layers to see that the CX density in the Clifford layers -have halved: - -.. jupyter-execute:: - - exp = MirrorRB((0,1,2,3), - lengths=[2], - two_qubit_gate_density=0.25, - pauli_randomize=False, - seed=100, - backend=backend, - num_samples=1) - exp.circuits()[0].draw("mpl") There are three boolean options that @@ -236,6 +207,37 @@ And now with both options turned off: inverting_pauli_layer=True) exp.circuits()[0].decompose().draw("mpl") +Another important option is ``two_qubit_gate_density`` (default ``0.2``). This is the +expected fraction of two-qubit gates in the circuit, not accounting for the optional +constant number of Clifford and Pauli layers at the start and end. This means that given +the same ``two_qubit_gate_density``, if ``pauli_randomize`` is off, the concentration of +CX gates in the Clifford layers will be halved so that the overall density doesn't +change. We'll demonstrate this by first leaving ``pauli_randomize`` on: + +.. jupyter-execute:: + + exp = MirrorRB(range(8), + lengths=[2], + two_qubit_gate_density=0.5, + seed=101, + backend=backend, + num_samples=1) + exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") + +Note that And now we remove the Pauli layers to see that the CX density in the Clifford layers +have halved: + +.. jupyter-execute:: + + exp = MirrorRB(range(8), + lengths=[2], + two_qubit_gate_density=0.5, + pauli_randomize=False, + seed=101, + backend=backend, + num_samples=1) + exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") + Mirror RB implementation in ``pyGSTi`` diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index fa312ff94f..42d1ddc892 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -15,12 +15,11 @@ import warnings from abc import ABC, abstractmethod -from typing import Optional, Union, Sequence, List, Tuple, TypeVar +from typing import Optional, Union, List, Tuple, TypeVar from numpy.random import Generator, default_rng, BitGenerator, SeedSequence from qiskit import QuantumCircuit -from qiskit.exceptions import QiskitError from qiskit.circuit import Instruction from qiskit.circuit.library import CXGate from qiskit.quantum_info.operators.base_operator import BaseOperator @@ -49,12 +48,13 @@ def __call__(self, qubits, seed=None, **params) -> List[Tuple[Tuple[int, ...], G seed: Seed for random generation. """ - pass + return None class SingleQubitSampler(RBSampler): """A sampler that samples layers of random single-qubit gates from a specified gate set.""" + # pylint: disable=arguments-differ def __call__( self, qubits, @@ -129,6 +129,7 @@ class EdgeGrabSampler(RBSampler): """ + # pylint: disable=arguments-differ def __call__( self, qubits: int, From a6c8ff871352305bb5fdf6bf4283749350184593 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Wed, 22 Mar 2023 19:33:39 -0400 Subject: [PATCH 41/56] refactored sampling utils and added tests Improved the sampler interface by making several input parameters part of base class attributes instead of set at __call__. Now the distribution can be more easily customized with defined gate ratios. --- .../mirror_rb_experiment.py | 58 ++-- .../randomized_benchmarking/sampling_utils.py | 265 ++++++++++++------ .../test_sampling_utils.py | 69 +++++ 3 files changed, 290 insertions(+), 102 deletions(-) create mode 100644 test/library/randomized_benchmarking/test_sampling_utils.py diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 6026dea8c5..296de9d0bf 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -22,6 +22,7 @@ from qiskit.providers.backend import Backend from qiskit.providers.options import Options from qiskit.exceptions import QiskitError +from qiskit.circuit.library import CXGate from qiskit_experiments.warnings import deprecate_arguments from .rb_experiment import StandardRB, SequenceElementType @@ -71,6 +72,7 @@ def __init__( local_clifford: bool = True, pauli_randomize: bool = True, two_qubit_gate_density: float = 0.2, + two_qubit_gate: GateType = CXGate, backend: Optional[Backend] = None, num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, @@ -83,13 +85,16 @@ def __init__( physical_qubits: A list of physical qubits for the experiment. lengths: A list of RB sequences lengths. distribution: The probability distribution over the layer set to sample. - Defaults to the :class:`.EdgeGrabSampler`. + Defaults to the :class:`.EdgeGrabSampler`. Distribution options can be set by + accessing the distribution object of this class. local_clifford: If True, begin the circuit with uniformly random 1-qubit Cliffords and end the circuit with their inverses. pauli_randomize: If True, surround each inner Clifford layer with uniformly random Paulis. - two_qubit_gate_density: Expected proportion of qubits with CNOTs based on - the backend coupling map. + two_qubit_gate_density: Expected proportion of qubit sites with two-qubit + gates over all circuit layers (not counting optional layers at the start + and end). + two_qubit_gate: The two-qubit gate to use. Defaults to "cx". backend: The backend to run the experiment on. num_samples: Number of samples to generate for each sequence length. seed: Optional, seed used to initialize ``numpy.random.default_rng``. @@ -121,14 +126,14 @@ def __init__( full_sampling=full_sampling, ) - self._distribution = distribution() + self.distribution = distribution() self.set_experiment_options( - distribution=distribution, local_clifford=local_clifford, pauli_randomize=pauli_randomize, inverting_pauli_layer=inverting_pauli_layer, two_qubit_gate_density=two_qubit_gate_density, + two_qubit_gate=two_qubit_gate, ) self.analysis = MirrorRBAnalysis() @@ -147,6 +152,7 @@ def _default_experiment_options(cls) -> Options: two_qubit_gate_density (float): Expected proportion of two-qubit gates in the mirror circuit layers (not counting Clifford or Pauli layers at the start and end). + two_qubit_gate (str | ): The two qubit gate to use. num_samples (int): Number of samples to generate for each sequence length. """ options = super()._default_experiment_options() @@ -154,6 +160,7 @@ def _default_experiment_options(cls) -> Options: local_clifford=True, pauli_randomize=True, two_qubit_gate_density=0.2, + two_qubit_gate="cx", distribution=None, inverting_pauli_layer=False, ) @@ -207,32 +214,44 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: rng = default_rng(seed=self.experiment_options.seed) - sequences = [] - # Adjust the density based on whether the pauli layers are in if self.experiment_options.pauli_randomize: adjusted_2q_density = self.experiment_options.two_qubit_gate_density * 2 else: adjusted_2q_density = self.experiment_options.two_qubit_gate_density + self.distribution.seed = rng + self.distribution.coupling_map = experiment_coupling_map + self.distribution.gate_distribution = [ + (adjusted_2q_density, 2, self.experiment_options.two_qubit_gate), + (1 - adjusted_2q_density, 1, "clifford"), + ] + # Sequence of lengths to sample for if not self.experiment_options.full_sampling: seqlens = (max(self.experiment_options.lengths),) else: seqlens = self.experiment_options.lengths + if self.experiment_options.pauli_randomize: + pauli_sampler = SingleQubitSampler(seed=rng) + pauli_sampler.gate_distribution = [(1, 1, "pauli")] + + if self.experiment_options.local_clifford: + clifford_sampler = SingleQubitSampler(seed=rng) + clifford_sampler.gate_distribution = [(1, 1, "clifford")] + + sequences = [] + for _ in range(self.experiment_options.num_samples): for seqlen in seqlens: seq = [] # Sample the first half of the mirror layers layers = list( - self._distribution( - range(self.num_qubits), - adjusted_2q_density, - experiment_coupling_map, - seqlen // 2, - seed=rng, + self.distribution( + qubits=range(self.num_qubits), + length=seqlen // 2, ) ) @@ -247,8 +266,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Interleave random Paulis if set by user if self.experiment_options.pauli_randomize: - sampler = SingleQubitSampler() - pauli_layers = sampler(range(self.num_qubits), seqlen + 1, "pauli", rng) + pauli_layers = pauli_sampler(range(self.num_qubits), length=seqlen + 1) seq = list(itertools.chain(*zip(pauli_layers[:-1], seq))) seq.append(pauli_layers[-1]) if not self.experiment_options.full_sampling: @@ -257,8 +275,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Add start and end local cliffords if set by user if self.experiment_options.local_clifford: cseq = [] - sampler = SingleQubitSampler() - clifford_layers = sampler(range(self.num_qubits), 1, "clifford", rng) + clifford_layers = clifford_sampler(range(self.num_qubits), length=1) cseq.append(clifford_layers[0]) cseq.extend(seq) cseq.append(self._inverse_layer(clifford_layers[0])) @@ -327,12 +344,15 @@ def _to_instruction( elem: SequenceElementType, basis_gates: Optional[Tuple[str, ...]] = None, ) -> Instruction: - # Overriding the default RB, which uses ``self.num_qubits`` to assume Clifford size + """Convert the sampled object to an instruction.""" if isinstance(elem, Integral): return _clifford_1q_int_to_instruction(elem, basis_gates) elif isinstance(elem, Instruction): return elem - return elem.to_instruction() + elif getattr(elem, "to_instruction", None): + return elem.to_instruction() + else: + return elem() def _inverse_layer( self, layer: List[Tuple[Tuple[int, ...], GateType]] diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 42d1ddc892..2a1a3a929c 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -14,30 +14,129 @@ """ import warnings +import math from abc import ABC, abstractmethod -from typing import Optional, Union, List, Tuple, TypeVar +from typing import Optional, Union, List, Tuple, Sequence, TypeVar +from collections import defaultdict from numpy.random import Generator, default_rng, BitGenerator, SeedSequence from qiskit import QuantumCircuit from qiskit.circuit import Instruction -from qiskit.circuit.library import CXGate from qiskit.quantum_info.operators.base_operator import BaseOperator -from qiskit.quantum_info import random_pauli, Operator -from .clifford_utils import CliffordUtils +from qiskit.quantum_info import Operator +from qiskit.exceptions import QiskitError -GateType = TypeVar("Gate", Instruction, Operator, QuantumCircuit, BaseOperator) +from .clifford_utils import CliffordUtils, _CLIFF_SINGLE_GATE_MAP_1Q + +GateType = TypeVar("GateType", str, int, Instruction, Operator, QuantumCircuit, BaseOperator) class RBSampler(ABC): """Sampling distribution for randomized benchmarking experiments. Subclasses must implement the ``__call__()`` method.""" - def __init__(self): - pass + def __init__( + self, + gate_distribution=None, + coupling_map: Optional[List[List[int]]] = None, + seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, + ): + """Instantiate the sampler. Note that this is different from invoking the + instance. + + Args: + seed: Seed for random generation. + gate_distribution: The gate distribution for sampling. + """ + self._gate_distribution = gate_distribution + self._coupling_map = coupling_map + self.seed = default_rng(seed) + + @property + def coupling_map(self): + """The coupling map of the system to sample over.""" + return self._coupling_map + + @coupling_map.setter + def coupling_map(self, coupling_map): + self._coupling_map = coupling_map + + @property + def seed(self): + """The seed for random generation.""" + return self._rng + + @seed.setter + def seed(self, seed): + self._rng = default_rng(seed) + + @property + def gate_distribution(self): + """The gate distribution for sampling. The distribution is a list of tuples + of the form ``(probability, width of gate, gate)``. Gates can be actual + operators, circuits, or the special keywords "clifford", "pauli", "idle". An + example distribution for the edge grab sampler might be + + .. parsed-literal:: + [(0.8, 1, "clifford"), (0.2, 2, CXGate)] + + The probabilities must sum to 1.""" + return self._gate_distribution + + @gate_distribution.setter + def gate_distribution(self, dist: List[Tuple[float, int, GateType]]): + """Set the distribution of gates used in the sampler. + + Args: + dist: A list of tuples with format ``(probability, width of gate, gate)``. + """ + if not isinstance(dist, List): + raise TypeError("The gate distribution should be a list.") + if sum(list(zip(*dist))[0]) != 1: + raise QiskitError("Gate distribution probabilities must sum to 1.") + + self._gate_distribution = dist + + def _probs_by_gate_size(self): + """Return a list of gates and their probabilities indexed by the size of the gate. The + probability distributions are normalized to 1 within each gate size category. + """ + if not self._gate_distribution: + raise QiskitError("Gate distribution must be set before sampling.") + gate_probs = defaultdict(list) + + for gate in self.gate_distribution: + if gate[2] == "clifford" and gate[1] == 1: + gateset = list(range(CliffordUtils.NUM_CLIFFORD_1_QUBIT)) + probs = [ + gate[0] / CliffordUtils.NUM_CLIFFORD_1_QUBIT + ] * CliffordUtils.NUM_CLIFFORD_1_QUBIT + elif gate[2] == "pauli" and gate[1] == 1: + gateset = [ + _CLIFF_SINGLE_GATE_MAP_1Q[("id", (0,))], + _CLIFF_SINGLE_GATE_MAP_1Q[("x", (0,))], + _CLIFF_SINGLE_GATE_MAP_1Q[("y", (0,))], + _CLIFF_SINGLE_GATE_MAP_1Q[("z", (0,))], + ] + probs = [gate[0] / 4] * 4 + elif gate[2] == "clifford" and gate[1] == 2: + gateset = list(range(CliffordUtils.NUM_CLIFFORD_2_QUBIT)) + probs = [ + gate[0] / CliffordUtils.NUM_CLIFFORD_2_QUBIT + ] * CliffordUtils.NUM_CLIFFORD_2_QUBIT + else: + gateset = [gate[2]] + probs = [gate[0]] + if len(gate_probs[gate[1]]) == 0: + gate_probs[gate[1]] = [gateset, probs] + else: + gate_probs[gate[1]][0].extend(gateset) + gate_probs[gate[1]][1].extend(probs) + return gate_probs @abstractmethod - def __call__(self, qubits, seed=None, **params) -> List[Tuple[Tuple[int, ...], GateType]]: + def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[Tuple[int, ...], GateType]]: """Samplers should define this method such that it returns sampled layers given the input parameters. Each layer is represented by a list of size-2 tuples where the first element is a tuple of qubit indices, and the second @@ -45,8 +144,7 @@ def __call__(self, qubits, seed=None, **params) -> List[Tuple[Tuple[int, ...], G Args: qubits: A sequence of qubits to generate layers for. - seed: Seed for random generation. - + length: The number of layers to generate. Defaults to 1. """ return None @@ -54,50 +152,45 @@ def __call__(self, qubits, seed=None, **params) -> List[Tuple[Tuple[int, ...], G class SingleQubitSampler(RBSampler): """A sampler that samples layers of random single-qubit gates from a specified gate set.""" - # pylint: disable=arguments-differ def __call__( self, - qubits, - length, - gate_set: Optional[Union[str, List]] = "clifford", - seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, - ) -> List[Tuple[Tuple[int, ...], GateType]]: - """Samples random single-qubit gates from a specified gate set. + qubits: Sequence, + length: int = 1, + ) -> List[List[Tuple[Tuple[int, ...], GateType]]]: + """Samples random single-qubit gates from the specified gate set. Args: qubits: A sequence of qubits to generate layers for. length: The length of the sequence to output. - gate_set: The one qubit gate set to sample from. Can be either a - list of gates, "clifford", or "pauli". Default is "clifford". seed: Seed for random generation. Returns: A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over ``num_qubits`` qubits. Each layer is represented by a list of tuples which are in the format ((one or more qubit indices), gate). Single-qubit - Cliffords are represented by integers for speed. For two qubits, length - 3, and the default Clifford gate set, an example output would be - - .. parsed-literal:: + Cliffords are represented by integers for speed. For two qubits, length 3, + and the full Clifford distribution `[(1, "clifford1q")]`, an example output + would be - [(((0,), 2), ((1,), 2)), (((0,), 11), ((1,), 4)), (((0,), 17), ((1,), 17))] + .. parsed-literal:: + [[((0,), 2), ((1,), 2)], [((0,), 11), ((1,), 4)], [((0,), 17), ((1,), 17)]] """ - rng = default_rng(seed=seed) - num_qubits = len(qubits) - if gate_set == "clifford": - layers = [] - for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=(length, num_qubits)): - layers.append(tuple(zip(((j,) for j in qubits), i))) - elif gate_set == "pauli": - layers = [] - for i in range(length): - layers.append( - tuple(zip(((j,) for j in qubits), random_pauli(num_qubits, seed=rng))) - ) - else: - layers = [] - for i in rng.integers(len(gate_set), size=(length, num_qubits)): - layers.append(tuple(zip(((j,) for j in qubits), gate_set[i]))) + + gateset = self._probs_by_gate_size() + if not math.isclose(sum(gateset[1][1]), 1): + raise QiskitError( + "The distribution for SingleQubitSampler should be all single qubit gates." + ) + + samples = self._rng.choice( + gateset[1][0], + size=(length, len(qubits)), + p=gateset[1][1], + ) + + layers = [] + for layer in samples: + layers.append(tuple(zip(((j,) for j in qubits), layer))) return layers @@ -129,28 +222,15 @@ class EdgeGrabSampler(RBSampler): """ - # pylint: disable=arguments-differ def __call__( self, - qubits: int, - two_qubit_gate_density: float, - coupling_map: List[List[int]], - length: int, - one_qubit_gate_set: Optional[Union[str, List]] = "clifford", - two_qubit_gate_set: Optional[Union[str, List]] = "cx", - seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, + qubits: Sequence, + length: int = 1, ) -> List[Tuple[Tuple[int, ...], GateType]]: """Sample layers using the edge grab algorithm. Args: qubits: A sequence of qubits to generate layers for. - one_qubit_gate_set: The one qubit gate set to sample from. Can be either a - list of gates or "clifford". - two_qubit_gate_set: The two qubit gate set to sample from. Can be either a - list of gates or one of "cx", "cy", "cz", or "csx". - two_qubit_gate_density: the expected fraction of two-qubit gates in the - sampled layer. - coupling_map: List of pairs of connected edges between qubits. length: The length of the sequence to output. seed: Seed for random generation. @@ -168,38 +248,33 @@ def __call__( two-qubit gates: .. parsed-literal:: - - (((1, 2), 0), ((0,), 12), ((3,), 20)) + (((1, 2), CXGate), ((0,), 12), ((3,), 20)) This represents a layer where the 12th Clifford is performed on qubit 0, a CX is performed with control qubit 1 and target qubit 2, and the 20th Clifford is performed on qubit 3. """ - rng = default_rng(seed=seed) num_qubits = len(qubits) - if not isinstance(one_qubit_gate_set, list) and one_qubit_gate_set.casefold() != "clifford": - raise TypeError("one_qubit_gate_set must be a list of gates or 'clifford'.") - + gateset = self._probs_by_gate_size() + norm1q = sum(gateset[1][1]) + norm2q = sum(gateset[2][1]) + two_qubit_gate_density = sum(gateset[2][1]) / (sum(gateset[2][1]) + sum(gateset[1][1])) if num_qubits == 1: - if one_qubit_gate_set.casefold() == "clifford": - return ( - (((qubits[0],), i),) - for i in rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT, size=length) + return [ + (((qubits[0],), i),) + for i in self._rng.choice( + gateset[1][0], p=[i / norm1q for i in gateset[1][1]], size=length ) - else: - return list(enumerate((0, i) for i in rng.choice(one_qubit_gate_set, size=length))) - - if not isinstance(two_qubit_gate_set, list) and two_qubit_gate_set.casefold() != "cx": - raise TypeError("two_qubit_gate_set must be a list of gates or 'cx'.") + ] layer_list = [] for _ in list(range(length)): - all_edges = coupling_map[:] # make copy of coupling map from which we pop edges + all_edges = self.coupling_map[:] # make copy of coupling map from which we pop edges selected_edges = [] while all_edges: - rand_edge = all_edges.pop(rng.integers(len(all_edges))) + rand_edge = all_edges.pop(self._rng.integers(len(all_edges))) selected_edges.append( rand_edge ) # move random edge from all_edges to selected_edges @@ -222,22 +297,46 @@ def __call__( + "Actual density of two-qubit gates will likely be lower than input density." ) - put_1_qubit_gates = set(qubits) - # put_1_qubit_gates is a list of qubits that aren't assigned to a 2-qubit gate + put_1q_gates = set(qubits) + # put_1q_gates is a list of qubits that aren't assigned to a 2-qubit gate # 1-qubit gates will be assigned to these edges layer = [] for edge in selected_edges: - if rng.random() < two_qubit_prob: + if self._rng.random() < two_qubit_prob: # with probability two_qubit_prob, place a two-qubit gate from the # gate set on edge in selected_edges - if two_qubit_gate_set == "cx": - layer.append((tuple(edge), CXGate())) + if len(gateset[2][0]) == 1: + layer.append((tuple(edge), gateset[2][0][0])) else: - layer.append(edge, rng.choice(two_qubit_gate_set)) - # remove these qubits from put_1_qubit_gates - put_1_qubit_gates.remove(edge[0]) - put_1_qubit_gates.remove(edge[1]) - for q in put_1_qubit_gates: - layer.append(((q,), rng.integers(CliffordUtils.NUM_CLIFFORD_1_QUBIT))) + layer.append( + ( + tuple(edge), + self._rng.choice( + gateset[2][0], + p=[x / norm2q for x in gateset[2][1]], + ), + ), + ) + # remove these qubits from put_1q_gates + put_1q_gates.remove(edge[0]) + put_1q_gates.remove(edge[1]) + for q in put_1q_gates: + + if sum(gateset[1][1]) > 0: + layer.append( + ( + (q,), + self._rng.choice( + gateset[1][0], p=[x / norm1q for x in gateset[1][1]] + ), + ) + ) + else: # edge case of two qubit density of 1 where we still fill gaps + layer.append( + ( + (q,), + self._rng.choice(gateset[1][0]), + ) + ) layer_list.append(tuple(layer)) return layer_list diff --git a/test/library/randomized_benchmarking/test_sampling_utils.py b/test/library/randomized_benchmarking/test_sampling_utils.py new file mode 100644 index 0000000000..9d44af4593 --- /dev/null +++ b/test/library/randomized_benchmarking/test_sampling_utils.py @@ -0,0 +1,69 @@ +# 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. + +""" +Tests for RB sampling utils. +""" + +from test.base import QiskitExperimentsTestCase + +from qiskit.circuit.library import XGate, CXGate + +from qiskit_experiments.library.randomized_benchmarking.sampling_utils import ( + SingleQubitSampler, + EdgeGrabSampler, +) +from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils + + +class TestSamplingUtils(QiskitExperimentsTestCase): + """Tests for the Sampler classes.""" + + seed = 1 + + def test_gate_distribution(self): + """Test the gate distribution is calculated correctly.""" + sampler = SingleQubitSampler(seed=self.seed) + sampler.gate_distribution = [(0.8, 1, "clifford"), (0.2, 2, XGate)] + dist = sampler._probs_by_gate_size() + self.assertEqual(len(dist[1][0]), 24) + self.assertAlmostEqual(sum(dist[1][1]), 0.8) + self.assertEqual(dist[2][0], [XGate]) + self.assertAlmostEqual(sum(dist[2][1]), 0.2) + + def test_1q_custom_gate(self): + """Test that the single qubit sampler works with custom gates.""" + sampler = SingleQubitSampler(seed=self.seed) + sampler.gate_distribution = [(1, 1, XGate)] + layer = sampler((0,), 3) + self.assertEqual( + layer, + [(((0,), XGate),), (((0,), XGate),), (((0,), XGate),)], + ) + + def test_1q_cliffords(self): + """Test that the single qubit sampler can generate clifford layers.""" + sampler = SingleQubitSampler(seed=self.seed) + sampler.gate_distribution = [(1, 1, "clifford")] + layer = sampler((0,), 3) + for i in layer: + self.assertTrue(i[0][1] < CliffordUtils.NUM_CLIFFORD_1_QUBIT and i[0][1] >= 0) + + def test_edgegrab(self): + """Test that the edge grab sampler behaves as expected.""" + sampler = EdgeGrabSampler(seed=self.seed) + sampler.gate_distribution = [(0.5, 1, "clifford"), (0.5, 2, CXGate)] + layer = sampler((0,), 3) + for i in layer: + self.assertTrue( + (i[0][1] < CliffordUtils.NUM_CLIFFORD_1_QUBIT and i[0][1] >= 0) or i[0][1] == CXGate + ) From 999bd6f97848f33a344eab00eca870a8f760f3fd Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Thu, 23 Mar 2023 01:02:55 -0400 Subject: [PATCH 42/56] added distribution property to `MirrorRB` now users can fully customize the distribution after instantiation. also changed `local_clifford` to `start_end_clifford` which is clearer. --- docs/manuals/benchmarking/mirror_rb.rst | 83 ++++++++-- .../mirror_rb_experiment.py | 155 +++++++++++------- .../randomized_benchmarking/sampling_utils.py | 87 +++++----- .../test_randomized_benchmarking.py | 77 ++++++--- .../test_sampling_utils.py | 10 ++ 5 files changed, 270 insertions(+), 142 deletions(-) diff --git a/docs/manuals/benchmarking/mirror_rb.rst b/docs/manuals/benchmarking/mirror_rb.rst index cc6f564c4c..aead0a6468 100644 --- a/docs/manuals/benchmarking/mirror_rb.rst +++ b/docs/manuals/benchmarking/mirror_rb.rst @@ -171,7 +171,7 @@ There are three boolean options that - ``pauli_randomize`` (default ``True``): if ``True``, put layers of uniformly random Paulis between the intermediate Clifford layers -- ``local_clifford`` (default ``True``): if ``True``, begin the circuit with +- ``start_end_clifford`` (default ``True``): if ``True``, begin the circuit with uniformly random one-qubit Cliffords and end the circuit with their inverses - ``inverting_pauli_layer`` (default ``False``): if ``True``, add a layer of @@ -201,7 +201,7 @@ And now with both options turned off: seed=100, backend=backend, num_samples=1, - local_clifford=False, + start_end_clifford=False, two_qubit_gate_density=0.4, pauli_randomize=False, inverting_pauli_layer=True) @@ -216,43 +216,95 @@ change. We'll demonstrate this by first leaving ``pauli_randomize`` on: .. jupyter-execute:: - exp = MirrorRB(range(8), + # choose a linear string on this backend for ease of visualization + exp = MirrorRB((0,1,2,3,5,8,11,14), lengths=[2], two_qubit_gate_density=0.5, - seed=101, + seed=120, backend=backend, - num_samples=1) + num_samples=1, + start_end_clifford=False) exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") -Note that And now we remove the Pauli layers to see that the CX density in the Clifford layers -have halved: +And now we remove the Pauli layers to see that the CX density in the Clifford layers +has decreased: .. jupyter-execute:: - exp = MirrorRB(range(8), + exp = MirrorRB((0,1,2,3,5,8,11,14), lengths=[2], two_qubit_gate_density=0.5, pauli_randomize=False, + seed=120, + backend=backend, + num_samples=1, + start_end_clifford=False) + exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") + +Note that the edge grab algorithm is probabilistic, and only tends to the exact two +qubit gate density asymptotically. + + +Custom layer distributions +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to customize the layer distributions when running mirror RB by setting +the distribution and its options directly using the :attr:`.MirrorRB.distribution` +attribute. Note that if the distribution options are set manually after experiment +instantiation, the experiment will let you override experiment options such as +``two_qubit_gate_density`` with your custom distribution. + +Here is an example where we override the default distribution and change the gate +distribution manually into one with 20% single-qubit Paulis and 80% two-qubit +:class:`~.qiskit.circuit.library.ECRGate` (Consult the :class:`.EdgeGrabSampler` +documentation for details on available options): + +.. jupyter-execute:: + + from qiskit.circuit.library import ECRGate + + exp = MirrorRB(range(4), + lengths=[2], + two_qubit_gate_density=0.5, seed=101, backend=backend, - num_samples=1) + num_samples=1, + start_end_clifford=False) + exp.distribution.gate_distribution = [(0.5, 1, "pauli"), (0.5, 2, ECRGate)] exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") +If we reset the distribution to :class:`.EdgeGrabSampler`, we will get the expected +default behavior again. + +.. jupyter-execute:: + + exp.distribution = EdgeGrabSampler + exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") +It is possible to set the distribution to another sampler entirely, or your own custom sampler: + +.. jupyter-execute:: + + from qiskit_experiments.library.randomized_benchmarking.sampling_utils import SingleQubitSampler + from qiskit.circuit.library import SGate + + exp.distribution = SingleQubitSampler + exp.distribution.gate_distribution = [(1, 1, SGate)] + exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The :mod:`pygsti` implementation of Mirror RB, +The :mod:`pygsti` implementation of mirror RB, :class:`~.pygsti.protocols.rb.MirrorRBDesign`, can be used for testing and comparison. We note however that ``pyGSTi`` transpiles circuits slightly differently, producing small discrepancies in fit parameters between the two codes. To illustrate, consider the -two circuits below, both of which were generated in ``pyGSTi``. The first circuit was -transpiled in ``pyGSTi``. +two circuits below, both of which were generated in ``pyGSTi``. This first circuit was +transpiled in ``pyGSTi``: .. image:: images/pygsti-data-pygsti-transpiled-circ.png -and the second was transpiled in Qiskit. +This second circuit was transpiled in Qiskit: .. image:: images/pygsti-data-qiskit-transpiled-circ.png @@ -273,3 +325,8 @@ References Blume-Kohout, *Measuring the Capabilities of Quantum Computers*, https://arxiv.org/pdf/2008.11294.pdf + +See also +-------- + +* :doc:` /manuals/verification/randomized_benchmarking` diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 296de9d0bf..3229a61c59 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -12,9 +12,11 @@ """ Mirror RB Experiment class. """ +import warnings from typing import Union, Iterable, Optional, List, Sequence, Tuple from numbers import Integral import itertools +import numpy as np from numpy.random import Generator, BitGenerator, SeedSequence, default_rng from qiskit.circuit import QuantumCircuit, Instruction, Barrier @@ -40,18 +42,18 @@ class MirrorRB(StandardRB): and Pauli gates. # section: overview - Mirror randomized benchmarking (mirror RB) is a method to estimate the average - error-rate of quantum gates that is more scalable than the standard RB methods. - - A mirror RB experiment generates circuits of layers of Cliffords interleaved - with layers of Pauli gates and capped at the start and end by a layer of - single-qubit Cliffords. The second half of the Clifford layers are the - inverses of the first half of Clifford layers. After running the circuits on - a backend, various quantities (success probability, adjusted success - probability, and effective polarization) are computed and used to fit an - exponential decay curve and calculate the EPC (error per Clifford, also - referred to as the average gate infidelity) and entanglement infidelity (see - references for more info). + Mirror randomized benchmarking (mirror RB) estimates the average error rate of + quantum gates using gate layers sampled from a distribution that are then + inverted in the second half of the circuit. + + The default mirror RB experiment generates circuits of layers of Cliffords + interleaved with layers of Pauli gates and capped at the start and end by a + layer of single-qubit Cliffords. The second half of the Clifford layers are the + inverses of the first half of Clifford layers. After running the circuits on a + backend, various quantities (success probability, adjusted success probability, + and effective polarization) are computed and used to fit an exponential decay + curve and calculate the EPC (error per Clifford, also referred to as the average + gate infidelity) and entanglement infidelity (see references for more info). # section: analysis_ref :class:`MirrorRBAnalysis` @@ -69,7 +71,7 @@ def __init__( physical_qubits: Sequence[int], lengths: Iterable[int], distribution: RBSampler = EdgeGrabSampler, - local_clifford: bool = True, + start_end_clifford: bool = True, pauli_randomize: bool = True, two_qubit_gate_density: float = 0.2, two_qubit_gate: GateType = CXGate, @@ -85,12 +87,12 @@ def __init__( physical_qubits: A list of physical qubits for the experiment. lengths: A list of RB sequences lengths. distribution: The probability distribution over the layer set to sample. - Defaults to the :class:`.EdgeGrabSampler`. Distribution options can be set by + Defaults to :class:`.EdgeGrabSampler`. Distribution options can be set by accessing the distribution object of this class. - local_clifford: If True, begin the circuit with uniformly random 1-qubit + start_end_clifford: If True, begin the circuit with uniformly random 1-qubit Cliffords and end the circuit with their inverses. - pauli_randomize: If True, surround each inner Clifford layer with - uniformly random Paulis. + pauli_randomize: If True, surround each inner Clifford layer with layers of + uniformly random 1-qubit Paulis. two_qubit_gate_density: Expected proportion of qubit sites with two-qubit gates over all circuit layers (not counting optional layers at the start and end). @@ -126,16 +128,16 @@ def __init__( full_sampling=full_sampling, ) - self.distribution = distribution() - self.set_experiment_options( - local_clifford=local_clifford, + start_end_clifford=start_end_clifford, pauli_randomize=pauli_randomize, inverting_pauli_layer=inverting_pauli_layer, two_qubit_gate_density=two_qubit_gate_density, two_qubit_gate=two_qubit_gate, ) + self.distribution = distribution + self.analysis = MirrorRBAnalysis() @classmethod @@ -143,10 +145,10 @@ def _default_experiment_options(cls) -> Options: """Default experiment options. Experiment Options: - local_clifford (bool): Whether to begin the circuit with uniformly random 1-qubit + start_end_clifford (bool): Whether to begin the circuit with uniformly random 1-qubit Cliffords and end the circuit with their inverses. pauli_randomize (bool): Whether to surround each inner Clifford layer with - uniformly random Paulis. + layers of uniformly random 1-qubit Paulis. inverting_pauli_layer (bool): Whether to append a layer of Pauli gates at the end of the circuit to set all qubits to 0. two_qubit_gate_density (float): Expected proportion of two-qubit gates in @@ -157,10 +159,10 @@ def _default_experiment_options(cls) -> Options: """ options = super()._default_experiment_options() options.update_options( - local_clifford=True, + start_end_clifford=True, pauli_randomize=True, two_qubit_gate_density=0.2, - two_qubit_gate="cx", + two_qubit_gate=CXGate, distribution=None, inverting_pauli_layer=False, ) @@ -178,41 +180,48 @@ def circuits(self) -> List[QuantumCircuit]: return circuits - def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: - """Sample layers of mirror RB using the provided distribution and user options. - - First, layers are sampled using the distribution, then Pauli-dressed if - ``pauli_randomize`` is ``True``. The inverse of the resulting circuit is - appended to the end. If ``local_clifford`` is ``True``, then cliffords are added - to the beginning and end. If ``inverting_pauli_layer`` is ``True``, a Pauli - layer will be appended at the end to set the output bitstring to all zeros. - - Returns: - A list of mirror RB sequences. Each element is a list of layers with length - matching the corresponding element in ``lengths``. The layers are made up - of tuples in the format ((one or more qubit indices), gate). Single-qubit - Cliffords are represented by integers for speed. - - Raises: - QiskitError: If no backend is provided. - """ - if not self._backend: - raise QiskitError("A backend must be provided for circuit generation.") + def _set_backend(self, backend: Backend): + """Set the backend for the experiment.""" + super()._set_backend(backend) + # Recalculate the coupling map if needed + if hasattr(self, "_distribution"): + self.set_distribution_options() + + @property + def distribution(self): + """The sampling distribution for generating circuit layers. If this attribute + is set manually, the experiment will use the distribution as given and not + override the provided sampler's gate distribution using the other experiment + options such as ``two_qubit_gate_density``.""" + return self._distribution + + @distribution.setter + def distribution(self, distribution): + """Set the sampling distribution.""" + self._distribution = distribution() + self.set_distribution_options() + + def set_distribution_options(self): + """Set the coupling map and gate distribution of the sampler + based on experiment options.""" + + self.distribution.seed = self.experiment_options.seed # Coupling map is full connectivity by default. If backend has a coupling map, # get backend coupling map and create coupling map for physical qubits converted # to qubits 0, 1...n - coupling_map = list(itertools.permutations(range(max(self.physical_qubits) + 1), 2)) - if self._backend_data.coupling_map: + if self.backend and self._backend_data.coupling_map: coupling_map = self._backend_data.coupling_map - + else: + coupling_map = list(itertools.permutations(range(max(self.physical_qubits) + 1), 2)) qmap = {self.physical_qubits[i]: i for i in range(len(self.physical_qubits))} experiment_coupling_map = [] + for edge in coupling_map: if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append((qmap[edge[0]], qmap[edge[1]])) - rng = default_rng(seed=self.experiment_options.seed) + self.distribution.coupling_map = experiment_coupling_map # Adjust the density based on whether the pauli layers are in if self.experiment_options.pauli_randomize: @@ -220,13 +229,36 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: else: adjusted_2q_density = self.experiment_options.two_qubit_gate_density - self.distribution.seed = rng - self.distribution.coupling_map = experiment_coupling_map - self.distribution.gate_distribution = [ + if adjusted_2q_density > 1: + warnings.warn("Two-qubit gate density is too high, capping at 1.") + adjusted_2q_density = 1 + + self._distribution.gate_distribution = [ (adjusted_2q_density, 2, self.experiment_options.two_qubit_gate), (1 - adjusted_2q_density, 1, "clifford"), ] + def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: + """Sample layers of mirror RB using the provided distribution and user options. + + First, layers are sampled using the distribution, then Pauli-dressed if + ``pauli_randomize`` is ``True``. The inverse of the resulting circuit is + appended to the end. If ``start_end_clifford`` is ``True``, then cliffords are added + to the beginning and end. If ``inverting_pauli_layer`` is ``True``, a Pauli + layer will be appended at the end to set the output bitstring to all zeros. + + Returns: + A list of mirror RB sequences. Each element is a list of layers with length + matching the corresponding element in ``lengths``. The layers are made up + of tuples in the format ((one or more qubit indices), gate). Single-qubit + Cliffords are represented by integers for speed. + + Raises: + QiskitError: If no backend is provided. + """ + if not self._backend: + raise QiskitError("A backend must be provided for circuit generation.") + # Sequence of lengths to sample for if not self.experiment_options.full_sampling: seqlens = (max(self.experiment_options.lengths),) @@ -234,11 +266,11 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: seqlens = self.experiment_options.lengths if self.experiment_options.pauli_randomize: - pauli_sampler = SingleQubitSampler(seed=rng) + pauli_sampler = SingleQubitSampler(seed=self.experiment_options.seed) pauli_sampler.gate_distribution = [(1, 1, "pauli")] - if self.experiment_options.local_clifford: - clifford_sampler = SingleQubitSampler(seed=rng) + if self.experiment_options.start_end_clifford: + clifford_sampler = SingleQubitSampler(seed=self.experiment_options.seed) clifford_sampler.gate_distribution = [(1, 1, "clifford")] sequences = [] @@ -272,8 +304,8 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if not self.experiment_options.full_sampling: build_seq_lengths = [length * 2 + 1 for length in build_seq_lengths] - # Add start and end local cliffords if set by user - if self.experiment_options.local_clifford: + # Add start and end cliffords if set by user + if self.experiment_options.start_end_clifford: cseq = [] clifford_layers = clifford_sampler(range(self.num_qubits), length=1) cseq.append(clifford_layers[0]) @@ -358,7 +390,7 @@ def _inverse_layer( self, layer: List[Tuple[Tuple[int, ...], GateType]] ) -> List[Tuple[Tuple[int, ...], GateType]]: """Generates the inverse layer of a Clifford mirror RB layer by inverting the - single-qubit Cliffords and keeping the CXs identical. See + single-qubit Cliffords and keeping the two-qubit gate identical. See :class:`.RBSampler` for the format of the layer. Args: @@ -372,10 +404,13 @@ def _inverse_layer( """ inverse_layer = [] for elem in layer: - if len(elem[0]) == 1: + if len(elem[0]) == 1 and np.issubdtype(type(elem[1]), int): inverse_layer.append((elem[0], inverse_1q(elem[1]))) - elif len(elem[0]) == 2: + elif len(elem[0]) == 2 and elem[1] == CXGate: inverse_layer.append(elem) else: - raise QiskitError("Invalid layer from sampler.") + try: + inverse_layer.append((elem[0], elem[1]().inverse())) + except TypeError as exc: + raise QiskitError("Invalid layer supplied.") from exc return tuple(inverse_layer) diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 2a1a3a929c..015a90b3b1 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -33,7 +33,7 @@ class RBSampler(ABC): - """Sampling distribution for randomized benchmarking experiments. + """Base class for the sampling distribution for randomized benchmarking experiments. Subclasses must implement the ``__call__()`` method.""" def __init__( @@ -42,9 +42,7 @@ def __init__( coupling_map: Optional[List[List[int]]] = None, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, ): - """Instantiate the sampler. Note that this is different from invoking the - instance. - + """ Args: seed: Seed for random generation. gate_distribution: The gate distribution for sampling. @@ -166,11 +164,10 @@ def __call__( Returns: A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over - ``num_qubits`` qubits. Each layer is represented by a list of tuples which - are in the format ((one or more qubit indices), gate). Single-qubit - Cliffords are represented by integers for speed. For two qubits, length 3, - and the full Clifford distribution `[(1, "clifford1q")]`, an example output - would be + ``qubits``. Each layer is represented by a list of tuples which are in the + format ((one or more qubit indices), gate). Single-qubit Cliffords are + represented by integers for speed. For two qubits, length 3, and the + all-Clifford distribution ``[(1, "clifford")]``, an example output would be .. parsed-literal:: [[((0,), 2), ((1,), 2)], [((0,), 11), ((1,), 4)], [((0,), 17), ((1,), 17)]] @@ -195,30 +192,29 @@ def __call__( class EdgeGrabSampler(RBSampler): - r"""A sampler that uses the edge grab algorithm for sampling one- and two-qubit gate - layers. + r"""A sampler that uses the edge grab algorithm [1] for sampling gate layers. - # section: overview + The edge grab sampler, given a list of :math:`w` qubits, their connectivity + graph, and the desired two-qubit gate density :math:`\xi_s`, outputs a layer + as follows: - The edge grab sampler, given a list of :math:`w` qubits, their connectivity - graph, and the desired two-qubit gate density :math:`\xi_s`, outputs a layer - as follows: + 1. Begin with the empty set :math:`E` and :math:`E_r`, the set of all edges + in the connectivity graph. Select an edge from :math:`E_r` at random and + add it to :math:`E`, removing all edges that share a qubit with the edge + from :math:`E_r`. - 1. Begin with the empty set :math:`E` and :math:`E_r`, the set of all edges - in the connectivity graph. Select an edge from :math:`E_r` at random and - add it to :math:`E`, removing all edges that share a qubit with the edge - from :math:`E_r`. - 2. Select edges from :math:`E` with the probability :math:`w\xi/2|E|`. These - edges will have two-qubit gates in the output layer. + 2. Select edges from :math:`E` with the probability :math:`w\xi/2|E|`. These + edges will have two-qubit gates in the output layer. - This produces a layer with an expected two-qubit gate density :math:`\xi`. In - the default mirror RB configuration where these layers are dressed with - single-qubit Pauli layers, this means the overall two-qubit gate density will be - :math:`\xi_s/2=\xi`. The overall density will converge to :math:`\xi` as the - circuit size increases. + | - # section: reference - .. ref_arxiv:: 1 2008.11294 + This produces a layer with an expected two-qubit gate density :math:`\xi`. In + the default mirror RB configuration where these layers are dressed with + single-qubit Pauli layers, this means the overall two-qubit gate density will be + :math:`\xi_s/2=\xi`. The overall density will converge to :math:`\xi` as the + circuit size increases. + + .. ref_arxiv:: 1 2008.11294 """ @@ -256,7 +252,6 @@ def __call__( """ num_qubits = len(qubits) - gateset = self._probs_by_gate_size() norm1q = sum(gateset[1][1]) norm2q = sum(gateset[2][1]) @@ -269,6 +264,9 @@ def __call__( ) ] + if not isinstance(self.coupling_map, List): + raise QiskitError("The coupling map must be set correctly before sampling.") + layer_list = [] for _ in list(range(length)): all_edges = self.coupling_map[:] # make copy of coupling map from which we pop edges @@ -291,7 +289,7 @@ def __call__( two_qubit_prob = num_qubits * two_qubit_gate_density / 2 / len(selected_edges) except ZeroDivisionError: warnings.warn("Device has no connectivity. All gates will be single-qubit.") - if two_qubit_prob > 1: + if two_qubit_prob > 1 and not np.isclose(two_qubit_prob, 1): warnings.warn( "Mean number of two-qubit gates is higher than the number of selected edges. " + "Actual density of two-qubit gates will likely be lower than input density." @@ -320,23 +318,20 @@ def __call__( # remove these qubits from put_1q_gates put_1q_gates.remove(edge[0]) put_1q_gates.remove(edge[1]) - for q in put_1q_gates: - - if sum(gateset[1][1]) > 0: - layer.append( - ( - (q,), - self._rng.choice( - gateset[1][0], p=[x / norm1q for x in gateset[1][1]] - ), - ) + for q in put_1q_gates: + if sum(gateset[1][1]) > 0: + layer.append( + ( + (q,), + self._rng.choice(gateset[1][0], p=[x / norm1q for x in gateset[1][1]]), ) - else: # edge case of two qubit density of 1 where we still fill gaps - layer.append( - ( - (q,), - self._rng.choice(gateset[1][0]), - ) + ) + else: # edge case of two qubit density of 1 where we still fill gaps + layer.append( + ( + (q,), + self._rng.choice(gateset[1][0]), ) + ) layer_list.append(tuple(layer)) return layer_list diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index da91d617e4..6e6cf2b936 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -19,7 +19,7 @@ from ddt import ddt, data, unpack from qiskit.circuit import Delay, QuantumCircuit, Parameter, Gate -from qiskit.circuit.library import SXGate, CXGate, TGate, CZGate +from qiskit.circuit.library import SXGate, CXGate, TGate, CZGate, ECRGate from qiskit.exceptions import QiskitError from qiskit.providers.fake_provider import FakeManila, FakeManilaV2, FakeWashington, FakeParis from qiskit.pulse import Schedule, InstructionScheduleMap @@ -36,7 +36,9 @@ from qiskit_experiments.library import randomized_benchmarking as rb from qiskit_experiments.library.randomized_benchmarking.clifford_utils import ( compute_target_bitstring, + CliffordUtils, ) +from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler class RBTestMixin: @@ -928,6 +930,8 @@ def run(self, circuits, validate=False, parameter_binds=None, **run_options): class TestMirrorRB(QiskitExperimentsTestCase, RBTestMixin): """Test for mirror RB.""" + seed = 123 + def setUp(self): """Setup the tests.""" super().setUp() @@ -946,14 +950,14 @@ def test_return_same_circuit(self): exp1 = rb.MirrorRB( physical_qubits=(0, 1), lengths=lengths, - seed=123, + seed=self.seed, backend=self.backend, ) exp2 = rb.MirrorRB( physical_qubits=(0, 1), lengths=lengths, - seed=123, + seed=self.seed, backend=self.backend, ) @@ -968,7 +972,7 @@ def test_full_sampling(self): exp1 = rb.MirrorRB( physical_qubits=(0, 1), lengths=[10, 20], - seed=123, + seed=self.seed, backend=self.backend, num_samples=1, full_sampling=True, @@ -977,7 +981,7 @@ def test_full_sampling(self): exp2 = rb.MirrorRB( physical_qubits=(0, 1), lengths=[10, 20], - seed=123, + seed=self.seed, backend=self.backend, num_samples=1, full_sampling=False, @@ -998,7 +1002,7 @@ def test_zero_2q_gate_density(self): exp = rb.MirrorRB( physical_qubits=(0, 1), lengths=[40], - seed=124, + seed=self.seed, backend=self.backend, num_samples=1, two_qubit_gate_density=0, @@ -1017,7 +1021,7 @@ def test_max_2q_gate_density(self): exp = rb.MirrorRB( physical_qubits=(0, 1, 2, 3), lengths=[40], - seed=125, + seed=self.seed, backend=backend, num_samples=1, two_qubit_gate_density=0.5, @@ -1029,16 +1033,16 @@ def test_max_2q_gate_density(self): num_cxs += 1 self.assertEqual(80, num_cxs) - def test_local_clifford(self): + def test_start_end_clifford(self): """Test that the number of layers is correct depending on whether - local_clifford is set to True or False by counting the number of barriers.""" + start_end_clifford is set to True or False by counting the number of barriers.""" exp = rb.MirrorRB( physical_qubits=(0,), lengths=[2], - seed=126, + seed=self.seed, backend=self.backend, num_samples=1, - local_clifford=True, + start_end_clifford=True, pauli_randomize=False, two_qubit_gate_density=0.2, inverting_pauli_layer=False, @@ -1056,10 +1060,10 @@ def test_pauli_randomize(self): exp = rb.MirrorRB( physical_qubits=(0,), lengths=[2], - seed=126, + seed=self.seed, backend=self.backend, num_samples=1, - local_clifford=False, + start_end_clifford=False, pauli_randomize=True, two_qubit_gate_density=0.2, inverting_pauli_layer=False, @@ -1077,10 +1081,10 @@ def test_inverting_pauli_layer(self): exp = rb.MirrorRB( physical_qubits=(0, 1, 2), lengths=[2], - seed=127, + seed=self.seed, backend=self.backend, num_samples=3, - local_clifford=True, + start_end_clifford=True, pauli_randomize=True, two_qubit_gate_density=0.2, inverting_pauli_layer=True, @@ -1120,6 +1124,7 @@ def test_backend_with_directed_basis_gates(self): lengths=[4], num_samples=4, backend=my_backend, + seed=self.seed, ) transpiled = exp._transpiled_circuits() for qc in transpiled: @@ -1129,11 +1134,37 @@ def test_backend_with_directed_basis_gates(self): if inst.operation.name == "cx": self.assertEqual(inst.qubits, expected_qubits) + def test_change_distribution_options(self): + """Test that changing the distribution option and then resetting works as expected.""" + + exp = rb.MirrorRB( + physical_qubits=range(4), + two_qubit_gate_density=1, + lengths=[4], + num_samples=1, + backend=self.backend, + seed=self.seed, + ) + + exp.distribution.gate_distribution = [(0.2, 1, "clifford"), (0.8, 2, ECRGate)] + gates = exp.circuits()[0].count_ops() + if "ecr" not in gates or "cx" in gates: + raise QiskitError("Unexpected output gate distribution.") + + exp.distribution = EdgeGrabSampler + + gates = exp.circuits()[0].count_ops() + + if "cx" not in gates or "ecr" in gates: + raise QiskitError("Unexpected output gate distribution.") + @ddt class TestRunMirrorRB(RBRunTestCase): """Class for testing execution of mirror RB experiments.""" + seed = 123 + def setUp(self): """Setup the tests.""" super().setUp() @@ -1177,7 +1208,7 @@ def test_single_qubit(self): exp = rb.MirrorRB( physical_qubits=(0,), lengths=list(range(2, 300, 40)), - seed=124, + seed=self.seed, backend=self.backend, num_samples=20, ) @@ -1208,7 +1239,7 @@ def test_two_qubit(self): exp = rb.MirrorRB( physical_qubits=(0, 1), lengths=list(range(2, 80, 16)), - seed=123, + seed=self.seed, backend=self.backend, num_samples=20, two_qubit_gate_density=two_qubit_gate_density, @@ -1266,9 +1297,9 @@ def test_two_qubit_nonlocal_noise(self): exp = rb.MirrorRB( physical_qubits=(0, 1), lengths=list(range(2, 110, 20)), - seed=123, + seed=self.seed, backend=noise_backend, - num_samples=20, + num_samples=30, two_qubit_gate_density=two_qubit_gate_density, ) exp.analysis.set_options(gate_error_ratio=None) @@ -1288,7 +1319,7 @@ def test_two_qubit_nonlocal_noise(self): sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) def test_three_qubit_nonlocal_noise(self): """Test three-qubit mirrored RB on a nonlocal noise model""" @@ -1323,7 +1354,7 @@ def test_three_qubit_nonlocal_noise(self): exp = rb.MirrorRB( physical_qubits=(0, 1, 2), lengths=list(range(2, 110, 50)), - seed=123, + seed=self.seed, backend=noise_backend, num_samples=20, two_qubit_gate_density=two_qubit_gate_density, @@ -1351,7 +1382,7 @@ def test_add_more_circuit_yields_lower_variance(self): exp1 = rb.MirrorRB( physical_qubits=(0, 1), lengths=list(range(2, 30, 4)), - seed=123, + seed=self.seed, backend=self.backend, num_samples=3, inverting_pauli_layer=False, @@ -1454,7 +1485,7 @@ def test_expdata_serialization(self): exp = rb.MirrorRB( physical_qubits=(0,), lengths=list(range(2, 200, 50)), - seed=123, + seed=self.seed, backend=self.backend, inverting_pauli_layer=False, ) diff --git a/test/library/randomized_benchmarking/test_sampling_utils.py b/test/library/randomized_benchmarking/test_sampling_utils.py index 9d44af4593..cd605e68a8 100644 --- a/test/library/randomized_benchmarking/test_sampling_utils.py +++ b/test/library/randomized_benchmarking/test_sampling_utils.py @@ -67,3 +67,13 @@ def test_edgegrab(self): self.assertTrue( (i[0][1] < CliffordUtils.NUM_CLIFFORD_1_QUBIT and i[0][1] >= 0) or i[0][1] == CXGate ) + + def test_edgegrab_all_2q(self): + """Test that the edge grab sampler behaves as expected when two qubit density is + 1.""" + sampler = EdgeGrabSampler(seed=self.seed) + sampler.gate_distribution = [(0, 1, "clifford"), (1, 2, CXGate)] + sampler.coupling_map = [[k, k + 1] for k in range(9)] + layer = sampler(range(10), 3) + for i in layer: + self.assertTrue(i[0][1] == CXGate) From 3b0ae70dadc51754a18d4cf2420a5c60bea7fa5a Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Thu, 23 Mar 2023 01:19:36 -0400 Subject: [PATCH 43/56] lint and fix docs --- docs/manuals/verification/mirror_rb.rst | 10 +--------- .../randomized_benchmarking/mirror_rb_analysis.py | 4 ++-- .../randomized_benchmarking/mirror_rb_experiment.py | 10 +++++----- .../randomized_benchmarking/sampling_utils.py | 13 ++++++++----- .../test_randomized_benchmarking.py | 1 - 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index aead0a6468..a1e5f914c3 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -107,15 +107,7 @@ experiment: lengths = np.arange(2, 810, 200) num_samples = 5 seed = 1010 - qubits = (0,) - - exp_2q = MirrorRB((0,1), - lengths=[4], - backend=backend, - num_samples=1, - seed=1010, - two_qubit_gate_density=.4, - distribution=EdgeGrabSampler) + qubits = (0,1) exp_2q = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) expdata_2q = exp_2q.run(backend).block_for_results() diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index 1fced93803..23ddaf0d5d 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -213,7 +213,7 @@ def _format_data( # TODO Eventually move this to data processor, then create RB data processor. # take average over the same x value by keeping sigma - data_allocation, xdata, ydata, sigma, shots = curve.data_processing.multi_mean_xy_data( + data_allocation, xdata, ydata, sigma, shots = curve.utils.multi_mean_xy_data( series=curve_data.data_allocation, xdata=curve_data.x, ydata=curve_data.y, @@ -223,7 +223,7 @@ def _format_data( ) # sort by x value in ascending order - data_allocation, xdata, ydata, sigma, shots = curve.data_processing.data_sort( + data_allocation, xdata, ydata, sigma, shots = curve.utils.data_sort( series=data_allocation, xdata=xdata, ydata=ydata, diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 3229a61c59..34ddb79e97 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -17,7 +17,7 @@ from numbers import Integral import itertools import numpy as np -from numpy.random import Generator, BitGenerator, SeedSequence, default_rng +from numpy.random import Generator, BitGenerator, SeedSequence from qiskit.circuit import QuantumCircuit, Instruction, Barrier from qiskit.quantum_info.operators import Pauli @@ -34,7 +34,7 @@ inverse_1q, _clifford_1q_int_to_instruction, ) -from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler, GateType +from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler, GateTypeT class MirrorRB(StandardRB): @@ -74,7 +74,7 @@ def __init__( start_end_clifford: bool = True, pauli_randomize: bool = True, two_qubit_gate_density: float = 0.2, - two_qubit_gate: GateType = CXGate, + two_qubit_gate: GateTypeT = CXGate, backend: Optional[Backend] = None, num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, @@ -387,8 +387,8 @@ def _to_instruction( return elem() def _inverse_layer( - self, layer: List[Tuple[Tuple[int, ...], GateType]] - ) -> List[Tuple[Tuple[int, ...], GateType]]: + self, layer: List[Tuple[Tuple[int, ...], GateTypeT]] + ) -> List[Tuple[Tuple[int, ...], GateTypeT]]: """Generates the inverse layer of a Clifford mirror RB layer by inverting the single-qubit Cliffords and keeping the two-qubit gate identical. See :class:`.RBSampler` for the format of the layer. diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 015a90b3b1..5a60f47e18 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -20,6 +20,7 @@ from collections import defaultdict from numpy.random import Generator, default_rng, BitGenerator, SeedSequence +import numpy as np from qiskit import QuantumCircuit from qiskit.circuit import Instruction @@ -29,7 +30,7 @@ from .clifford_utils import CliffordUtils, _CLIFF_SINGLE_GATE_MAP_1Q -GateType = TypeVar("GateType", str, int, Instruction, Operator, QuantumCircuit, BaseOperator) +GateTypeT = TypeVar("GateTypeT", str, int, Instruction, Operator, QuantumCircuit, BaseOperator) class RBSampler(ABC): @@ -83,7 +84,7 @@ def gate_distribution(self): return self._gate_distribution @gate_distribution.setter - def gate_distribution(self, dist: List[Tuple[float, int, GateType]]): + def gate_distribution(self, dist: List[Tuple[float, int, GateTypeT]]): """Set the distribution of gates used in the sampler. Args: @@ -134,7 +135,9 @@ def _probs_by_gate_size(self): return gate_probs @abstractmethod - def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[Tuple[int, ...], GateType]]: + def __call__( + self, qubits: Sequence, length: int = 1 + ) -> List[Tuple[Tuple[int, ...], GateTypeT]]: """Samplers should define this method such that it returns sampled layers given the input parameters. Each layer is represented by a list of size-2 tuples where the first element is a tuple of qubit indices, and the second @@ -154,7 +157,7 @@ def __call__( self, qubits: Sequence, length: int = 1, - ) -> List[List[Tuple[Tuple[int, ...], GateType]]]: + ) -> List[List[Tuple[Tuple[int, ...], GateTypeT]]]: """Samples random single-qubit gates from the specified gate set. Args: @@ -222,7 +225,7 @@ def __call__( self, qubits: Sequence, length: int = 1, - ) -> List[Tuple[Tuple[int, ...], GateType]]: + ) -> List[Tuple[Tuple[int, ...], GateTypeT]]: """Sample layers using the edge grab algorithm. Args: diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 6e6cf2b936..8a91244e4a 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -36,7 +36,6 @@ from qiskit_experiments.library import randomized_benchmarking as rb from qiskit_experiments.library.randomized_benchmarking.clifford_utils import ( compute_target_bitstring, - CliffordUtils, ) from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler From d318e5106a49038edab433085fef7836724a8ca9 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Thu, 23 Mar 2023 01:53:09 -0400 Subject: [PATCH 44/56] fix doc links --- docs/manuals/verification/mirror_rb.rst | 2 +- .../library/randomized_benchmarking/mirror_rb_experiment.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index a1e5f914c3..f2497d8def 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -321,4 +321,4 @@ References See also -------- -* :doc:` /manuals/verification/randomized_benchmarking` +* Experiment manual: :doc:`/manuals/verification/randomized_benchmarking` diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 34ddb79e97..e17d8d567d 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -58,6 +58,9 @@ class MirrorRB(StandardRB): # section: analysis_ref :class:`MirrorRBAnalysis` + # section: manual + :doc:`/manuals/verification/mirror_rb` + # section: reference .. ref_arxiv:: 1 2112.09853 .. ref_arxiv:: 2 2008.11294 From fb23e995edbad09a3c771b250cf5eb85d5998c73 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Thu, 23 Mar 2023 15:45:09 -0400 Subject: [PATCH 45/56] Update tests Changed tolerances to be based on std_dev. Optimization level is removed since it's now 1 by default. --- docs/manuals/verification/mirror_rb.rst | 2 +- .../mirror_rb_experiment.py | 3 ++- .../test_randomized_benchmarking.py | 14 ++++++-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index f2497d8def..51786c0ac2 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -129,7 +129,7 @@ instead of the default: .. jupyter-execute:: - lengths = np.arange(2,302,50) + lengths = np.arange(2,202,50) num_samples = 5 seed = 42 qubits = (0,) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index e17d8d567d..dadb5574be 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -46,7 +46,8 @@ class MirrorRB(StandardRB): quantum gates using gate layers sampled from a distribution that are then inverted in the second half of the circuit. - The default mirror RB experiment generates circuits of layers of Cliffords + The default mirror RB experiment generates circuits of layers of Cliffords, + consisting of single-qubit Cliffords and a two-qubit gate such as CX, interleaved with layers of Pauli gates and capped at the start and end by a layer of single-qubit Cliffords. The second half of the Clifford layers are the inverses of the first half of Clifford layers. After running the circuits on a diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 5fe3c45675..34ebffd9e8 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -939,7 +939,6 @@ def setUp(self): self.transpiler_options = { "basis_gates": self.basis_gates, - "optimization_level": 1, } def test_return_same_circuit(self): @@ -1229,7 +1228,7 @@ def test_single_qubit(self): epc = expdata.analysis_results("EPC") epc_expected = 1 - (1 - 1 / 2 * self.p1q) ** 2.0 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.1 * epc_expected) + self.assertAlmostEqual(epc.value.n, epc_expected, delta=3 * epc.value.std_dev) def test_two_qubit(self): """Test two qubit RB.""" @@ -1259,7 +1258,7 @@ def test_two_qubit(self): cx_factor = (1 - 3 * self.p2q / 4) ** (2 * two_qubit_gate_density) sx_factor = (1 - self.p1q / 2) ** (2 * 2 * (1 - two_qubit_gate_density)) epc_expected = 1 - cx_factor * sx_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + self.assertAlmostEqual(epc.value.n, epc_expected, delta=3 * epc.value.std_dev) def test_two_qubit_nonlocal_noise(self): """Test for 2 qubit Mirrored RB with a nonlocal noise model""" @@ -1282,7 +1281,6 @@ def test_two_qubit_nonlocal_noise(self): # Need level1 for consecutive gate cancellation for reference EPC value calculation transpiler_options = { "basis_gates": basis_gates, - "optimization_level": 1, } # Coupling map is 3 x 3 lattice noise_backend = NoiseSimulator( @@ -1317,10 +1315,11 @@ def test_two_qubit_nonlocal_noise(self): sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + print(epc.value.n, epc_expected) + self.assertAlmostEqual(epc.value.n, epc_expected, delta=3 * epc.value.std_dev) def test_three_qubit_nonlocal_noise(self): - """Test three-qubit mirrored RB on a nonlocal noise model""" + """Test three-qubit mirror RB on a nonlocal noise model""" # depolarizing error p1q = 0.001 p2q = 0.01 @@ -1340,7 +1339,6 @@ def test_three_qubit_nonlocal_noise(self): # Need level1 for consecutive gate cancellation for reference EPC value calculation transpiler_options = { "basis_gates": basis_gates, - "optimization_level": 1, } noise_backend = NoiseSimulator( noise_model=noise_model, @@ -1373,7 +1371,7 @@ def test_three_qubit_nonlocal_noise(self): # 4. Use qiskit.quantum_info.average_gate_fidelity on these N layers # to compute 1 - EPC for each layer, and average over the N layers. epc_expected = 0.0124 - self.assertAlmostEqual(epc.value.n, epc_expected, delta=0.2 * epc_expected) + self.assertAlmostEqual(epc.value.n, epc_expected, delta=3 * epc.value.std_dev) def test_add_more_circuit_yields_lower_variance(self): """Test variance reduction with larger number of sampling.""" From 7224f59dfa57b86b36f8fcda125b2c5d501a003c Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Thu, 23 Mar 2023 18:09:09 -0400 Subject: [PATCH 46/56] fix nonlocal test there's an issue with `NoiseSimulator` throwing a coupling map related error on 2 qubits that seems unrelated to mirror since standard RB also fails. Changed the coupling map to 2 qubits to avoid this. Also updated the gate type. --- .../mirror_rb_experiment.py | 6 +++-- .../randomized_benchmarking/sampling_utils.py | 5 +--- .../test_randomized_benchmarking.py | 23 ++++++++----------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index dadb5574be..a4bc91cdd5 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -100,7 +100,8 @@ def __init__( two_qubit_gate_density: Expected proportion of qubit sites with two-qubit gates over all circuit layers (not counting optional layers at the start and end). - two_qubit_gate: The two-qubit gate to use. Defaults to "cx". + two_qubit_gate: The two-qubit gate to use. Defaults to + :class:`~qiskit.circuit.library.CXGate`. backend: The backend to run the experiment on. num_samples: Number of samples to generate for each sequence length. seed: Optional, seed used to initialize ``numpy.random.default_rng``. @@ -158,7 +159,8 @@ def _default_experiment_options(cls) -> Options: two_qubit_gate_density (float): Expected proportion of two-qubit gates in the mirror circuit layers (not counting Clifford or Pauli layers at the start and end). - two_qubit_gate (str | ): The two qubit gate to use. + two_qubit_gate (str | int | :class:`~qiskit.circuit.Instruction`): The two + qubit gate to use. Defaults to :class:`~qiskit.circuit.library.CXGate`. num_samples (int): Number of samples to generate for each sequence length. """ options = super()._default_experiment_options() diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 5a60f47e18..2100577936 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -22,15 +22,12 @@ from numpy.random import Generator, default_rng, BitGenerator, SeedSequence import numpy as np -from qiskit import QuantumCircuit from qiskit.circuit import Instruction -from qiskit.quantum_info.operators.base_operator import BaseOperator -from qiskit.quantum_info import Operator from qiskit.exceptions import QiskitError from .clifford_utils import CliffordUtils, _CLIFF_SINGLE_GATE_MAP_1Q -GateTypeT = TypeVar("GateTypeT", str, int, Instruction, Operator, QuantumCircuit, BaseOperator) +GateTypeT = TypeVar("GateTypeT", str, int, Instruction) class RBSampler(ABC): diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 34ebffd9e8..6acf64a829 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -834,13 +834,6 @@ def test_expdata_serialization(self): self.assertRoundTripPickle(expdata, check_func=self.experiment_data_equiv) -def decr_dep_param(q, q_1, q_2, coupling_map): - """Helper function to generate a one-qubit depolarizing channel whose - parameter depends on coupling map distance in a backend""" - d = min(coupling_map.distance(q, q_1), coupling_map.distance(q, q_2)) - return 0.0035 * 0.999**d - - class NonlocalCXDepError(TransformationPass): """Transpiler pass for simulating nonlocal errors in a quantum device""" @@ -854,6 +847,12 @@ def __init__(self, coupling_map, initial_layout=None): self.coupling_map = coupling_map self.initial_layout = initial_layout + def decr_dep_param(self, q, q_1, q_2, coupling_map): + """Helper function to generate a one-qubit depolarizing channel whose + parameter depends on coupling map distance in a backend""" + d = min(coupling_map.distance(q, q_1), coupling_map.distance(q, q_2)) + return 0.0035 * 0.999**d + def run(self, dag): """Runs the NonlocalCXDepError pass on `dag` @@ -895,7 +894,7 @@ def run(self, dag): qubit_1 = current_layout[cx.qargs[0]] qubit_2 = current_layout[cx.qargs[1]] for qubit in range(dag.num_qubits()): - dep_param = decr_dep_param(qubit, qubit_1, qubit_2, self.coupling_map) + dep_param = self.decr_dep_param(qubit, qubit_1, qubit_2, self.coupling_map) graph.apply_operation_back( depolarizing_error(dep_param, 1).to_instruction(), qargs=[canonical_register[qubit]], @@ -1278,15 +1277,14 @@ def test_two_qubit_nonlocal_noise(self): noise_model.add_all_qubit_quantum_error(cx_error, "cx") basis_gates = ["id", "sx", "rz", "cx"] - # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { "basis_gates": basis_gates, } - # Coupling map is 3 x 3 lattice noise_backend = NoiseSimulator( noise_model=noise_model, seed_simulator=123, - coupling_map=CouplingMap.from_grid(3, 3).get_edges(), + coupling_map=CouplingMap.from_grid(2, 1).get_edges(), ) two_qubit_gate_density = 0.2 @@ -1315,7 +1313,6 @@ def test_two_qubit_nonlocal_noise(self): sx_factor = (1 - p1q / 2) ** (2 * num_q * (1 - two_qubit_gate_density)) cx_nonlocal_factor = (1 - 0.0035 / 2) ** (num_q * num_q * two_qubit_gate_density) epc_expected = 1 - cx_factor * sx_factor * cx_nonlocal_factor - print(epc.value.n, epc_expected) self.assertAlmostEqual(epc.value.n, epc_expected, delta=3 * epc.value.std_dev) def test_three_qubit_nonlocal_noise(self): @@ -1336,7 +1333,7 @@ def test_three_qubit_nonlocal_noise(self): noise_model.add_all_qubit_quantum_error(cx_error, "cx") basis_gates = ["id", "sx", "rz", "cx"] - # Need level1 for consecutive gate cancellation for reference EPC value calculation + transpiler_options = { "basis_gates": basis_gates, } From 09fe450c18bf2bb706b664416e34cb26b770a9ff Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Fri, 24 Mar 2023 17:50:01 -0400 Subject: [PATCH 47/56] address review comments - removed deprecation warning - changed two_qubit_gate type to `Instruction`. this required changing the input to `rng.choice` to a numpy array with `dype=Instruction` - renamed `RBSampler` to `BaseSampler` - removed `distribution` experiment option since it's set separately (may need to refactor this) --- docs/manuals/verification/mirror_rb.rst | 12 +++-- .../randomized_benchmarking/__init__.py | 4 +- .../randomized_benchmarking/clifford_utils.py | 10 ++--- .../mirror_rb_experiment.py | 26 +++++------ .../randomized_benchmarking/sampling_utils.py | 44 +++++++++++-------- .../notes/mirror-rb-ec4d695a9a923971.yaml | 2 +- .../test_randomized_benchmarking.py | 2 +- 7 files changed, 54 insertions(+), 46 deletions(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index 51786c0ac2..18ae793a84 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -89,7 +89,7 @@ user can specify an expected two-qubit gate density :math:`\xi \in \left[0, Even though a :class:`.MirrorRB` experiment can be instantiated without a backend, the backend must be specified when the circuits are sampled because :math:`\Omega` depends on the backend's connectivity. To use your own :math:`\Omega`, you have to implement -your own subclass of the abstract :class:`.RBSampler` class, but here we will use +your own subclass of the abstract :class:`.BaseSampler` class, but here we will use the built-in :class:`.EdgeGrabSampler`. Here's how to instantiate and run the experiment: @@ -254,6 +254,7 @@ documentation for details on available options): .. jupyter-execute:: from qiskit.circuit.library import ECRGate + from qiskit.circuit.library import HGate exp = MirrorRB(range(4), lengths=[2], @@ -262,7 +263,7 @@ documentation for details on available options): backend=backend, num_samples=1, start_end_clifford=False) - exp.distribution.gate_distribution = [(0.5, 1, "pauli"), (0.5, 2, ECRGate)] + exp.distribution.gate_distribution = [(0.4, 1, "pauli"),(0.4, 1, HGate()),(0.2, 2, ECRGate())] exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") If we reset the distribution to :class:`.EdgeGrabSampler`, we will get the expected @@ -278,12 +279,14 @@ It is possible to set the distribution to another sampler entirely, or your own .. jupyter-execute:: from qiskit_experiments.library.randomized_benchmarking.sampling_utils import SingleQubitSampler - from qiskit.circuit.library import SGate + from qiskit.circuit.library import SGate, HGate exp.distribution = SingleQubitSampler - exp.distribution.gate_distribution = [(1, 1, SGate)] + exp.distribution.gate_distribution = [(0.5, 1, SGate()), (0.5, 1, HGate())] exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") +Note that only Clifford gates can be used. + Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -321,4 +324,5 @@ References See also -------- +* API documentation: :mod:`.MirrorRB` * Experiment manual: :doc:`/manuals/verification/randomized_benchmarking` diff --git a/qiskit_experiments/library/randomized_benchmarking/__init__.py b/qiskit_experiments/library/randomized_benchmarking/__init__.py index ece3c8d29b..bda786eabe 100644 --- a/qiskit_experiments/library/randomized_benchmarking/__init__.py +++ b/qiskit_experiments/library/randomized_benchmarking/__init__.py @@ -46,7 +46,7 @@ :toctree: ../stubs/ RBUtils - RBSampler + BaseSampler EdgeGrabSampler SingleQubitSampler @@ -54,7 +54,7 @@ from .rb_experiment import StandardRB from .interleaved_rb_experiment import InterleavedRB from .mirror_rb_experiment import MirrorRB -from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler +from .sampling_utils import BaseSampler, EdgeGrabSampler, SingleQubitSampler from .rb_analysis import RBAnalysis from .interleaved_rb_analysis import InterleavedRBAnalysis from .mirror_rb_analysis import MirrorRBAnalysis diff --git a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py index 5a96e37ca1..9a721f21f2 100644 --- a/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/clifford_utils.py @@ -300,18 +300,14 @@ def _unpack_num(num, sig): def compute_target_bitstring(circuit: QuantumCircuit) -> str: - """For a Clifford circuit C, compute C|0>. + """For a Pauli circuit C, which consists only of Clifford gates, compute C|0>. Args: - circuit: A Clifford QuantumCircuit. + circuit: A Pauli QuantumCircuit. Returns: Target bitstring. """ - # convert circuit to Boolean phase vector of stabilizer table - phase_vector = Clifford(circuit).table.phase - n = circuit.num_qubits - # target string has a 1 for each True in the stabilizer half of the phase vector - target = "".join(["1" if phase else "0" for phase in phase_vector[n:][::-1]]) + target = "".join(["1" if phase else "0" for phase in Clifford(circuit).stab_phase[::-1]]) return target diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index a4bc91cdd5..16c3bbd395 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -24,9 +24,8 @@ from qiskit.providers.backend import Backend from qiskit.providers.options import Options from qiskit.exceptions import QiskitError -from qiskit.circuit.library import CXGate +from qiskit.circuit.library import CXGate, CYGate, CZGate, ECRGate, SwapGate, iSwapGate -from qiskit_experiments.warnings import deprecate_arguments from .rb_experiment import StandardRB, SequenceElementType from .mirror_rb_analysis import MirrorRBAnalysis from .clifford_utils import ( @@ -34,7 +33,10 @@ inverse_1q, _clifford_1q_int_to_instruction, ) -from .sampling_utils import RBSampler, EdgeGrabSampler, SingleQubitSampler, GateTypeT +from .sampling_utils import BaseSampler, EdgeGrabSampler, SingleQubitSampler, GateTypeT + +# two qubit gates that are their own inverse +_self_adjoint_gates = [CXGate, CYGate, CZGate, ECRGate, SwapGate, iSwapGate] class MirrorRB(StandardRB): @@ -69,16 +71,15 @@ class MirrorRB(StandardRB): """ - @deprecate_arguments({"qubits": "physical_qubits"}, "0.5") def __init__( self, physical_qubits: Sequence[int], lengths: Iterable[int], - distribution: RBSampler = EdgeGrabSampler, + distribution: BaseSampler = EdgeGrabSampler, start_end_clifford: bool = True, pauli_randomize: bool = True, two_qubit_gate_density: float = 0.2, - two_qubit_gate: GateTypeT = CXGate, + two_qubit_gate: Instruction = CXGate(), backend: Optional[Backend] = None, num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, @@ -147,7 +148,7 @@ def __init__( @classmethod def _default_experiment_options(cls) -> Options: - """Default experiment options. + """Default mirror RB experiment options. Experiment Options: start_end_clifford (bool): Whether to begin the circuit with uniformly random 1-qubit @@ -159,7 +160,7 @@ def _default_experiment_options(cls) -> Options: two_qubit_gate_density (float): Expected proportion of two-qubit gates in the mirror circuit layers (not counting Clifford or Pauli layers at the start and end). - two_qubit_gate (str | int | :class:`~qiskit.circuit.Instruction`): The two + two_qubit_gate (:class:`~qiskit.circuit.Instruction`): The two qubit gate to use. Defaults to :class:`~qiskit.circuit.library.CXGate`. num_samples (int): Number of samples to generate for each sequence length. """ @@ -168,8 +169,7 @@ def _default_experiment_options(cls) -> Options: start_end_clifford=True, pauli_randomize=True, two_qubit_gate_density=0.2, - two_qubit_gate=CXGate, - distribution=None, + two_qubit_gate=CXGate(), inverting_pauli_layer=False, ) @@ -397,7 +397,7 @@ def _inverse_layer( ) -> List[Tuple[Tuple[int, ...], GateTypeT]]: """Generates the inverse layer of a Clifford mirror RB layer by inverting the single-qubit Cliffords and keeping the two-qubit gate identical. See - :class:`.RBSampler` for the format of the layer. + :class:`.BaseSampler` for the format of the layer. Args: layer: The input layer. @@ -412,11 +412,11 @@ def _inverse_layer( for elem in layer: if len(elem[0]) == 1 and np.issubdtype(type(elem[1]), int): inverse_layer.append((elem[0], inverse_1q(elem[1]))) - elif len(elem[0]) == 2 and elem[1] == CXGate: + elif len(elem[0]) == 2 and elem[1] in _self_adjoint_gates: inverse_layer.append(elem) else: try: - inverse_layer.append((elem[0], elem[1]().inverse())) + inverse_layer.append((elem[0], elem[1].inverse())) except TypeError as exc: raise QiskitError("Invalid layer supplied.") from exc return tuple(inverse_layer) diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 2100577936..a0a0404d28 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -30,7 +30,7 @@ GateTypeT = TypeVar("GateTypeT", str, int, Instruction) -class RBSampler(ABC): +class BaseSampler(ABC): """Base class for the sampling distribution for randomized benchmarking experiments. Subclasses must implement the ``__call__()`` method.""" @@ -75,7 +75,7 @@ def gate_distribution(self): example distribution for the edge grab sampler might be .. parsed-literal:: - [(0.8, 1, "clifford"), (0.2, 2, CXGate)] + [(0.8, 1, "clifford"), (0.2, 2, CXGate())] The probabilities must sum to 1.""" return self._gate_distribution @@ -91,13 +91,16 @@ def gate_distribution(self, dist: List[Tuple[float, int, GateTypeT]]): raise TypeError("The gate distribution should be a list.") if sum(list(zip(*dist))[0]) != 1: raise QiskitError("Gate distribution probabilities must sum to 1.") + for gate in dist: + if gate[2] not in ["clifford", "pauli"] and not isinstance(gate[2], Instruction): + raise TypeError( + "The only allowed gates in the distribution are 'clifford', 'pauli', and Instruction instances." + ) self._gate_distribution = dist def _probs_by_gate_size(self): - """Return a list of gates and their probabilities indexed by the size of the gate. The - probability distributions are normalized to 1 within each gate size category. - """ + """Return a list of gates and their probabilities indexed by the size of the gate.""" if not self._gate_distribution: raise QiskitError("Gate distribution must be set before sampling.") gate_probs = defaultdict(list) @@ -115,7 +118,7 @@ def _probs_by_gate_size(self): _CLIFF_SINGLE_GATE_MAP_1Q[("y", (0,))], _CLIFF_SINGLE_GATE_MAP_1Q[("z", (0,))], ] - probs = [gate[0] / 4] * 4 + probs = [gate[0] / len(gateset)] * len(gateset) elif gate[2] == "clifford" and gate[1] == 2: gateset = list(range(CliffordUtils.NUM_CLIFFORD_2_QUBIT)) probs = [ @@ -147,7 +150,7 @@ def __call__( return None -class SingleQubitSampler(RBSampler): +class SingleQubitSampler(BaseSampler): """A sampler that samples layers of random single-qubit gates from a specified gate set.""" def __call__( @@ -180,7 +183,7 @@ def __call__( ) samples = self._rng.choice( - gateset[1][0], + np.array(gateset[1][0], dtype=Instruction), size=(length, len(qubits)), p=gateset[1][1], ) @@ -191,7 +194,7 @@ def __call__( return layers -class EdgeGrabSampler(RBSampler): +class EdgeGrabSampler(BaseSampler): r"""A sampler that uses the edge grab algorithm [1] for sampling gate layers. The edge grab sampler, given a list of :math:`w` qubits, their connectivity @@ -208,10 +211,10 @@ class EdgeGrabSampler(RBSampler): | - This produces a layer with an expected two-qubit gate density :math:`\xi`. In - the default mirror RB configuration where these layers are dressed with - single-qubit Pauli layers, this means the overall two-qubit gate density will be - :math:`\xi_s/2=\xi`. The overall density will converge to :math:`\xi` as the + This produces a layer with an expected two-qubit gate density :math:`\xi`. In the + default mirror RB configuration where these layers are dressed with single-qubit + Pauli layers, this means the overall expected two-qubit gate density will be + :math:`\xi_s/2=\xi`. The actual density will converge to :math:`\xi_s` as the circuit size increases. .. ref_arxiv:: 1 2008.11294 @@ -244,7 +247,7 @@ def __call__( two-qubit gates: .. parsed-literal:: - (((1, 2), CXGate), ((0,), 12), ((3,), 20)) + (((1, 2), CXGate()), ((0,), 12), ((3,), 20)) This represents a layer where the 12th Clifford is performed on qubit 0, a CX is performed with control qubit 1 and target qubit 2, and the 20th @@ -260,7 +263,9 @@ def __call__( return [ (((qubits[0],), i),) for i in self._rng.choice( - gateset[1][0], p=[i / norm1q for i in gateset[1][1]], size=length + np.array(gateset[1][0], dtype=Instruction), + p=[i / norm1q for i in gateset[1][1]], + size=length, ) ] @@ -310,7 +315,7 @@ def __call__( ( tuple(edge), self._rng.choice( - gateset[2][0], + np.array(gateset[2][0], dtype=Instruction), p=[x / norm2q for x in gateset[2][1]], ), ), @@ -323,14 +328,17 @@ def __call__( layer.append( ( (q,), - self._rng.choice(gateset[1][0], p=[x / norm1q for x in gateset[1][1]]), + self._rng.choice( + np.array(gateset[1][0], dtype=Instruction), + p=[x / norm1q for x in gateset[1][1]], + ), ) ) else: # edge case of two qubit density of 1 where we still fill gaps layer.append( ( (q,), - self._rng.choice(gateset[1][0]), + self._rng.choice(np.array(gateset[1][0], dtype=Instruction)), ) ) layer_list.append(tuple(layer)) diff --git a/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml index 75335567d9..9953864b88 100644 --- a/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml +++ b/releasenotes/notes/mirror-rb-ec4d695a9a923971.yaml @@ -6,5 +6,5 @@ features: the fidelity of user-defined ensembles of randomized mirror circuits. - | Added a base class that samples circuit layers for randomized benchmarking experiments, - :class:`.RBSampler`. The edge grab sampler :class:`.EdgeGrabSampler` and a single + :class:`.BaseSampler`. The edge grab sampler :class:`.EdgeGrabSampler` and a single qubit gate sampler :class:`.SingleQubitSampler` are implemented. \ No newline at end of file diff --git a/test/library/randomized_benchmarking/test_randomized_benchmarking.py b/test/library/randomized_benchmarking/test_randomized_benchmarking.py index 6acf64a829..ce3ac40d74 100644 --- a/test/library/randomized_benchmarking/test_randomized_benchmarking.py +++ b/test/library/randomized_benchmarking/test_randomized_benchmarking.py @@ -1142,7 +1142,7 @@ def test_change_distribution_options(self): seed=self.seed, ) - exp.distribution.gate_distribution = [(0.2, 1, "clifford"), (0.8, 2, ECRGate)] + exp.distribution.gate_distribution = [(0.2, 1, "clifford"), (0.8, 2, ECRGate())] gates = exp.circuits()[0].count_ops() if "ecr" not in gates or "cx" in gates: raise QiskitError("Unexpected output gate distribution.") From 4951cb1e8c1e78ddb75378f38c929d386ee54925 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Sun, 26 Mar 2023 02:43:32 -0400 Subject: [PATCH 48/56] change sampler output to list of named tuple --- docs/manuals/verification/mirror_rb.rst | 4 +- .../mirror_rb_experiment.py | 20 +++-- .../randomized_benchmarking/sampling_utils.py | 80 +++++++++++-------- 3 files changed, 62 insertions(+), 42 deletions(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index 18ae793a84..4e61a9b4fd 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -279,10 +279,10 @@ It is possible to set the distribution to another sampler entirely, or your own .. jupyter-execute:: from qiskit_experiments.library.randomized_benchmarking.sampling_utils import SingleQubitSampler - from qiskit.circuit.library import SGate, HGate + from qiskit.circuit.library import HGate exp.distribution = SingleQubitSampler - exp.distribution.gate_distribution = [(0.5, 1, SGate()), (0.5, 1, HGate())] + exp.distribution.gate_distribution = [(0.5, 1, "pauli"), (0.5, 1, HGate())] exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") Note that only Clifford gates can be used. diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 16c3bbd395..3785c83be6 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -33,7 +33,13 @@ inverse_1q, _clifford_1q_int_to_instruction, ) -from .sampling_utils import BaseSampler, EdgeGrabSampler, SingleQubitSampler, GateTypeT +from .sampling_utils import ( + BaseSampler, + EdgeGrabSampler, + SingleQubitSampler, + GateTypeT, + GateInstruction, +) # two qubit gates that are their own inverse _self_adjoint_gates = [CXGate, CYGate, CZGate, ECRGate, SwapGate, iSwapGate] @@ -352,8 +358,8 @@ def _sequences_to_circuits( circ_target = QuantumCircuit(self.num_qubits) for layer in seq: for elem in layer: - circ.append(self._to_instruction(elem[1], basis_gates), elem[0]) - circ_target.append(self._to_instruction(elem[1]), elem[0]) + circ.append(self._to_instruction(elem.op, basis_gates), elem.qargs) + circ_target.append(self._to_instruction(elem.op), elem.qargs) circ.append(Barrier(self.num_qubits), circ.qubits) circ.metadata = { "xval": self.experiment_options.lengths[i % len(self.experiment_options.lengths)], @@ -410,13 +416,13 @@ def _inverse_layer( """ inverse_layer = [] for elem in layer: - if len(elem[0]) == 1 and np.issubdtype(type(elem[1]), int): - inverse_layer.append((elem[0], inverse_1q(elem[1]))) - elif len(elem[0]) == 2 and elem[1] in _self_adjoint_gates: + if len(elem.qargs) == 1 and np.issubdtype(type(elem.op), int): + inverse_layer.append(GateInstruction(elem.qargs, inverse_1q(elem.op))) + elif len(elem.qargs) == 2 and elem.op in _self_adjoint_gates: inverse_layer.append(elem) else: try: - inverse_layer.append((elem[0], elem[1].inverse())) + inverse_layer.append(GateInstruction(elem.qargs, elem.op.inverse())) except TypeError as exc: raise QiskitError("Invalid layer supplied.") from exc return tuple(inverse_layer) diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index a0a0404d28..38632c0203 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -16,7 +16,7 @@ import warnings import math from abc import ABC, abstractmethod -from typing import Optional, Union, List, Tuple, Sequence, TypeVar +from typing import Optional, Union, List, Tuple, Sequence, TypeVar, NamedTuple from collections import defaultdict from numpy.random import Generator, default_rng, BitGenerator, SeedSequence @@ -30,9 +30,19 @@ GateTypeT = TypeVar("GateTypeT", str, int, Instruction) +class GateInstruction(NamedTuple): + """Named tuple class for sampler output.""" + + # the list of qubits to apply the operation on + qargs: tuple + # the operation to apply + op: GateTypeT + + class BaseSampler(ABC): - """Base class for the sampling distribution for randomized benchmarking experiments. - Subclasses must implement the ``__call__()`` method.""" + """Base class for samplers that generate circuit layers based on a defined + algorithm and gate set. Subclasses must implement the ``__call__()`` method + which outputs a number of circuit layers.""" def __init__( self, @@ -40,7 +50,8 @@ def __init__( coupling_map: Optional[List[List[int]]] = None, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, ): - """ + """Initializes the sampler. + Args: seed: Seed for random generation. gate_distribution: The gate distribution for sampling. @@ -94,7 +105,8 @@ def gate_distribution(self, dist: List[Tuple[float, int, GateTypeT]]): for gate in dist: if gate[2] not in ["clifford", "pauli"] and not isinstance(gate[2], Instruction): raise TypeError( - "The only allowed gates in the distribution are 'clifford', 'pauli', and Instruction instances." + "The only allowed gates in the distribution are 'clifford', 'pauli', " + "and Instruction instances." ) self._gate_distribution = dist @@ -135,17 +147,19 @@ def _probs_by_gate_size(self): return gate_probs @abstractmethod - def __call__( - self, qubits: Sequence, length: int = 1 - ) -> List[Tuple[Tuple[int, ...], GateTypeT]]: + def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[GateInstruction]]: """Samplers should define this method such that it returns sampled layers - given the input parameters. Each layer is represented by a list of size-2 tuples - where the first element is a tuple of qubit indices, and the second - element represents the gate that should be applied to the indices. + given the input parameters. Each layer is represented by a list of + ``GateInstruction`` namedtuples, where ``GateInstruction.op`` is the gate to be + applied and ``GateInstruction.qargs`` is the tuple of qubit indices to + apply the gate to. Args: qubits: A sequence of qubits to generate layers for. length: The number of layers to generate. Defaults to 1. + + Returns: + A list of layers consisting of GateInstruction objects. """ return None @@ -157,8 +171,9 @@ def __call__( self, qubits: Sequence, length: int = 1, - ) -> List[List[Tuple[Tuple[int, ...], GateTypeT]]]: - """Samples random single-qubit gates from the specified gate set. + ) -> List[Tuple[GateInstruction]]: + """Samples random single-qubit gates from the specified gate set. The + input gate distribution must consist solely of single qubit gates. Args: qubits: A sequence of qubits to generate layers for. @@ -166,14 +181,12 @@ def __call__( seed: Seed for random generation. Returns: - A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over - ``qubits``. Each layer is represented by a list of tuples which are in the - format ((one or more qubit indices), gate). Single-qubit Cliffords are - represented by integers for speed. For two qubits, length 3, and the - all-Clifford distribution ``[(1, "clifford")]``, an example output would be - - .. parsed-literal:: - [[((0,), 2), ((1,), 2)], [((0,), 11), ((1,), 4)], [((0,), 17), ((1,), 17)]] + A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` + layers over ``qubits``. Each layer is represented by a list of + ``GateInstruction`` tuples where ``GateInstruction.op`` is the gate + to be applied and ``GateInstruction.qargs`` is the tuple of qubit + indices to apply the gate to. Single-qubit Cliffords are represented + by integers for speed. """ gateset = self._probs_by_gate_size() @@ -189,8 +202,10 @@ def __call__( ) layers = [] - for layer in samples: - layers.append(tuple(zip(((j,) for j in qubits), layer))) + for samplelayer in samples: + layers.append( + tuple(GateInstruction(*ins) for ins in zip(((j,) for j in qubits), samplelayer)) + ) return layers @@ -225,7 +240,7 @@ def __call__( self, qubits: Sequence, length: int = 1, - ) -> List[Tuple[Tuple[int, ...], GateTypeT]]: + ) -> List[Tuple[GateInstruction]]: """Sample layers using the edge grab algorithm. Args: @@ -261,7 +276,7 @@ def __call__( two_qubit_gate_density = sum(gateset[2][1]) / (sum(gateset[2][1]) + sum(gateset[1][1])) if num_qubits == 1: return [ - (((qubits[0],), i),) + (GateInstruction((qubits[0],), i),) for i in self._rng.choice( np.array(gateset[1][0], dtype=Instruction), p=[i / norm1q for i in gateset[1][1]], @@ -309,10 +324,10 @@ def __call__( # with probability two_qubit_prob, place a two-qubit gate from the # gate set on edge in selected_edges if len(gateset[2][0]) == 1: - layer.append((tuple(edge), gateset[2][0][0])) + layer.append(GateInstruction(tuple(edge), gateset[2][0][0])) else: layer.append( - ( + GateInstruction( tuple(edge), self._rng.choice( np.array(gateset[2][0], dtype=Instruction), @@ -326,20 +341,19 @@ def __call__( for q in put_1q_gates: if sum(gateset[1][1]) > 0: layer.append( - ( + GateInstruction( (q,), self._rng.choice( np.array(gateset[1][0], dtype=Instruction), p=[x / norm1q for x in gateset[1][1]], ), - ) + ), ) else: # edge case of two qubit density of 1 where we still fill gaps layer.append( - ( - (q,), - self._rng.choice(np.array(gateset[1][0], dtype=Instruction)), - ) + GateInstruction( + (q,), self._rng.choice(np.array(gateset[1][0], dtype=Instruction)) + ), ) layer_list.append(tuple(layer)) return layer_list From 585c053d96d4140352cd1a9ecce7b6ad8c894f76 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Sun, 26 Mar 2023 22:23:42 -0400 Subject: [PATCH 49/56] change gate distribution to named tuple --- .../mirror_rb_experiment.py | 11 +-- .../randomized_benchmarking/sampling_utils.py | 70 +++++++++++-------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 3785c83be6..76348b2da2 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -39,6 +39,7 @@ SingleQubitSampler, GateTypeT, GateInstruction, + GateDistribution, ) # two qubit gates that are their own inverse @@ -246,8 +247,10 @@ def set_distribution_options(self): adjusted_2q_density = 1 self._distribution.gate_distribution = [ - (adjusted_2q_density, 2, self.experiment_options.two_qubit_gate), - (1 - adjusted_2q_density, 1, "clifford"), + GateDistribution( + prob=adjusted_2q_density, nq=2, op=self.experiment_options.two_qubit_gate + ), + GateDistribution(prob=1 - adjusted_2q_density, nq=1, op="clifford"), ] def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: @@ -279,11 +282,11 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if self.experiment_options.pauli_randomize: pauli_sampler = SingleQubitSampler(seed=self.experiment_options.seed) - pauli_sampler.gate_distribution = [(1, 1, "pauli")] + pauli_sampler.gate_distribution = [GateDistribution(prob=1, nq=1, op="pauli")] if self.experiment_options.start_end_clifford: clifford_sampler = SingleQubitSampler(seed=self.experiment_options.seed) - clifford_sampler.gate_distribution = [(1, 1, "clifford")] + clifford_sampler.gate_distribution = [GateDistribution(prob=1, nq=1, op="clifford")] sequences = [] diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 38632c0203..a5153ee92b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -16,7 +16,7 @@ import warnings import math from abc import ABC, abstractmethod -from typing import Optional, Union, List, Tuple, Sequence, TypeVar, NamedTuple +from typing import Optional, Union, List, Tuple, Sequence, TypeVar, NamedTuple, Dict from collections import defaultdict from numpy.random import Generator, default_rng, BitGenerator, SeedSequence @@ -39,6 +39,17 @@ class GateInstruction(NamedTuple): op: GateTypeT +class GateDistribution(NamedTuple): + """Named tuple class for sampler input distribution.""" + + # probability of the instruction to be sampled + prob: float + # the number of qubits the instruction applies to + nq: int + # the instruction, can be Instructions or the special keywords "clifford", "pauli" + op: Union[Instruction, str] + + class BaseSampler(ABC): """Base class for samplers that generate circuit layers based on a defined algorithm and gate set. Subclasses must implement the ``__call__()`` method @@ -49,7 +60,7 @@ def __init__( gate_distribution=None, coupling_map: Optional[List[List[int]]] = None, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, - ): + ) -> None: """Initializes the sampler. Args: @@ -61,38 +72,39 @@ def __init__( self.seed = default_rng(seed) @property - def coupling_map(self): + def coupling_map(self) -> Optional[List[List[int]]]: """The coupling map of the system to sample over.""" return self._coupling_map @coupling_map.setter - def coupling_map(self, coupling_map): + def coupling_map(self, coupling_map) -> None: self._coupling_map = coupling_map @property - def seed(self): + def seed(self) -> Union[int, SeedSequence, BitGenerator, Generator]: """The seed for random generation.""" return self._rng @seed.setter - def seed(self, seed): + def seed(self, seed) -> None: self._rng = default_rng(seed) @property - def gate_distribution(self): - """The gate distribution for sampling. The distribution is a list of tuples - of the form ``(probability, width of gate, gate)``. Gates can be actual - operators, circuits, or the special keywords "clifford", "pauli", "idle". An - example distribution for the edge grab sampler might be + def gate_distribution(self) -> List[GateDistribution]: + """The gate distribution for sampling. The distribution is a list of + ``GateDistribution`` named tuples with field names ``(prob, nq, op)``, + where the probabilites must sum to 1 and ``nq`` is the number of qubits + the ``op`` applies to. Gates can be ``Instruction`` or the special + keywords "clifford", "pauli". An example distribution for the edge grab + sampler might be .. parsed-literal:: [(0.8, 1, "clifford"), (0.2, 2, CXGate())] - - The probabilities must sum to 1.""" + """ return self._gate_distribution @gate_distribution.setter - def gate_distribution(self, dist: List[Tuple[float, int, GateTypeT]]): + def gate_distribution(self, dist: List[GateDistribution]) -> None: """Set the distribution of gates used in the sampler. Args: @@ -100,10 +112,12 @@ def gate_distribution(self, dist: List[Tuple[float, int, GateTypeT]]): """ if not isinstance(dist, List): raise TypeError("The gate distribution should be a list.") + # cast to named tuple + dist = [GateDistribution(*elem) for elem in dist] if sum(list(zip(*dist))[0]) != 1: raise QiskitError("Gate distribution probabilities must sum to 1.") for gate in dist: - if gate[2] not in ["clifford", "pauli"] and not isinstance(gate[2], Instruction): + if gate.op not in ["clifford", "pauli"] and not isinstance(gate.op, Instruction): raise TypeError( "The only allowed gates in the distribution are 'clifford', 'pauli', " "and Instruction instances." @@ -111,39 +125,39 @@ def gate_distribution(self, dist: List[Tuple[float, int, GateTypeT]]): self._gate_distribution = dist - def _probs_by_gate_size(self): + def _probs_by_gate_size(self) -> Dict: """Return a list of gates and their probabilities indexed by the size of the gate.""" if not self._gate_distribution: raise QiskitError("Gate distribution must be set before sampling.") gate_probs = defaultdict(list) for gate in self.gate_distribution: - if gate[2] == "clifford" and gate[1] == 1: + if gate.op == "clifford" and gate.nq == 1: gateset = list(range(CliffordUtils.NUM_CLIFFORD_1_QUBIT)) probs = [ - gate[0] / CliffordUtils.NUM_CLIFFORD_1_QUBIT + gate.prob / CliffordUtils.NUM_CLIFFORD_1_QUBIT ] * CliffordUtils.NUM_CLIFFORD_1_QUBIT - elif gate[2] == "pauli" and gate[1] == 1: + elif gate.op == "pauli" and gate.nq == 1: gateset = [ _CLIFF_SINGLE_GATE_MAP_1Q[("id", (0,))], _CLIFF_SINGLE_GATE_MAP_1Q[("x", (0,))], _CLIFF_SINGLE_GATE_MAP_1Q[("y", (0,))], _CLIFF_SINGLE_GATE_MAP_1Q[("z", (0,))], ] - probs = [gate[0] / len(gateset)] * len(gateset) - elif gate[2] == "clifford" and gate[1] == 2: + probs = [gate.prob / len(gateset)] * len(gateset) + elif gate.op == "clifford" and gate.nq == 2: gateset = list(range(CliffordUtils.NUM_CLIFFORD_2_QUBIT)) probs = [ - gate[0] / CliffordUtils.NUM_CLIFFORD_2_QUBIT + gate.prob / CliffordUtils.NUM_CLIFFORD_2_QUBIT ] * CliffordUtils.NUM_CLIFFORD_2_QUBIT else: - gateset = [gate[2]] - probs = [gate[0]] - if len(gate_probs[gate[1]]) == 0: - gate_probs[gate[1]] = [gateset, probs] + gateset = [gate.op] + probs = [gate.prob] + if len(gate_probs[gate.nq]) == 0: + gate_probs[gate.nq] = [gateset, probs] else: - gate_probs[gate[1]][0].extend(gateset) - gate_probs[gate[1]][1].extend(probs) + gate_probs[gate.nq][0].extend(gateset) + gate_probs[gate.nq][1].extend(probs) return gate_probs @abstractmethod From 38120492e529aa85563338285efca08b317a501c Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Mon, 27 Mar 2023 15:12:39 -0400 Subject: [PATCH 50/56] refactored experiment options now `sampling_algorithm` specifies the algorithm in str form and `sampler_opts` is passed at sampler instantiation. two-qubit gate and density are only passed to the default edge grab sampler, otherwise users have to implement their own methods. also addressed some review comments. --- docs/manuals/verification/mirror_rb.rst | 82 ++------ .../mirror_rb_experiment.py | 121 +++++------ .../randomized_benchmarking/sampling_utils.py | 190 +++++++++++------- .../randomized_benchmarking/test_mirror_rb.py | 29 +-- .../test_sampling_utils.py | 15 +- 5 files changed, 202 insertions(+), 235 deletions(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index 4e61a9b4fd..66d2b375fb 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -86,12 +86,13 @@ user can specify an expected two-qubit gate density :math:`\xi \in \left[0, \frac{1}{2}\right]`, and each intermediate Clifford layer will have approximately :math:`n \xi` CXs on average. -Even though a :class:`.MirrorRB` experiment can be instantiated without a backend, the -backend must be specified when the circuits are sampled because :math:`\Omega` depends -on the backend's connectivity. To use your own :math:`\Omega`, you have to implement -your own subclass of the abstract :class:`.BaseSampler` class, but here we will use -the built-in :class:`.EdgeGrabSampler`. Here's how to instantiate and run the -experiment: +Even though a :class:`.MirrorRB` experiment can be instantiated without a +backend, the backend must be specified when the circuits are sampled because +sampling algorithms containing two-qubit gates need to know the backend's +connectivity. To use your own :math:`\Omega`, you must implement your own +subclass of the abstract :class:`.BaseSampler` class, but in this manual we will +use the built-in :class:`.EdgeGrabSampler`. Here's how to instantiate and run +the experiment: .. jupyter-execute:: @@ -100,9 +101,9 @@ experiment: from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler from qiskit_aer import AerSimulator - from qiskit.providers.fake_provider import FakeParis + from qiskit.providers.fake_provider import FakeParisV2 - backend = AerSimulator.from_backend(FakeParis()) + backend = AerSimulator.from_backend(FakeParisV2()) lengths = np.arange(2, 810, 200) num_samples = 5 @@ -158,10 +159,8 @@ Mirror RB user options There are several options that change the composition of the mirror RB circuit layers. -There are three boolean options that - - ``pauli_randomize`` (default ``True``): if ``True``, put layers of uniformly - random Paulis between the intermediate Clifford layers + random Paulis between the intermediate sampled layers - ``start_end_clifford`` (default ``True``): if ``True``, begin the circuit with uniformly random one-qubit Cliffords and end the circuit with their inverses @@ -184,7 +183,7 @@ between Cliffords and single-qubit Cliffords at the start and end: num_samples=1) exp.circuits()[0].decompose().draw("mpl") -And now with both options turned off: +And now with the intermediate Pauli layers turned off and the inverting Pauli layer added at the end: .. jupyter-execute:: @@ -194,8 +193,7 @@ And now with both options turned off: backend=backend, num_samples=1, start_end_clifford=False, - two_qubit_gate_density=0.4, - pauli_randomize=False, + pauli_randomize=True, inverting_pauli_layer=True) exp.circuits()[0].decompose().draw("mpl") @@ -212,7 +210,7 @@ change. We'll demonstrate this by first leaving ``pauli_randomize`` on: exp = MirrorRB((0,1,2,3,5,8,11,14), lengths=[2], two_qubit_gate_density=0.5, - seed=120, + seed=100, backend=backend, num_samples=1, start_end_clifford=False) @@ -227,66 +225,16 @@ has decreased: lengths=[2], two_qubit_gate_density=0.5, pauli_randomize=False, - seed=120, + seed=100, backend=backend, num_samples=1, start_end_clifford=False) exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") -Note that the edge grab algorithm is probabilistic, and only tends to the exact two +Note that the edge grab algorithm is probabilistic and only tends to the exact two qubit gate density asymptotically. -Custom layer distributions -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -It is possible to customize the layer distributions when running mirror RB by setting -the distribution and its options directly using the :attr:`.MirrorRB.distribution` -attribute. Note that if the distribution options are set manually after experiment -instantiation, the experiment will let you override experiment options such as -``two_qubit_gate_density`` with your custom distribution. - -Here is an example where we override the default distribution and change the gate -distribution manually into one with 20% single-qubit Paulis and 80% two-qubit -:class:`~.qiskit.circuit.library.ECRGate` (Consult the :class:`.EdgeGrabSampler` -documentation for details on available options): - -.. jupyter-execute:: - - from qiskit.circuit.library import ECRGate - from qiskit.circuit.library import HGate - - exp = MirrorRB(range(4), - lengths=[2], - two_qubit_gate_density=0.5, - seed=101, - backend=backend, - num_samples=1, - start_end_clifford=False) - exp.distribution.gate_distribution = [(0.4, 1, "pauli"),(0.4, 1, HGate()),(0.2, 2, ECRGate())] - exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") - -If we reset the distribution to :class:`.EdgeGrabSampler`, we will get the expected -default behavior again. - -.. jupyter-execute:: - - exp.distribution = EdgeGrabSampler - exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") - -It is possible to set the distribution to another sampler entirely, or your own custom sampler: - -.. jupyter-execute:: - - from qiskit_experiments.library.randomized_benchmarking.sampling_utils import SingleQubitSampler - from qiskit.circuit.library import HGate - - exp.distribution = SingleQubitSampler - exp.distribution.gate_distribution = [(0.5, 1, "pauli"), (0.5, 1, HGate())] - exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") - -Note that only Clifford gates can be used. - Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 21ed7b0ce8..7acca5d150 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -34,12 +34,12 @@ _clifford_1q_int_to_instruction, ) from .sampling_utils import ( - BaseSampler, EdgeGrabSampler, SingleQubitSampler, - GateTypeT, GateInstruction, GateDistribution, + GenericClifford, + GenericPauli, ) # two qubit gates that are their own inverse @@ -47,8 +47,8 @@ class MirrorRB(StandardRB): - """An experiment to measure gate infidelity using random mirrored layers of Clifford - and Pauli gates. + """An experiment to measure gate infidelity using mirrored circuit + layers sampled from a defined distribution. # section: overview Mirror randomized benchmarking (mirror RB) estimates the average error rate of @@ -78,15 +78,18 @@ class MirrorRB(StandardRB): """ + sampler_map = {"edge_grab": EdgeGrabSampler, "single_qubit": SingleQubitSampler} + def __init__( self, physical_qubits: Sequence[int], lengths: Iterable[int], - distribution: BaseSampler = EdgeGrabSampler, start_end_clifford: bool = True, pauli_randomize: bool = True, + sampling_algorithm: str = "edge_grab", two_qubit_gate_density: float = 0.2, two_qubit_gate: Instruction = CXGate(), + sampler_opts: dict = {}, backend: Optional[Backend] = None, num_samples: int = 3, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, @@ -98,18 +101,20 @@ def __init__( Args: physical_qubits: A list of physical qubits for the experiment. lengths: A list of RB sequences lengths. - distribution: The probability distribution over the layer set to sample. - Defaults to :class:`.EdgeGrabSampler`. Distribution options can be set by - accessing the distribution object of this class. + sampling_algorithm: The sampling algorithm to use for generating + circuit layers. Defaults to "edge_grab" which uses :class:`.EdgeGrabSampler`. start_end_clifford: If True, begin the circuit with uniformly random 1-qubit Cliffords and end the circuit with their inverses. - pauli_randomize: If True, surround each inner Clifford layer with layers of + pauli_randomize: If True, surround each sampled circuit layer with layers of uniformly random 1-qubit Paulis. two_qubit_gate_density: Expected proportion of qubit sites with two-qubit gates over all circuit layers (not counting optional layers at the start - and end). + and end). Only has effect if the default sampler + :class:`.EdgeGrabSampler` is used. two_qubit_gate: The two-qubit gate to use. Defaults to - :class:`~qiskit.circuit.library.CXGate`. + :class:`~qiskit.circuit.library.CXGate`. Only has effect if the + default sampler :class:`.EdgeGrabSampler` is used. + sampler_opts: Dictionary of keyword arguments to pass to the sampler. backend: The backend to run the experiment on. num_samples: Number of samples to generate for each sequence length. seed: Optional, seed used to initialize ``numpy.random.default_rng``. @@ -142,15 +147,16 @@ def __init__( ) self.set_experiment_options( + sampling_algorithm=sampling_algorithm, + sampler_opts=sampler_opts, start_end_clifford=start_end_clifford, pauli_randomize=pauli_randomize, - inverting_pauli_layer=inverting_pauli_layer, - two_qubit_gate_density=two_qubit_gate_density, two_qubit_gate=two_qubit_gate, + two_qubit_gate_density=two_qubit_gate_density, + inverting_pauli_layer=inverting_pauli_layer, ) - self.distribution = distribution - + self._distribution = self.sampler_map.get(sampling_algorithm)(seed=seed, **sampler_opts) self.analysis = MirrorRBAnalysis() @classmethod @@ -158,25 +164,31 @@ def _default_experiment_options(cls) -> Options: """Default mirror RB experiment options. Experiment Options: + sampling_algorithm (str): Name of sampling algorithm to use. start_end_clifford (bool): Whether to begin the circuit with uniformly random 1-qubit Cliffords and end the circuit with their inverses. pauli_randomize (bool): Whether to surround each inner Clifford layer with layers of uniformly random 1-qubit Paulis. inverting_pauli_layer (bool): Whether to append a layer of Pauli gates at the end of the circuit to set all qubits to 0. - two_qubit_gate_density (float): Expected proportion of two-qubit gates in - the mirror circuit layers (not counting Clifford or Pauli layers at the - start and end). - two_qubit_gate (:class:`~qiskit.circuit.Instruction`): The two - qubit gate to use. Defaults to :class:`~qiskit.circuit.library.CXGate`. + sampler_opts (dict): The keyword arguments to pass to the sampler. + two_qubit_gate_density (float): Expected proportion of qubit sites with two-qubit + gates over all circuit layers (not counting optional layers at the start + and end). Only has effect if the default sampler + :class:`.EdgeGrabSampler` is used. + two_qubit_gate (:class:`.Instruction`): The two-qubit gate to use. Defaults to + :class:`~qiskit.circuit.library.CXGate`. Only has effect if the + default sampler :class:`.EdgeGrabSampler` is used. num_samples (int): Number of samples to generate for each sequence length. """ options = super()._default_experiment_options() options.update_options( + sampling_algorithm="edge_grab", start_end_clifford=True, pauli_randomize=True, two_qubit_gate_density=0.2, two_qubit_gate=CXGate(), + sampler_opts={}, inverting_pauli_layer=False, ) @@ -193,32 +205,18 @@ def circuits(self) -> List[QuantumCircuit]: return circuits - def _set_backend(self, backend: Backend): - """Set the backend for the experiment.""" - super()._set_backend(backend) - # Recalculate the coupling map if needed - if hasattr(self, "_distribution"): - self.set_distribution_options() - - @property - def distribution(self): - """The sampling distribution for generating circuit layers. If this attribute - is set manually, the experiment will use the distribution as given and not - override the provided sampler's gate distribution using the other experiment - options such as ``two_qubit_gate_density``.""" - return self._distribution - - @distribution.setter - def distribution(self, distribution): - """Set the sampling distribution.""" - self._distribution = distribution() - self.set_distribution_options() - - def set_distribution_options(self): + def _set_distribution_options(self): """Set the coupling map and gate distribution of the sampler - based on experiment options.""" + based on experiment options. This method is currently implemented + for the default "edge_grab" sampler.""" + + if self.experiment_options.sampling_algorithm != "edge_grab": + raise QiskitError( + "Unsupported sampling algorithm provided. You must implement" + "a custom `_set_distribution_options` method." + ) - self.distribution.seed = self.experiment_options.seed + self._distribution.seed = self.experiment_options.seed # Coupling map is full connectivity by default. If backend has a coupling map, # get backend coupling map and create coupling map for physical qubits converted @@ -234,7 +232,7 @@ def set_distribution_options(self): if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: experiment_coupling_map.append((qmap[edge[0]], qmap[edge[1]])) - self.distribution.coupling_map = experiment_coupling_map + self._distribution.coupling_map = experiment_coupling_map # Adjust the density based on whether the pauli layers are in if self.experiment_options.pauli_randomize: @@ -246,12 +244,21 @@ def set_distribution_options(self): warnings.warn("Two-qubit gate density is too high, capping at 1.") adjusted_2q_density = 1 - self._distribution.gate_distribution = [ - GateDistribution( - prob=adjusted_2q_density, nq=2, op=self.experiment_options.two_qubit_gate - ), - GateDistribution(prob=1 - adjusted_2q_density, nq=1, op="clifford"), - ] + if self.experiment_options.pauli_randomize: + self._distribution.gate_distribution = [ + GateDistribution( + prob=adjusted_2q_density, op=self.experiment_options.two_qubit_gate + ), + GateDistribution(prob=1 - adjusted_2q_density, op=GenericClifford(1)), + ] + + else: + self._distribution.gate_distribution = [ + GateDistribution( + prob=adjusted_2q_density, op=self.experiment_options.two_qubit_gate + ), + GateDistribution(prob=1 - adjusted_2q_density, op=GenericClifford(1)), + ] def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: """Sample layers of mirror RB using the provided distribution and user options. @@ -274,6 +281,8 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if not self._backend: raise QiskitError("A backend must be provided for circuit generation.") + self._set_distribution_options() + # Sequence of lengths to sample for if not self.experiment_options.full_sampling: seqlens = (max(self.experiment_options.lengths),) @@ -282,11 +291,11 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: if self.experiment_options.pauli_randomize: pauli_sampler = SingleQubitSampler(seed=self.experiment_options.seed) - pauli_sampler.gate_distribution = [GateDistribution(prob=1, nq=1, op="pauli")] + pauli_sampler.gate_distribution = [GateDistribution(prob=1, op=GenericPauli(1))] if self.experiment_options.start_end_clifford: clifford_sampler = SingleQubitSampler(seed=self.experiment_options.seed) - clifford_sampler.gate_distribution = [GateDistribution(prob=1, nq=1, op="clifford")] + clifford_sampler.gate_distribution = [GateDistribution(prob=1, op=GenericClifford(1))] sequences = [] @@ -296,7 +305,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Sample the first half of the mirror layers layers = list( - self.distribution( + self._distribution( qubits=range(self.num_qubits), length=seqlen // 2, ) @@ -402,8 +411,8 @@ def _to_instruction( return elem() def _inverse_layer( - self, layer: List[Tuple[Tuple[int, ...], GateTypeT]] - ) -> List[Tuple[Tuple[int, ...], GateTypeT]]: + self, layer: List[Tuple[GateInstruction, ...]] + ) -> List[Tuple[GateInstruction, ...]]: """Generates the inverse layer of a Clifford mirror RB layer by inverting the single-qubit Cliffords and keeping the two-qubit gate identical. See :class:`.BaseSampler` for the format of the layer. diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index a5153ee92b..4268d388ac 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -23,11 +23,25 @@ import numpy as np from qiskit.circuit import Instruction +from qiskit.circuit.gate import Gate from qiskit.exceptions import QiskitError +from qiskit.transpiler import CouplingMap from .clifford_utils import CliffordUtils, _CLIFF_SINGLE_GATE_MAP_1Q -GateTypeT = TypeVar("GateTypeT", str, int, Instruction) + +class GenericClifford(Gate): + """Representation of a generic multi-qubit Clifford gate for sampling.""" + + def __init__(self, n_qubits): + super().__init__("generic_clifford", n_qubits, []) + + +class GenericPauli(Gate): + """Representation of a generic multi-qubit Pauli gate for sampling.""" + + def __init__(self, n_qubits): + super().__init__("generic_pauli", n_qubits, []) class GateInstruction(NamedTuple): @@ -36,18 +50,16 @@ class GateInstruction(NamedTuple): # the list of qubits to apply the operation on qargs: tuple # the operation to apply - op: GateTypeT + op: Instruction class GateDistribution(NamedTuple): """Named tuple class for sampler input distribution.""" - # probability of the instruction to be sampled + # probability with which to sample the instruction prob: float - # the number of qubits the instruction applies to - nq: int - # the instruction, can be Instructions or the special keywords "clifford", "pauli" - op: Union[Instruction, str] + # the instruction to include in sampling + op: Instruction class BaseSampler(ABC): @@ -57,8 +69,6 @@ class BaseSampler(ABC): def __init__( self, - gate_distribution=None, - coupling_map: Optional[List[List[int]]] = None, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, ) -> None: """Initializes the sampler. @@ -67,18 +77,7 @@ def __init__( seed: Seed for random generation. gate_distribution: The gate distribution for sampling. """ - self._gate_distribution = gate_distribution - self._coupling_map = coupling_map - self.seed = default_rng(seed) - - @property - def coupling_map(self) -> Optional[List[List[int]]]: - """The coupling map of the system to sample over.""" - return self._coupling_map - - @coupling_map.setter - def coupling_map(self, coupling_map) -> None: - self._coupling_map = coupling_map + self.seed = seed @property def seed(self) -> Union[int, SeedSequence, BitGenerator, Generator]: @@ -92,14 +91,12 @@ def seed(self, seed) -> None: @property def gate_distribution(self) -> List[GateDistribution]: """The gate distribution for sampling. The distribution is a list of - ``GateDistribution`` named tuples with field names ``(prob, nq, op)``, - where the probabilites must sum to 1 and ``nq`` is the number of qubits - the ``op`` applies to. Gates can be ``Instruction`` or the special - keywords "clifford", "pauli". An example distribution for the edge grab - sampler might be + ``GateDistribution`` named tuples with field names ``(prob, op)``, where + the probabilites must sum to 1 and ``op`` is the Instruction instance to + be sampled. An example distribution for the edge grab sampler is .. parsed-literal:: - [(0.8, 1, "clifford"), (0.2, 2, CXGate())] + [(0.8, GenericClifford(1)), (0.2, CXGate())] """ return self._gate_distribution @@ -108,60 +105,71 @@ def gate_distribution(self, dist: List[GateDistribution]) -> None: """Set the distribution of gates used in the sampler. Args: - dist: A list of tuples with format ``(probability, width of gate, gate)``. + dist: A list of tuples with format ``(probability, gate)``. """ - if not isinstance(dist, List): - raise TypeError("The gate distribution should be a list.") # cast to named tuple - dist = [GateDistribution(*elem) for elem in dist] + try: + dist = [GateDistribution(*elem) for elem in dist] + except TypeError as exc: + raise TypeError( + "The gate distribution should be a sequence of (prob, op) tuples." + ) from exc if sum(list(zip(*dist))[0]) != 1: raise QiskitError("Gate distribution probabilities must sum to 1.") for gate in dist: - if gate.op not in ["clifford", "pauli"] and not isinstance(gate.op, Instruction): + if not isinstance(gate.op, Instruction): raise TypeError( - "The only allowed gates in the distribution are 'clifford', 'pauli', " - "and Instruction instances." + "The only allowed gates in the distribution are Instruction instances." ) self._gate_distribution = dist - def _probs_by_gate_size(self) -> Dict: + def _probs_by_gate_size(self, distribution: Sequence[GateDistribution]) -> Dict: """Return a list of gates and their probabilities indexed by the size of the gate.""" - if not self._gate_distribution: - raise QiskitError("Gate distribution must be set before sampling.") + gate_probs = defaultdict(list) - for gate in self.gate_distribution: - if gate.op == "clifford" and gate.nq == 1: - gateset = list(range(CliffordUtils.NUM_CLIFFORD_1_QUBIT)) - probs = [ - gate.prob / CliffordUtils.NUM_CLIFFORD_1_QUBIT - ] * CliffordUtils.NUM_CLIFFORD_1_QUBIT - elif gate.op == "pauli" and gate.nq == 1: - gateset = [ - _CLIFF_SINGLE_GATE_MAP_1Q[("id", (0,))], - _CLIFF_SINGLE_GATE_MAP_1Q[("x", (0,))], - _CLIFF_SINGLE_GATE_MAP_1Q[("y", (0,))], - _CLIFF_SINGLE_GATE_MAP_1Q[("z", (0,))], - ] - probs = [gate.prob / len(gateset)] * len(gateset) - elif gate.op == "clifford" and gate.nq == 2: - gateset = list(range(CliffordUtils.NUM_CLIFFORD_2_QUBIT)) - probs = [ - gate.prob / CliffordUtils.NUM_CLIFFORD_2_QUBIT - ] * CliffordUtils.NUM_CLIFFORD_2_QUBIT + for gate in distribution: + if gate.op.name == "generic_clifford": + if gate.op.num_qubits == 1: + gateset = list(range(CliffordUtils.NUM_CLIFFORD_1_QUBIT)) + probs = [ + gate.prob / CliffordUtils.NUM_CLIFFORD_1_QUBIT + ] * CliffordUtils.NUM_CLIFFORD_1_QUBIT + elif gate.op.num_qubits == 2: + gateset = list(range(CliffordUtils.NUM_CLIFFORD_2_QUBIT)) + probs = [ + gate.prob / CliffordUtils.NUM_CLIFFORD_2_QUBIT + ] * CliffordUtils.NUM_CLIFFORD_2_QUBIT + else: + raise QiskitError( + "Generic Cliffords larger than 2-qubit are not currently supported." + ) + elif gate.op.name == "generic_pauli": + if gate.op.num_qubits == 1: + gateset = [ + _CLIFF_SINGLE_GATE_MAP_1Q[("id", (0,))], + _CLIFF_SINGLE_GATE_MAP_1Q[("x", (0,))], + _CLIFF_SINGLE_GATE_MAP_1Q[("y", (0,))], + _CLIFF_SINGLE_GATE_MAP_1Q[("z", (0,))], + ] + probs = [gate.prob / len(gateset)] * len(gateset) + else: + raise QiskitError( + "Generic Paulis larger than 1-qubit are not currently supported." + ) else: gateset = [gate.op] probs = [gate.prob] - if len(gate_probs[gate.nq]) == 0: - gate_probs[gate.nq] = [gateset, probs] + if len(gate_probs[gate.op.num_qubits]) == 0: + gate_probs[gate.op.num_qubits] = [gateset, probs] else: - gate_probs[gate.nq][0].extend(gateset) - gate_probs[gate.nq][1].extend(probs) + gate_probs[gate.op.num_qubits][0].extend(gateset) + gate_probs[gate.op.num_qubits][1].extend(probs) return gate_probs @abstractmethod - def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[GateInstruction]]: + def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[GateInstruction, ...]]: """Samplers should define this method such that it returns sampled layers given the input parameters. Each layer is represented by a list of ``GateInstruction`` namedtuples, where ``GateInstruction.op`` is the gate to be @@ -175,7 +183,7 @@ def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[GateInstruct Returns: A list of layers consisting of GateInstruction objects. """ - return None + raise NotImplementedError class SingleQubitSampler(BaseSampler): @@ -192,7 +200,6 @@ def __call__( Args: qubits: A sequence of qubits to generate layers for. length: The length of the sequence to output. - seed: Seed for random generation. Returns: A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` @@ -203,14 +210,14 @@ def __call__( by integers for speed. """ - gateset = self._probs_by_gate_size() + gateset = self._probs_by_gate_size(self._gate_distribution) if not math.isclose(sum(gateset[1][1]), 1): raise QiskitError( "The distribution for SingleQubitSampler should be all single qubit gates." ) samples = self._rng.choice( - np.array(gateset[1][0], dtype=Instruction), + np.array(gateset[1][0], dtype=object), size=(length, len(qubits)), p=gateset[1][1], ) @@ -250,6 +257,32 @@ class EdgeGrabSampler(BaseSampler): """ + def __init__( + self, + gate_distribution=None, + coupling_map: Optional[Union[List[List[int]], CouplingMap]] = None, + seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, + ) -> None: + """Initializes the sampler. + + Args: + seed: Seed for random generation. + gate_distribution: The gate distribution for sampling. + coupling_map: The coupling map between the qubits. + """ + super().__init__(seed) + self._gate_distribution = gate_distribution + self._coupling_map = coupling_map + + @property + def coupling_map(self): + """The coupling map of the system to sample over.""" + return self._coupling_map + + @coupling_map.setter + def coupling_map(self, coupling_map): + self._coupling_map = coupling_map + def __call__( self, qubits: Sequence, @@ -260,20 +293,20 @@ def __call__( Args: qubits: A sequence of qubits to generate layers for. length: The length of the sequence to output. - seed: Seed for random generation. Raises: Warning: If the coupling map has no connectivity or ``two_qubit_gate_density`` is too high. TypeError: If invalid gate set(s) are specified. + QiskitError: If the coupling map is invalid. Returns: - A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` layers over - ``num_qubits`` qubits. Each layer is represented by a list of tuples which - are in the format ((one or more qubit indices), gate). Single-qubit - Cliffords are represented by integers for speed. Here's an example with the - default choice of Cliffords for the single-qubit gates and CXs for the - two-qubit gates: + A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` + layers over ``num_qubits`` qubits. Each layer is represented by a + list of ``GateInstruction`` named tuples which are in the format + (qargs, gate). Single-qubit Cliffords are represented by integers + for speed. Here's an example with the default choice of Cliffords + for the single-qubit gates and CXs for the two-qubit gates: .. parsed-literal:: (((1, 2), CXGate()), ((0,), 12), ((3,), 20)) @@ -284,25 +317,27 @@ def __call__( """ num_qubits = len(qubits) - gateset = self._probs_by_gate_size() + gateset = self._probs_by_gate_size(self._gate_distribution) norm1q = sum(gateset[1][1]) norm2q = sum(gateset[2][1]) - two_qubit_gate_density = sum(gateset[2][1]) / (sum(gateset[2][1]) + sum(gateset[1][1])) + if not np.isclose(norm1q + norm2q, 1): + raise TypeError("The edge grab sampler only supports 1- and 2-qubit gates.") + two_qubit_gate_density = norm2q / (norm1q + norm2q) if num_qubits == 1: return [ (GateInstruction((qubits[0],), i),) for i in self._rng.choice( - np.array(gateset[1][0], dtype=Instruction), + np.array(gateset[1][0], dtype=object), p=[i / norm1q for i in gateset[1][1]], size=length, ) ] - if not isinstance(self.coupling_map, List): + if not isinstance(self.coupling_map, List) or isinstance(self.coupling_map, CouplingMap): raise QiskitError("The coupling map must be set correctly before sampling.") layer_list = [] - for _ in list(range(length)): + for _ in range(length): all_edges = self.coupling_map[:] # make copy of coupling map from which we pop edges selected_edges = [] while all_edges: @@ -349,6 +384,7 @@ def __call__( ), ), ) + # remove these qubits from put_1q_gates put_1q_gates.remove(edge[0]) put_1q_gates.remove(edge[1]) diff --git a/test/library/randomized_benchmarking/test_mirror_rb.py b/test/library/randomized_benchmarking/test_mirror_rb.py index 4c07751d5e..b5b4f0dec0 100644 --- a/test/library/randomized_benchmarking/test_mirror_rb.py +++ b/test/library/randomized_benchmarking/test_mirror_rb.py @@ -302,10 +302,7 @@ def test_experiment_config(self): def test_roundtrip_serializable(self): """Test round trip JSON serialization""" - exp = rb.MirrorRB([0], lengths=[10, 20, 30], seed=123) - self.assertRoundTripSerializable(exp, self.json_equiv) - exp = rb.MirrorRB([0], lengths=[10, 20, 30], seed=123) - exp.distribution.gate_distribution = [(0.5, 1, "pauli"), (0.5, 1, "clifford")] + exp = rb.MirrorRB([0], lengths=[10, 20, 30], seed=123, two_qubit_gate=ECRGate()) self.assertRoundTripSerializable(exp, self.json_equiv) def test_analysis_config(self): @@ -336,30 +333,6 @@ def test_backend_with_directed_basis_gates(self): if inst.operation.name == "cx": self.assertEqual(inst.qubits, expected_qubits) - def test_change_distribution_options(self): - """Test that changing the distribution option and then resetting works as expected.""" - - exp = rb.MirrorRB( - physical_qubits=range(4), - two_qubit_gate_density=1, - lengths=[4], - num_samples=1, - backend=self.backend, - seed=self.seed, - ) - - exp.distribution.gate_distribution = [(0.2, 1, "clifford"), (0.8, 2, ECRGate())] - gates = exp.circuits()[0].count_ops() - if "ecr" not in gates or "cx" in gates: - raise QiskitError("Unexpected output gate distribution.") - - exp.distribution = EdgeGrabSampler - - gates = exp.circuits()[0].count_ops() - - if "cx" not in gates or "ecr" in gates: - raise QiskitError("Unexpected output gate distribution.") - @ddt class TestRunMirrorRB(QiskitExperimentsTestCase, RBTestMixin): diff --git a/test/library/randomized_benchmarking/test_sampling_utils.py b/test/library/randomized_benchmarking/test_sampling_utils.py index ffc10970ee..1dc5a7ef99 100644 --- a/test/library/randomized_benchmarking/test_sampling_utils.py +++ b/test/library/randomized_benchmarking/test_sampling_utils.py @@ -21,6 +21,7 @@ from qiskit_experiments.library.randomized_benchmarking.sampling_utils import ( SingleQubitSampler, EdgeGrabSampler, + GenericClifford, ) from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils @@ -33,17 +34,17 @@ class TestSamplingUtils(QiskitExperimentsTestCase): def test_gate_distribution(self): """Test the gate distribution is calculated correctly.""" sampler = SingleQubitSampler(seed=self.seed) - sampler.gate_distribution = [(0.8, 1, "clifford"), (0.2, 2, XGate())] - dist = sampler._probs_by_gate_size() + sampler.gate_distribution = [(0.8, GenericClifford(1)), (0.2, CXGate())] + dist = sampler._probs_by_gate_size(sampler.gate_distribution) self.assertEqual(len(dist[1][0]), 24) self.assertAlmostEqual(sum(dist[1][1]), 0.8) - self.assertEqual(dist[2][0], [XGate()]) + self.assertEqual(dist[2][0], [CXGate()]) self.assertAlmostEqual(sum(dist[2][1]), 0.2) def test_1q_custom_gate(self): """Test that the single qubit sampler works with custom gates.""" sampler = SingleQubitSampler(seed=self.seed) - sampler.gate_distribution = [(1, 1, XGate())] + sampler.gate_distribution = [(1, XGate())] layer = sampler((0,), 3) self.assertEqual( layer, @@ -53,7 +54,7 @@ def test_1q_custom_gate(self): def test_1q_cliffords(self): """Test that the single qubit sampler can generate clifford layers.""" sampler = SingleQubitSampler(seed=self.seed) - sampler.gate_distribution = [(1, 1, "clifford")] + sampler.gate_distribution = [(1, GenericClifford(1))] layer = sampler((0,), 3) for i in layer: self.assertTrue(i[0][1] < CliffordUtils.NUM_CLIFFORD_1_QUBIT and i[0][1] >= 0) @@ -61,7 +62,7 @@ def test_1q_cliffords(self): def test_edgegrab(self): """Test that the edge grab sampler behaves as expected.""" sampler = EdgeGrabSampler(seed=self.seed) - sampler.gate_distribution = [(0.5, 1, "clifford"), (0.5, 2, CXGate())] + sampler.gate_distribution = [(0.5, GenericClifford(1)), (0.5, CXGate())] layer = sampler((0,), 3) for i in layer: self.assertTrue( @@ -73,7 +74,7 @@ def test_edgegrab_all_2q(self): """Test that the edge grab sampler behaves as expected when two qubit density is 1.""" sampler = EdgeGrabSampler(seed=self.seed) - sampler.gate_distribution = [(0, 1, "clifford"), (1, 2, CXGate())] + sampler.gate_distribution = [(0, GenericClifford(1)), (1, CXGate())] sampler.coupling_map = [[k, k + 1] for k in range(9)] layer = sampler(range(10), 3) for i in layer: From d423e588eeb66cb6b51c8b58ca6222c1d5a9d40d Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Mon, 27 Mar 2023 19:24:32 -0400 Subject: [PATCH 51/56] subclass`MirrorRBAnalysis` from `RBAnalysis` also updated test backends to V2. --- docs/manuals/verification/mirror_rb.rst | 19 +- .../mirror_rb_analysis.py | 306 ++---------------- .../mirror_rb_experiment.py | 26 +- .../randomized_benchmarking/sampling_utils.py | 2 +- .../randomized_benchmarking/test_mirror_rb.py | 7 +- 5 files changed, 51 insertions(+), 309 deletions(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index 66d2b375fb..89b09c28cd 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -2,9 +2,10 @@ Mirror Randomized Benchmarking ============================== Mirror randomized benchmarking (mirror RB) is a randomized benchmarking protocol -that is more scalable than standard randomized benchmarking and is suitable for -characterizing crosstalk errors over a large number of qubits in a quantum device. A -randomized Clifford mirror circuit [1]_ consists of: +where layers of gates are sampled from a distribution and then run on a set of +qubits along with their mirror inverses. A randomized Clifford mirror circuit +[1]_, which we will be running in this manual, is a specific type of mirror RB +and consists of: - random n-qubit Clifford layers and their inverses sampled according to some distribution :math:`\Omega` over a layer set :math:`\mathbb{L}`, @@ -15,10 +16,13 @@ randomized Clifford mirror circuit [1]_ consists of: of the circuit. Note that the random n-qubit Clifford layers can be realized with only one-qubit -Cliffords and a two-qubit gate such as CX, which twirl the local errors sufficiently to -produce a useful metric of gate infidelity. This is in contrast to standard RB, which -requires the implementation of n-qubit Cliffords that have much more overhead for large -n. Mirror RB can also be generalized to universal gatesets beyond the Cliffords [2]_. +Cliffords and a two-qubit gate such as CX, which twirl the local errors +sufficiently to produce a useful metric of gate infidelity. This is in contrast +to standard RB, which requires the implementation of n-qubit Cliffords that have +much more overhead for large n. As a result, mirror RB is more scalable than +standard RB and is suitable for characterizing crosstalk errors over a large +number of qubits in a quantum device. Mirror RB can also be generalized to +universal gatesets beyond the Cliffords [2]_. Output metrics -------------- @@ -116,7 +120,6 @@ the experiment: .. jupyter-execute:: - print("Gate error ratio: %s" % expdata_2q.experiment.analysis.options.gate_error_ratio) display(expdata_2q.figure(0)) for result in results_2q: print(result) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index 23ddaf0d5d..4c44912886 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -12,8 +12,7 @@ """ Mirror RB analysis class. """ -from collections import defaultdict -from typing import Dict, List, Sequence, Tuple, Union, Optional, TYPE_CHECKING +from typing import Dict, List, Tuple, Union, TYPE_CHECKING import lmfit from qiskit.exceptions import QiskitError @@ -22,12 +21,12 @@ from scipy.spatial.distance import hamming import qiskit_experiments.curve_analysis as curve -from qiskit_experiments.exceptions import AnalysisError -from qiskit_experiments.framework import AnalysisResultData, ExperimentData -from qiskit_experiments.framework.analysis_result import AnalysisResult +from qiskit_experiments.framework import AnalysisResultData from qiskit_experiments.data_processing.exceptions import DataProcessorError from uncertainties import unumpy as unp # pylint: disable=wrong-import-order +from .rb_analysis import RBAnalysis + if TYPE_CHECKING: from uncertainties import UFloat @@ -35,7 +34,7 @@ QubitGateTuple = Tuple[Tuple[int, ...], str] -class MirrorRBAnalysis(curve.CurveAnalysis): +class MirrorRBAnalysis(RBAnalysis): r"""A class to analyze mirror randomized benchmarking experiment. # section: overview @@ -104,14 +103,6 @@ class MirrorRBAnalysis(curve.CurveAnalysis): """ - def __init__(self): - super().__init__( - models=[lmfit.models.ExpressionModel(expr="a * alpha ** x + b", name="mirror")] - ) - self._gate_counts_per_clifford = None - self._physical_qubits = None - self._num_qubits = None - @classmethod def _default_options(cls): """Default analysis options. @@ -183,14 +174,16 @@ def _generate_fit_guesses( Returns: List of fit options that are passed to the fitter function. """ + user_opt.bounds.set_if_empty(a=(0, 1), alpha=(0, 1), b=(0, 1)) + num_qubits = len(self._physical_qubits) # Initialize guess for baseline and amplitude based on infidelity type - b_guess = 1 / 4**self._num_qubits + b_guess = 1 / 4**num_qubits if self.options.y_axis == "Success Probability": - b_guess = 1 / 2**self._num_qubits + b_guess = 1 / 2**num_qubits - mirror_curve = curve_data.get_subset_of("mirror") + mirror_curve = curve_data.get_subset_of("rb_decay") alpha_mirror = curve.guess.rb_decay(mirror_curve.x, mirror_curve.y, b=b_guess) a_guess = (curve_data.y[0] - b_guess) / (alpha_mirror ** curve_data.x[0]) @@ -246,7 +239,8 @@ def _create_analysis_results( quality: str, **metadata, ) -> List[AnalysisResultData]: - """Create analysis results for important fit parameters. + """Create analysis results for important fit parameters. Besides the + default standard RB parameters, Entanglement Infidelity (EI) is also calculated. Args: fit_data: Fit outcome. @@ -260,66 +254,16 @@ def _create_analysis_results( num_qubits = len(self._physical_qubits) # nrb is calculated for both EPC and EI per the equations in the docstring - ei_nrb = 4**self._num_qubits + ei_nrb = 4**num_qubits ei_scale = (ei_nrb - 1) / ei_nrb - epc_nrb = 2**self._num_qubits - epc_scale = (epc_nrb - 1) / epc_nrb + ei = ei_scale * (1 - fit_data.ufloat_params["alpha"]) - alpha = fit_data.ufloat_params["alpha"] - - # Calculate EPC and EI per the equations in the docstring - epc = epc_scale * (1 - alpha) - ei = ei_scale * (1 - alpha) - - outcomes.append( - AnalysisResultData( - name="EPC", value=epc, chisq=fit_data.reduced_chisq, quality=quality, extra=metadata - ) - ) outcomes.append( AnalysisResultData( name="EI", value=ei, chisq=fit_data.reduced_chisq, quality=quality, extra=metadata ) ) - # Correction for 1Q depolarizing channel if EPGs are provided - if self.options.epg_1_qubit and num_qubits == 2: - epc = _exclude_1q_error( - epc=epc, - qubits=self._physical_qubits, - gate_counts_per_clifford=self._gate_counts_per_clifford, - extra_analyses=self.options.epg_1_qubit, - ) - outcomes.append( - AnalysisResultData( - name="EPC_corrected", - value=epc, - chisq=fit_data.reduced_chisq, - quality=quality, - extra=metadata, - ) - ) - - # Calculate EPG - if self._gate_counts_per_clifford is not None and self.options.gate_error_ratio: - epg_dict = _calculate_epg( - epc=epc, - qubits=self._physical_qubits, - gate_error_ratio=self.options.gate_error_ratio, - gate_counts_per_clifford=self._gate_counts_per_clifford, - ) - if epg_dict: - for gate, epg_val in epg_dict.items(): - outcomes.append( - AnalysisResultData( - name=f"EPG_{gate}", - value=epg_val, - chisq=fit_data.reduced_chisq, - quality=quality, - extra=metadata, - ) - ) - return outcomes def _run_data_processing( @@ -401,7 +345,8 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. # Arrays to store the y-axis data and uncertainties y_data = [] y_data_unc = [] - target_bs = "0" * self._num_qubits + num_qubits = len(self._physical_qubits) + target_bs = "0" * num_qubits for circ_result in raw_data: # If there is no inverting Pauli layer at the end of the circuit, get the target bitstring @@ -409,7 +354,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. target_bs = circ_result["metadata"]["target"] # h[k] = proportion of shots that are Hamming distance k away from target bitstring - hamming_dists = np.zeros(self._num_qubits + 1) + hamming_dists = np.zeros(num_qubits + 1) for bitstring, count in circ_result["counts"].items(): # Compute success probability success_prob = 0.0 @@ -427,7 +372,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. # Compute hamming distance proportions target_bs_to_list = [int(char) for char in target_bs] actual_bs_to_list = [int(char) for char in bitstring] - k = int(round(hamming(target_bs_to_list, actual_bs_to_list) * self._num_qubits)) + k = int(round(hamming(target_bs_to_list, actual_bs_to_list) * num_qubits)) hamming_dists[k] += count / circ_result.get( "shots", sum(circ_result["counts"].values()) ) @@ -438,7 +383,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. # Compute adjusted success probability and standard deviation adjusted_success_prob = 0.0 adjusted_success_prob_unc = 0.0 - for k in range(self._num_qubits + 1): + for k in range(num_qubits + 1): adjusted_success_prob += (-0.5) ** k * hamming_dists[k] adjusted_success_prob_unc += (0.5) ** k * hamming_dist_unc[k] ** 2 adjusted_success_prob_unc = np.sqrt(adjusted_success_prob_unc) @@ -451,7 +396,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. y_data_unc.append(adjusted_success_prob_unc) # Compute effective polarization and standard deviation (arXiv:2112.09853v1) - pol_factor = 4**self._num_qubits + pol_factor = 4**num_qubits pol = pol_factor / (pol_factor - 1) * adjusted_success_prob - 1 / (pol_factor - 1) pol_unc = np.sqrt(pol_factor / (pol_factor - 1)) * adjusted_success_prob_unc circ_result["metadata"]["polarization"] = pol @@ -461,214 +406,3 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. y_data_unc.append(pol_unc) return unp.uarray(y_data, y_data_unc) - - def _initialize( - self, - experiment_data: ExperimentData, - ): - """Initialize curve analysis with experiment data. - - This method is called ahead of other processing. - - Args: - experiment_data: Experiment data to analyze. - - Raises: - AnalysisError: When circuit metadata for ops count is missing. - """ - super()._initialize(experiment_data) - - if self.options.gate_error_ratio is not None: - # If gate error ratio is not False, EPG analysis is enabled. - # Here analysis prepares gate error ratio and gate counts for EPC to EPG conversion. - - # If gate count dictionary is not set it will compute counts from circuit metadata. - avg_gpc = defaultdict(float) - n_circs = len(experiment_data.data()) - for circ_result in experiment_data.data(): - try: - count_ops = circ_result["metadata"]["count_ops"] - except KeyError as ex: - raise AnalysisError( - "'count_ops' key is not found in the circuit metadata. " - "This analysis cannot compute error per gates. " - "Please disable this with 'gate_error_ratio=False'." - ) from ex - nclif = circ_result["metadata"]["xval"] - for (qinds, gate), count in count_ops: - formatted_key = tuple(sorted(qinds)), gate - avg_gpc[formatted_key] += count / nclif / n_circs - self._gate_counts_per_clifford = dict(avg_gpc) - - if self.options.gate_error_ratio == "default": - # Gate error dict is computed for gates appearing in counts dictionary - # Error ratio among gates is determined based on the predefined lookup table. - # This is not always accurate for every quantum backends. - gate_error_ratio = {} - for qinds, gate in self._gate_counts_per_clifford.keys(): - if set(qinds) != set(experiment_data.metadata["physical_qubits"]): - continue - gate_error_ratio[gate] = _lookup_epg_ratio(gate, len(qinds)) - self.set_options(gate_error_ratio=gate_error_ratio) - - # Get qubit number - self._physical_qubits = experiment_data.metadata["physical_qubits"] - self._num_qubits = len(experiment_data.metadata["physical_qubits"]) - - -def _lookup_epg_ratio(gate: str, n_qubits: int) -> Union[None, int]: - """A helper method to look-up preset gate error ratio for given basis gate name. - - In the table the error ratio is defined based on the count of - typical assembly gate in the gate decomposition. - For example, "u3" gate can be decomposed into two "sx" gates. - In this case, the ratio of "u3" gate error becomes 2. - - .. note:: - - This table is not aware of the actual waveform played on the hardware, - and the returned error ratio is just a guess. - To be precise, user can always set "gate_error_ratio" option of the experiment. - - Args: - gate: Name of the gate. - n_qubits: Number of qubits measured in the RB experiments. - - Returns: - Corresponding error ratio. - - Raises: - QiskitError: When number of qubit is more than three. - """ - - # Gate count in (X, SX)-based decomposition. VZ gate contribution is ignored. - # Amplitude or duration modulated pulse implementation is not considered. - standard_1q_ratio = { - "u1": 0.0, - "u2": 1.0, - "u3": 2.0, - "u": 2.0, - "p": 0.0, - "x": 1.0, - "y": 1.0, - "z": 0.0, - "t": 0.0, - "tdg": 0.0, - "s": 0.0, - "sdg": 0.0, - "sx": 1.0, - "sxdg": 1.0, - "rx": 2.0, - "ry": 2.0, - "rz": 0.0, - "id": 0.0, - "h": 1.0, - } - - # Gate count in (CX, CSX)-based decomposition, 1q gate contribution is ignored. - # Amplitude or duration modulated pulse implementation is not considered. - standard_2q_ratio = { - "swap": 3.0, - "rxx": 2.0, - "rzz": 2.0, - "cx": 1.0, - "cy": 1.0, - "cz": 1.0, - "ch": 1.0, - "crx": 2.0, - "cry": 2.0, - "crz": 2.0, - "csx": 1.0, - "cu1": 2.0, - "cp": 2.0, - "cu": 2.0, - "cu3": 2.0, - } - - if n_qubits == 1: - return standard_1q_ratio.get(gate, None) - - if n_qubits == 2: - return standard_2q_ratio.get(gate, None) - - raise QiskitError( - f"Standard gate error ratio for {n_qubits} qubit RB is not provided. " - "Please explicitly set 'gate_error_ratio' option of the experiment." - ) - - -def _calculate_epg( - epc: Union[float, "UFloat"], - qubits: Sequence[int], - gate_error_ratio: Dict[str, float], - gate_counts_per_clifford: Dict[QubitGateTuple, float], -) -> Dict[str, Union[float, "UFloat"]]: - """A helper mehtod to compute EPGs of basis gates from fit EPC value. - - Args: - epc: Error per Clifford. - qubits: List of qubits used in the experiment. - gate_error_ratio: A dictionary of assumed ratio of errors among basis gates. - gate_counts_per_clifford: Basis gate counts per Clifford gate. - - Returns: - A dictionary of gate errors keyed on the gate name. - """ - norm = 0 - for gate, r_epg in gate_error_ratio.items(): - formatted_key = tuple(sorted(qubits)), gate - norm += r_epg * gate_counts_per_clifford.get(formatted_key, 0.0) - - epgs = {} - for gate, r_epg in gate_error_ratio.items(): - epgs[gate] = r_epg * epc / norm - return epgs - - -def _exclude_1q_error( - epc: Union[float, "UFloat"], - qubits: Tuple[int, int], - gate_counts_per_clifford: Dict[QubitGateTuple, float], - extra_analyses: Optional[List[AnalysisResult]], -) -> Union[float, "UFloat"]: - """A helper method to exclude contribution of single qubit gates from 2Q EPC. - - Args: - epc: EPC from 2Q RB experiment. - qubits: Index of two qubits used for 2Q RB experiment. - gate_counts_per_clifford: Basis gate counts per 2Q Clifford gate. - extra_analyses: Analysis results containing depolarizing parameters of 1Q RB experiments. - - Returns: - Corrected 2Q EPC. - """ - # Extract EPC of non-measured qubits from previous experiments - epg_1qs = {} - for analyis_data in extra_analyses: - if ( - not analyis_data.name.startswith("EPG_") - or len(analyis_data.device_components) > 1 - or not str(analyis_data.device_components[0]).startswith("Q") - ): - continue - qind = analyis_data.device_components[0]._index - gate = analyis_data.name[4:] - formatted_key = (qind,), gate - epg_1qs[formatted_key] = analyis_data.value - - if not epg_1qs: - return epc - - # Convert 2Q EPC into depolarizing parameter alpha - alpha_c_2q = 1 - 4 / 3 * epc - - # Estimate composite alpha of 1Q channels - alpha_i = [1.0, 1.0] - for q_gate_tup, epg in epg_1qs.items(): - n_gate = gate_counts_per_clifford.get(q_gate_tup, 0.0) - aind = qubits.index(q_gate_tup[0][0]) - alpha_i[aind] *= (1 - 2 * epg) ** n_gate - alpha_c_1q = 1 / 5 * (alpha_i[0] + alpha_i[1] + 3 * alpha_i[0] * alpha_i[1]) - - # Corrected 2Q channel EPC - return 3 / 4 * (1 - (alpha_c_2q / alpha_c_1q)) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 7acca5d150..2c4f651d1e 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -52,18 +52,23 @@ class MirrorRB(StandardRB): # section: overview Mirror randomized benchmarking (mirror RB) estimates the average error rate of - quantum gates using gate layers sampled from a distribution that are then + quantum gates using layers of gates sampled from a distribution that are then inverted in the second half of the circuit. The default mirror RB experiment generates circuits of layers of Cliffords, consisting of single-qubit Cliffords and a two-qubit gate such as CX, interleaved with layers of Pauli gates and capped at the start and end by a layer of single-qubit Cliffords. The second half of the Clifford layers are the - inverses of the first half of Clifford layers. After running the circuits on a - backend, various quantities (success probability, adjusted success probability, - and effective polarization) are computed and used to fit an exponential decay - curve and calculate the EPC (error per Clifford, also referred to as the average - gate infidelity) and entanglement infidelity (see references for more info). + inverses of the first half of Clifford layers. This algorithm has a lot less + overhead than the standard randomized benchmarking, which requires + n-qubit Clifford gates, and so it can be used for benchmarking gates on + 10s of or even 100+ noisy qubits. + + After running the circuits on a backend, various quantities (success + probability, adjusted success probability, and effective polarization) + are computed and used to fit an exponential decay curve and calculate + the EPC (error per Clifford, also referred to as the average gate + infidelity) and entanglement infidelity (see references for more info). # section: analysis_ref :class:`MirrorRBAnalysis` @@ -80,6 +85,7 @@ class MirrorRB(StandardRB): sampler_map = {"edge_grab": EdgeGrabSampler, "single_qubit": SingleQubitSampler} + # pylint: disable=dangerous-default-value def __init__( self, physical_qubits: Sequence[int], @@ -89,9 +95,9 @@ def __init__( sampling_algorithm: str = "edge_grab", two_qubit_gate_density: float = 0.2, two_qubit_gate: Instruction = CXGate(), - sampler_opts: dict = {}, - backend: Optional[Backend] = None, num_samples: int = 3, + sampler_opts: Optional[dict] = {}, + backend: Optional[Backend] = None, seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None, full_sampling: bool = False, inverting_pauli_layer: bool = False, @@ -114,9 +120,9 @@ def __init__( two_qubit_gate: The two-qubit gate to use. Defaults to :class:`~qiskit.circuit.library.CXGate`. Only has effect if the default sampler :class:`.EdgeGrabSampler` is used. - sampler_opts: Dictionary of keyword arguments to pass to the sampler. - backend: The backend to run the experiment on. num_samples: Number of samples to generate for each sequence length. + sampler_opts: Optional dictionary of keyword arguments to pass to the sampler. + backend: Optional, the backend to run the experiment on. seed: Optional, seed used to initialize ``numpy.random.default_rng``. when generating circuits. The ``default_rng`` will be initialized with this seed value every time :meth:`circuits` is called. diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 4268d388ac..fb8441790b 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -16,7 +16,7 @@ import warnings import math from abc import ABC, abstractmethod -from typing import Optional, Union, List, Tuple, Sequence, TypeVar, NamedTuple, Dict +from typing import Optional, Union, List, Tuple, Sequence, NamedTuple, Dict from collections import defaultdict from numpy.random import Generator, default_rng, BitGenerator, SeedSequence diff --git a/test/library/randomized_benchmarking/test_mirror_rb.py b/test/library/randomized_benchmarking/test_mirror_rb.py index b5b4f0dec0..0fa9ca6ab5 100644 --- a/test/library/randomized_benchmarking/test_mirror_rb.py +++ b/test/library/randomized_benchmarking/test_mirror_rb.py @@ -20,7 +20,7 @@ from qiskit.circuit.library import CXGate, ECRGate from qiskit.exceptions import QiskitError -from qiskit.providers.fake_provider import FakeManilaV2, FakeParis +from qiskit.providers.fake_provider import FakeManilaV2 from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler import Layout, PassManager, CouplingMap from qiskit.transpiler.exceptions import TranspilerError @@ -34,7 +34,6 @@ from qiskit_experiments.library.randomized_benchmarking.clifford_utils import ( compute_target_bitstring, ) -from qiskit_experiments.library.randomized_benchmarking.sampling_utils import EdgeGrabSampler class NonlocalCXDepError(TransformationPass): @@ -135,7 +134,7 @@ class TestMirrorRB(QiskitExperimentsTestCase, RBTestMixin): def setUp(self): """Setup the tests.""" super().setUp() - self.backend = FakeParis() + self.backend = FakeManilaV2() self.basis_gates = ["sx", "rz", "cx"] @@ -375,7 +374,7 @@ def setUp(self): self.backend = AerSimulator( noise_model=noise_model, seed_simulator=123, - coupling_map=AerSimulator.from_backend(FakeParis()).configuration().coupling_map, + coupling_map=AerSimulator.from_backend(FakeManilaV2()).configuration().coupling_map, ) def test_single_qubit(self): From b71d098ce48c683e3c8a8a078f6f355e3be403a9 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Mon, 27 Mar 2023 20:02:30 -0400 Subject: [PATCH 52/56] change y-axis option to `analyzed_quantity` --- docs/manuals/verification/mirror_rb.rst | 16 ++++++++-------- .../mirror_rb_analysis.py | 18 +++++++++--------- .../randomized_benchmarking/sampling_utils.py | 11 ++++++++--- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index 89b09c28cd..9c1a9bfa55 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -124,12 +124,12 @@ the experiment: for result in results_2q: print(result) -Selecting :math:`y`-axis values +Selecting the analyzed quantity ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can set what you want to use as the :math:`y`-axis metric for fitting by setting -the ``y-axis`` analysis option. Here's an example of plotting the success probability -instead of the default: +You can set what you want to use as the metric for fitting by setting the +``analyzed_quantity`` analysis option. Here's an example of plotting the success +probability instead of the default: .. jupyter-execute:: @@ -140,8 +140,8 @@ instead of the default: exp = MirrorRB(qubits, lengths, backend=backend, num_samples=num_samples, seed=seed) - # select y-axis, can also be "Adjusted Success Probability" or "Effective Polarization" - exp.analysis.set_options(y_axis="Success Probability") + # select analyzed_quantity, can also be "Adjusted Success Probability" or "Effective Polarization" + exp.analysis.set_options(analyzed_quantity="Success Probability") # y-axis label must be set separately exp.analysis.options.plotter.set_figure_options( @@ -186,7 +186,7 @@ between Cliffords and single-qubit Cliffords at the start and end: num_samples=1) exp.circuits()[0].decompose().draw("mpl") -And now with the intermediate Pauli layers turned off and the inverting Pauli layer added at the end: +And now with the start and end Clifford layers turned off and the inverting Pauli layer added at the end: .. jupyter-execute:: @@ -204,7 +204,7 @@ Another important option is ``two_qubit_gate_density`` (default ``0.2``). This i expected fraction of two-qubit gates in the circuit, not accounting for the optional constant number of Clifford and Pauli layers at the start and end. This means that given the same ``two_qubit_gate_density``, if ``pauli_randomize`` is off, the concentration of -CX gates in the Clifford layers will be halved so that the overall density doesn't +two-qubit gates in the Clifford layers will be halved so that the overall density doesn't change. We'll demonstrate this by first leaving ``pauli_randomize`` on: .. jupyter-execute:: diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index 4c44912886..ba06d07b54 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -108,7 +108,7 @@ def _default_options(cls): """Default analysis options. Analysis Options: - y_axis (str): Set the metric to plot on the y-axis. Must be one of + analyzed_quantity (str): Set the metric to plot on the y-axis. Must be one of "Effective Polarization" (default), "Success Probability", or "Adjusted Success Probability". gate_error_ratio (Optional[Dict[str, float]]): A dictionary with gate name keys @@ -143,19 +143,19 @@ def _default_options(cls): # By default, effective polarization is plotted (see arXiv:2112.09853). We can # also plot success probability or adjusted success probability (see PyGSTi). # Do this by setting options to "Success Probability" or "Adjusted Success Probability" - default_options.y_axis = "Effective Polarization" + default_options.analyzed_quantity = "Effective Polarization" return default_options def set_options(self, **fields): - if "y_axis" in fields: - if fields["y_axis"] not in [ + if "analyzed_quantity" in fields: + if fields["analyzed_quantity"] not in [ "Success Probability", "Adjusted Success Probability", "Effective Polarization", ]: raise QiskitError( - 'y_axis must be one of "Success Probability", "Adjusted Success Probability", ' + 'analyzed_quantity must be one of "Success Probability", "Adjusted Success Probability", ' 'or "Effective Polarization"' ) super().set_options(**fields) @@ -180,7 +180,7 @@ def _generate_fit_guesses( # Initialize guess for baseline and amplitude based on infidelity type b_guess = 1 / 4**num_qubits - if self.options.y_axis == "Success Probability": + if self.options.analyzed_quantity == "Success Probability": b_guess = 1 / 2**num_qubits mirror_curve = curve_data.get_subset_of("rb_decay") @@ -363,7 +363,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. "shots", sum(circ_result["counts"].values()) ) success_prob_unc = np.sqrt(success_prob * (1 - success_prob)) - if self.options.y_axis == "Success Probability": + if self.options.analyzed_quantity == "Success Probability": y_data.append(success_prob) y_data_unc.append(success_prob_unc) circ_result["metadata"]["success_probability"] = success_prob @@ -391,7 +391,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. circ_result["metadata"][ "adjusted_success_probability_stddev" ] = adjusted_success_prob_unc - if self.options.y_axis == "Adjusted Success Probability": + if self.options.analyzed_quantity == "Adjusted Success Probability": y_data.append(adjusted_success_prob) y_data_unc.append(adjusted_success_prob_unc) @@ -401,7 +401,7 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. pol_unc = np.sqrt(pol_factor / (pol_factor - 1)) * adjusted_success_prob_unc circ_result["metadata"]["polarization"] = pol circ_result["metadata"]["polarization_uncertainty"] = pol_unc - if self.options.y_axis == "Effective Polarization": + if self.options.analyzed_quantity == "Effective Polarization": y_data.append(pol) y_data_unc.append(pol_unc) diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index fb8441790b..66baafa0e8 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -318,10 +318,15 @@ def __call__( """ num_qubits = len(qubits) gateset = self._probs_by_gate_size(self._gate_distribution) - norm1q = sum(gateset[1][1]) - norm2q = sum(gateset[2][1]) + try: + norm1q = sum(gateset[1][1]) + norm2q = sum(gateset[2][1]) + except KeyError as exc: + raise QiskitError( + "The edge grab sampler requires 1-qubit and 2-qubit gates to be specified." + ) from exc if not np.isclose(norm1q + norm2q, 1): - raise TypeError("The edge grab sampler only supports 1- and 2-qubit gates.") + raise QiskitError("The edge grab sampler only supports 1- and 2-qubit gates.") two_qubit_gate_density = norm2q / (norm1q + norm2q) if num_qubits == 1: return [ From 0510478d09d20fa75268aa2fb2776cd71ea91d4a Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Mon, 27 Mar 2023 21:47:30 -0400 Subject: [PATCH 53/56] changed to `CouplingMap` type and added validation Co-authored-by: Naoki Kanazawa --- .../mirror_rb_experiment.py | 30 ++++++------------- .../randomized_benchmarking/sampling_utils.py | 19 +++++++----- .../randomized_benchmarking/test_mirror_rb.py | 2 +- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 2c4f651d1e..19680cfd75 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -24,7 +24,8 @@ from qiskit.providers.backend import Backend from qiskit.providers.options import Options from qiskit.exceptions import QiskitError -from qiskit.circuit.library import CXGate, CYGate, CZGate, ECRGate, SwapGate, iSwapGate +from qiskit.transpiler import CouplingMap +from qiskit.circuit.library import CXGate, CYGate, CZGate, ECRGate, SwapGate from .standard_rb import StandardRB, SequenceElementType from .mirror_rb_analysis import MirrorRBAnalysis @@ -43,7 +44,7 @@ ) # two qubit gates that are their own inverse -_self_adjoint_gates = [CXGate, CYGate, CZGate, ECRGate, SwapGate, iSwapGate] +_self_adjoint_gates = [CXGate, CYGate, CZGate, ECRGate, SwapGate] class MirrorRB(StandardRB): @@ -140,9 +141,6 @@ def __init__( if not all(length % 2 == 0 for length in lengths): raise QiskitError("All lengths must be even") - if two_qubit_gate_density < 0 or two_qubit_gate_density > 1: - raise QiskitError("Two-qubit gate density must be between 0 and 1.") - super().__init__( physical_qubits, lengths, @@ -197,6 +195,7 @@ def _default_experiment_options(cls) -> Options: sampler_opts={}, inverting_pauli_layer=False, ) + options.set_validator(field="two_qubit_gate_density", validator_value=(0, 1)) return options @@ -228,17 +227,11 @@ def _set_distribution_options(self): # get backend coupling map and create coupling map for physical qubits converted # to qubits 0, 1...n if self.backend and self._backend_data.coupling_map: - coupling_map = self._backend_data.coupling_map + coupling_map = CouplingMap(self._backend_data.coupling_map) else: - coupling_map = list(itertools.permutations(range(max(self.physical_qubits) + 1), 2)) - qmap = {self.physical_qubits[i]: i for i in range(len(self.physical_qubits))} - experiment_coupling_map = [] - - for edge in coupling_map: - if edge[0] in self.physical_qubits and edge[1] in self.physical_qubits: - experiment_coupling_map.append((qmap[edge[0]], qmap[edge[1]])) + coupling_map = CouplingMap.from_full(len(self.physical_qubits)) - self._distribution.coupling_map = experiment_coupling_map + self._distribution.coupling_map = coupling_map.reduce(self.physical_qubits) # Adjust the density based on whether the pauli layers are in if self.experiment_options.pauli_randomize: @@ -336,14 +329,11 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Add start and end cliffords if set by user if self.experiment_options.start_end_clifford: - cseq = [] clifford_layers = clifford_sampler(range(self.num_qubits), length=1) - cseq.append(clifford_layers[0]) - cseq.extend(seq) - cseq.append(self._inverse_layer(clifford_layers[0])) + seq.insert(0, clifford_layers[0]) + seq.append(self._inverse_layer(clifford_layers[0])) if not self.experiment_options.full_sampling: build_seq_lengths = [length + 2 for length in build_seq_lengths] - seq = cseq if self.experiment_options.full_sampling: sequences.append(seq) @@ -381,8 +371,6 @@ def _sequences_to_circuits( circ.append(Barrier(self.num_qubits), circ.qubits) circ.metadata = { "xval": self.experiment_options.lengths[i % len(self.experiment_options.lengths)], - "group": "Clifford", - "physical_qubits": self.physical_qubits, "target": compute_target_bitstring(circ_target), "inverting_pauli_layer": self.experiment_options.inverting_pauli_layer, } diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 66baafa0e8..2bb0a4e4ee 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -272,16 +272,19 @@ def __init__( """ super().__init__(seed) self._gate_distribution = gate_distribution - self._coupling_map = coupling_map + self.coupling_map = coupling_map @property - def coupling_map(self): + def coupling_map(self) -> CouplingMap: """The coupling map of the system to sample over.""" return self._coupling_map @coupling_map.setter - def coupling_map(self, coupling_map): - self._coupling_map = coupling_map + def coupling_map(self, coupling_map: Union[List[List[int]], CouplingMap]) -> None: + try: + self._coupling_map = CouplingMap(coupling_map) + except (ValueError, TypeError) as exc: + raise TypeError("Invalid coupling map provided.") from exc def __call__( self, @@ -338,12 +341,12 @@ def __call__( ) ] - if not isinstance(self.coupling_map, List) or isinstance(self.coupling_map, CouplingMap): - raise QiskitError("The coupling map must be set correctly before sampling.") - layer_list = [] + for _ in range(length): - all_edges = self.coupling_map[:] # make copy of coupling map from which we pop edges + all_edges = self.coupling_map.get_edges()[ + : + ] # make copy of coupling map from which we pop edges selected_edges = [] while all_edges: rand_edge = all_edges.pop(self._rng.integers(len(all_edges))) diff --git a/test/library/randomized_benchmarking/test_mirror_rb.py b/test/library/randomized_benchmarking/test_mirror_rb.py index 0fa9ca6ab5..9170305309 100644 --- a/test/library/randomized_benchmarking/test_mirror_rb.py +++ b/test/library/randomized_benchmarking/test_mirror_rb.py @@ -635,7 +635,7 @@ def test_add_more_circuit_yields_lower_variance(self): ) def test_invalid_configuration(self, configs): """Test raise error when creating experiment with invalid configs.""" - self.assertRaises(QiskitError, rb.MirrorRB, **configs) + self.assertRaises((QiskitError, ValueError), rb.MirrorRB, **configs) @data( { From 1c980495308f038dda45d529e4f3f3ebe20f3f9b Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 28 Mar 2023 00:32:16 -0400 Subject: [PATCH 54/56] added data processor node for analysis and added validation for analysis option --- docs/conf.py | 2 +- docs/manuals/verification/mirror_rb.rst | 17 +- .../mirror_rb_analysis.py | 232 ++++++------------ .../randomized_benchmarking/sampling_utils.py | 1 - 4 files changed, 82 insertions(+), 170 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c9b2047add..9c12751e54 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -82,7 +82,7 @@ nbsphinx_thumbnails = { "manuals/verification/quantum_volume": "_images/quantum_volume_2_0.png", "manuals/measurement/readout_mitigation": "_images/readout_mitigation_4_0.png", - "manuals/verification/mirror_rb": "_images/mirror_rb_1_1.png", + "manuals/verification/mirror_rb": "_images/mirror_rb_1_0.png", "manuals/verification/randomized_benchmarking": "_images/randomized_benchmarking_3_1.png", "manuals/measurement/restless_measurements": "_images/restless_shots.png", "manuals/verification/state_tomography": "_images/state_tomography_3_0.png", diff --git a/docs/manuals/verification/mirror_rb.rst b/docs/manuals/verification/mirror_rb.rst index 9c1a9bfa55..2a6222f8dc 100644 --- a/docs/manuals/verification/mirror_rb.rst +++ b/docs/manuals/verification/mirror_rb.rst @@ -172,7 +172,7 @@ There are several options that change the composition of the mirror RB circuit l Paulis at the end of the circuit to set the output to :math:`\left\vert0\right\rangle^{\otimes n}`, up to a global phase -The default settings produce the circuits in Ref [1]_. +The default settings produce the circuits in Ref. [1]_. Let's look at how these options change the circuit. First, the default with Pauli layers between Cliffords and single-qubit Cliffords at the start and end: @@ -184,7 +184,7 @@ between Cliffords and single-qubit Cliffords at the start and end: seed=100, backend=backend, num_samples=1) - exp.circuits()[0].decompose().draw("mpl") + exp.circuits()[0].decompose().remove_final_measurements(inplace=False).draw("mpl") And now with the start and end Clifford layers turned off and the inverting Pauli layer added at the end: @@ -198,7 +198,7 @@ And now with the start and end Clifford layers turned off and the inverting Paul start_end_clifford=False, pauli_randomize=True, inverting_pauli_layer=True) - exp.circuits()[0].decompose().draw("mpl") + exp.circuits()[0].decompose().remove_final_measurements(inplace=False).draw("mpl") Another important option is ``two_qubit_gate_density`` (default ``0.2``). This is the expected fraction of two-qubit gates in the circuit, not accounting for the optional @@ -235,8 +235,15 @@ has decreased: exp.circuits()[0].remove_final_measurements(inplace=False).draw("mpl") Note that the edge grab algorithm is probabilistic and only tends to the exact two -qubit gate density asymptotically. - +qubit gate density asymptotically, so you may not get layers fully packed with +two-qubit gates even if you specify a density of 1. + +The default interface of :class:`MirrorRB` only allows the above options in +addition to passing ``sampler_opts`` to your sampler upon instantiation. If you +decide to choose a custom gate set or implement your own sampler, note that the +validity of fitting the effective polarizaton as a function of circuit length to +obtain average gate infidelity depends on a list of assumptions [1]_ that may no +longer be valid. Mirror RB implementation in ``pyGSTi`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index ba06d07b54..236a07aec6 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2021. +# (C) Copyright IBM 2023. # # 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 @@ -12,27 +12,18 @@ """ Mirror RB analysis class. """ -from typing import Dict, List, Tuple, Union, TYPE_CHECKING - -import lmfit -from qiskit.exceptions import QiskitError - +from typing import List, Union import numpy as np +from uncertainties import unumpy as unp from scipy.spatial.distance import hamming import qiskit_experiments.curve_analysis as curve -from qiskit_experiments.framework import AnalysisResultData -from qiskit_experiments.data_processing.exceptions import DataProcessorError -from uncertainties import unumpy as unp # pylint: disable=wrong-import-order +from qiskit_experiments.framework import AnalysisResultData, ExperimentData +from qiskit_experiments.data_processing import DataProcessor +from qiskit_experiments.data_processing.data_action import DataAction from .rb_analysis import RBAnalysis -if TYPE_CHECKING: - from uncertainties import UFloat - -# A dictionary key of qubit aware quantum instruction; type alias for better readability -QubitGateTuple = Tuple[Tuple[int, ...], str] - class MirrorRBAnalysis(RBAnalysis): r"""A class to analyze mirror randomized benchmarking experiment. @@ -145,20 +136,16 @@ def _default_options(cls): # Do this by setting options to "Success Probability" or "Adjusted Success Probability" default_options.analyzed_quantity = "Effective Polarization" - return default_options - - def set_options(self, **fields): - if "analyzed_quantity" in fields: - if fields["analyzed_quantity"] not in [ + default_options.set_validator( + field="analyzed_quantity", + validator_value=[ "Success Probability", "Adjusted Success Probability", "Effective Polarization", - ]: - raise QiskitError( - 'analyzed_quantity must be one of "Success Probability", "Adjusted Success Probability", ' - 'or "Effective Polarization"' - ) - super().set_options(**fields) + ], + ) + + return default_options def _generate_fit_guesses( self, @@ -191,48 +178,6 @@ def _generate_fit_guesses( return user_opt - def _format_data( - self, - curve_data: curve.CurveData, - ) -> curve.CurveData: - """Postprocessing for the processed dataset. - - Args: - curve_data: Processed dataset created from experiment results. - - Returns: - Formatted data. - """ - # TODO Eventually move this to data processor, then create RB data processor. - - # take average over the same x value by keeping sigma - data_allocation, xdata, ydata, sigma, shots = curve.utils.multi_mean_xy_data( - series=curve_data.data_allocation, - xdata=curve_data.x, - ydata=curve_data.y, - sigma=curve_data.y_err, - shots=curve_data.shots, - method="sample", - ) - - # sort by x value in ascending order - data_allocation, xdata, ydata, sigma, shots = curve.utils.data_sort( - series=data_allocation, - xdata=xdata, - ydata=ydata, - sigma=sigma, - shots=shots, - ) - - return curve.CurveData( - x=xdata, - y=ydata, - y_err=sigma, - shots=shots, - data_allocation=data_allocation, - labels=curve_data.labels, - ) - def _create_analysis_results( self, fit_data: curve.FitData, @@ -266,116 +211,83 @@ def _create_analysis_results( return outcomes - def _run_data_processing( - self, raw_data: List[Dict], models: List[lmfit.Model] - ) -> curve.CurveData: - """Manual data processing + def _initialize(self, experiment_data: ExperimentData): + """Initialize curve analysis by setting up the data processor for Mirror + RB data. Args: - raw_data: Payload in the experiment data. - models: A list of LMFIT models that provide the model name and - optionally data sorting keys. - - Returns: - Processed data that will be sent to the formatter method. - - Raises: - DataProcessorError: When model is multi-objective function but - data sorting option is not provided. - DataProcessorError: When key for x values is not found in the metadata. + experiment_data: Experiment data to analyze. """ - x_key = self.options.x_key - - try: - xdata = np.asarray([datum["metadata"][x_key] for datum in raw_data], dtype=float) - except KeyError as ex: - raise DataProcessorError( - f"X value key {x_key} is not defined in circuit metadata." - ) from ex - - ydata = self._compute_polarizations_and_probabilities(raw_data) - shots = np.asarray([datum.get("shots", np.nan) for datum in raw_data]) - - def _matched(metadata, **filters): - try: - return all(metadata[key] == val for key, val in filters.items()) - except KeyError: - return False - - if len(models) == 1: - # all data belongs to the single model - data_allocation = np.full(xdata.size, 0, dtype=int) - else: - data_allocation = np.full(xdata.size, -1, dtype=int) - for idx, sub_model in enumerate(models): - try: - tags = sub_model.opts["data_sort_key"] - except KeyError as ex: - raise DataProcessorError( - f"Data sort options for model {sub_model.name} is not defined." - ) from ex - if tags is None: - continue - matched_inds = np.asarray( - [_matched(d["metadata"], **tags) for d in raw_data], dtype=bool - ) - data_allocation[matched_inds] = idx - - return curve.CurveData( - x=xdata, - y=unp.nominal_values(ydata), - y_err=unp.std_devs(ydata), - shots=shots, - data_allocation=data_allocation, - labels=[sub_model._name for sub_model in models], + super()._initialize(experiment_data) + + num_qubits = len(self._physical_qubits) + target_bs = [] + for circ_result in experiment_data.data(): + if circ_result["metadata"]["inverting_pauli_layer"] is True: + target_bs.append("0" * num_qubits) + else: + target_bs.append(circ_result["metadata"]["target"]) + + self.set_options( + data_processor=DataProcessor( + input_key="counts", + data_actions=[ + ComputeQuantities( + analyzed_quantity=self.options.analyzed_quantity, + num_qubits=num_qubits, + target_bs=target_bs, + ) + ], + ) ) - def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp.uarray: - """Compute success probabilities, adjusted success probabilities, and - polarizations from raw results - Args: - raw_data: List of raw results for each circuit +class ComputeQuantities(DataAction): + """Data processing node for computing useful mirror RB quantities from raw results.""" - Returns: - Unp array of either success probabiltiies, adjusted success probabilities, - or polarizations as specified by the user. + def __init__( + self, + num_qubits, + target_bs, + analyzed_quantity: str = "Effective Polarization", + validate: bool = True, + ): """ + Args: + num_qubits: Number of qubits. + quantity: The quantity to calculate. + validate: If set to False the DataAction will not validate its input. + """ + super().__init__(validate) + self._num_qubits = num_qubits + self._analyzed_quantity = analyzed_quantity + self._target_bs = target_bs + def _process(self, data: np.ndarray): # Arrays to store the y-axis data and uncertainties y_data = [] y_data_unc = [] - num_qubits = len(self._physical_qubits) - target_bs = "0" * num_qubits - for circ_result in raw_data: - # If there is no inverting Pauli layer at the end of the circuit, get the target bitstring - if not circ_result["metadata"]["inverting_pauli_layer"]: - target_bs = circ_result["metadata"]["target"] + for i, circ_result in enumerate(data): + target_bs = self._target_bs[i] # h[k] = proportion of shots that are Hamming distance k away from target bitstring - hamming_dists = np.zeros(num_qubits + 1) - for bitstring, count in circ_result["counts"].items(): + hamming_dists = np.zeros(self._num_qubits + 1) + for bitstring, count in circ_result.items(): # Compute success probability success_prob = 0.0 if bitstring == target_bs: - success_prob = count / circ_result.get( - "shots", sum(circ_result["counts"].values()) - ) + success_prob = count / sum(circ_result.values()) success_prob_unc = np.sqrt(success_prob * (1 - success_prob)) - if self.options.analyzed_quantity == "Success Probability": + if self._analyzed_quantity == "Success Probability": y_data.append(success_prob) y_data_unc.append(success_prob_unc) - circ_result["metadata"]["success_probability"] = success_prob - circ_result["metadata"]["success_probability_stddev"] = success_prob_unc # Compute hamming distance proportions target_bs_to_list = [int(char) for char in target_bs] actual_bs_to_list = [int(char) for char in bitstring] - k = int(round(hamming(target_bs_to_list, actual_bs_to_list) * num_qubits)) - hamming_dists[k] += count / circ_result.get( - "shots", sum(circ_result["counts"].values()) - ) + k = int(round(hamming(target_bs_to_list, actual_bs_to_list) * self._num_qubits)) + hamming_dists[k] += count / sum(circ_result.values()) # Compute hamming distance uncertainties hamming_dist_unc = np.sqrt(hamming_dists * (1 - hamming_dists)) @@ -383,25 +295,19 @@ def _compute_polarizations_and_probabilities(self, raw_data: List[Dict]) -> unp. # Compute adjusted success probability and standard deviation adjusted_success_prob = 0.0 adjusted_success_prob_unc = 0.0 - for k in range(num_qubits + 1): + for k in range(self._num_qubits + 1): adjusted_success_prob += (-0.5) ** k * hamming_dists[k] adjusted_success_prob_unc += (0.5) ** k * hamming_dist_unc[k] ** 2 adjusted_success_prob_unc = np.sqrt(adjusted_success_prob_unc) - circ_result["metadata"]["adjusted_success_probability"] = adjusted_success_prob - circ_result["metadata"][ - "adjusted_success_probability_stddev" - ] = adjusted_success_prob_unc - if self.options.analyzed_quantity == "Adjusted Success Probability": + if self._analyzed_quantity == "Adjusted Success Probability": y_data.append(adjusted_success_prob) y_data_unc.append(adjusted_success_prob_unc) # Compute effective polarization and standard deviation (arXiv:2112.09853v1) - pol_factor = 4**num_qubits + pol_factor = 4**self._num_qubits pol = pol_factor / (pol_factor - 1) * adjusted_success_prob - 1 / (pol_factor - 1) pol_unc = np.sqrt(pol_factor / (pol_factor - 1)) * adjusted_success_prob_unc - circ_result["metadata"]["polarization"] = pol - circ_result["metadata"]["polarization_uncertainty"] = pol_unc - if self.options.analyzed_quantity == "Effective Polarization": + if self._analyzed_quantity == "Effective Polarization": y_data.append(pol) y_data_unc.append(pol_unc) diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 2bb0a4e4ee..58b79a47d3 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -18,7 +18,6 @@ from abc import ABC, abstractmethod from typing import Optional, Union, List, Tuple, Sequence, NamedTuple, Dict from collections import defaultdict - from numpy.random import Generator, default_rng, BitGenerator, SeedSequence import numpy as np From fb41d6d304f913d8d3d8f591f7d7145748665359 Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 28 Mar 2023 01:24:03 -0400 Subject: [PATCH 55/56] change sampler to return a generator --- .../mirror_rb_experiment.py | 4 +- .../randomized_benchmarking/sampling_utils.py | 54 +++++++++---------- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index 19680cfd75..cd9b4e6e34 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -321,7 +321,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Interleave random Paulis if set by user if self.experiment_options.pauli_randomize: - pauli_layers = pauli_sampler(range(self.num_qubits), length=seqlen + 1) + pauli_layers = list(pauli_sampler(range(self.num_qubits), length=seqlen + 1)) seq = list(itertools.chain(*zip(pauli_layers[:-1], seq))) seq.append(pauli_layers[-1]) if not self.experiment_options.full_sampling: @@ -329,7 +329,7 @@ def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: # Add start and end cliffords if set by user if self.experiment_options.start_end_clifford: - clifford_layers = clifford_sampler(range(self.num_qubits), length=1) + clifford_layers = list(clifford_sampler(range(self.num_qubits), length=1)) seq.insert(0, clifford_layers[0]) seq.append(self._inverse_layer(clifford_layers[0])) if not self.experiment_options.full_sampling: diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index 58b79a47d3..cd1719c5ad 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -18,6 +18,7 @@ from abc import ABC, abstractmethod from typing import Optional, Union, List, Tuple, Sequence, NamedTuple, Dict from collections import defaultdict +from typing import Iterator from numpy.random import Generator, default_rng, BitGenerator, SeedSequence import numpy as np @@ -120,7 +121,6 @@ def gate_distribution(self, dist: List[GateDistribution]) -> None: raise TypeError( "The only allowed gates in the distribution are Instruction instances." ) - self._gate_distribution = dist def _probs_by_gate_size(self, distribution: Sequence[GateDistribution]) -> Dict: @@ -168,7 +168,7 @@ def _probs_by_gate_size(self, distribution: Sequence[GateDistribution]) -> Dict: return gate_probs @abstractmethod - def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[GateInstruction, ...]]: + def __call__(self, qubits: Sequence, length: int = 1) -> Iterator[Tuple[GateInstruction, ...]]: """Samplers should define this method such that it returns sampled layers given the input parameters. Each layer is represented by a list of ``GateInstruction`` namedtuples, where ``GateInstruction.op`` is the gate to be @@ -180,7 +180,7 @@ def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[GateInstruct length: The number of layers to generate. Defaults to 1. Returns: - A list of layers consisting of GateInstruction objects. + A generator of layers consisting of GateInstruction objects. """ raise NotImplementedError @@ -188,11 +188,26 @@ def __call__(self, qubits: Sequence, length: int = 1) -> List[Tuple[GateInstruct class SingleQubitSampler(BaseSampler): """A sampler that samples layers of random single-qubit gates from a specified gate set.""" + @BaseSampler.gate_distribution.setter + def gate_distribution(self, dist: List[GateDistribution]) -> None: + """Set the distribution of gates used in the sampler. + + Args: + dist: A list of tuples with format ``(probability, gate)``. + """ + super(SingleQubitSampler, type(self)).gate_distribution.fset(self, dist) + + gateset = self._probs_by_gate_size(dist) + if not math.isclose(sum(gateset[1][1]), 1): + raise QiskitError( + "The distribution for SingleQubitSampler should be all single qubit gates." + ) + def __call__( self, qubits: Sequence, length: int = 1, - ) -> List[Tuple[GateInstruction]]: + ) -> Iterator[Tuple[GateInstruction]]: """Samples random single-qubit gates from the specified gate set. The input gate distribution must consist solely of single qubit gates. @@ -201,7 +216,7 @@ def __call__( length: The length of the sequence to output. Returns: - A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` + A ``length``-long iterator of :class:`qiskit.circuit.QuantumCircuit` layers over ``qubits``. Each layer is represented by a list of ``GateInstruction`` tuples where ``GateInstruction.op`` is the gate to be applied and ``GateInstruction.qargs`` is the tuple of qubit @@ -210,10 +225,6 @@ def __call__( """ gateset = self._probs_by_gate_size(self._gate_distribution) - if not math.isclose(sum(gateset[1][1]), 1): - raise QiskitError( - "The distribution for SingleQubitSampler should be all single qubit gates." - ) samples = self._rng.choice( np.array(gateset[1][0], dtype=object), @@ -221,12 +232,8 @@ def __call__( p=gateset[1][1], ) - layers = [] for samplelayer in samples: - layers.append( - tuple(GateInstruction(*ins) for ins in zip(((j,) for j in qubits), samplelayer)) - ) - return layers + yield tuple(GateInstruction(*ins) for ins in zip(((j,) for j in qubits), samplelayer)) class EdgeGrabSampler(BaseSampler): @@ -289,7 +296,7 @@ def __call__( self, qubits: Sequence, length: int = 1, - ) -> List[Tuple[GateInstruction]]: + ) -> Iterator[Tuple[GateInstruction]]: """Sample layers using the edge grab algorithm. Args: @@ -303,7 +310,7 @@ def __call__( QiskitError: If the coupling map is invalid. Returns: - A ``length``-long list of :class:`qiskit.circuit.QuantumCircuit` + A ``length``-long iterator of :class:`qiskit.circuit.QuantumCircuit` layers over ``num_qubits`` qubits. Each layer is represented by a list of ``GateInstruction`` named tuples which are in the format (qargs, gate). Single-qubit Cliffords are represented by integers @@ -330,17 +337,6 @@ def __call__( if not np.isclose(norm1q + norm2q, 1): raise QiskitError("The edge grab sampler only supports 1- and 2-qubit gates.") two_qubit_gate_density = norm2q / (norm1q + norm2q) - if num_qubits == 1: - return [ - (GateInstruction((qubits[0],), i),) - for i in self._rng.choice( - np.array(gateset[1][0], dtype=object), - p=[i / norm1q for i in gateset[1][1]], - size=length, - ) - ] - - layer_list = [] for _ in range(length): all_edges = self.coupling_map.get_edges()[ @@ -391,7 +387,6 @@ def __call__( ), ), ) - # remove these qubits from put_1q_gates put_1q_gates.remove(edge[0]) put_1q_gates.remove(edge[1]) @@ -412,5 +407,4 @@ def __call__( (q,), self._rng.choice(np.array(gateset[1][0], dtype=Instruction)) ), ) - layer_list.append(tuple(layer)) - return layer_list + yield tuple(layer) From 7710f7c1a1acfe8b3ed53d9c120cf25c7bbb129d Mon Sep 17 00:00:00 2001 From: Helena Zhang Date: Tue, 28 Mar 2023 11:20:53 -0400 Subject: [PATCH 56/56] Address review comments and fix tests - protect data processor node - moved edge grab distribution validation to setter - fixed tests and added invalid distribution tests --- .../mirror_rb_analysis.py | 4 +- .../mirror_rb_experiment.py | 19 ++-------- .../randomized_benchmarking/sampling_utils.py | 38 +++++++++++++------ .../test_sampling_utils.py | 38 ++++++++++++++----- 4 files changed, 61 insertions(+), 38 deletions(-) diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py index 236a07aec6..5ded55dece 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py @@ -232,7 +232,7 @@ def _initialize(self, experiment_data: ExperimentData): data_processor=DataProcessor( input_key="counts", data_actions=[ - ComputeQuantities( + _ComputeQuantities( analyzed_quantity=self.options.analyzed_quantity, num_qubits=num_qubits, target_bs=target_bs, @@ -242,7 +242,7 @@ def _initialize(self, experiment_data: ExperimentData): ) -class ComputeQuantities(DataAction): +class _ComputeQuantities(DataAction): """Data processing node for computing useful mirror RB quantities from raw results.""" def __init__( diff --git a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py index cd9b4e6e34..b504ab270a 100644 --- a/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py +++ b/qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py @@ -243,21 +243,10 @@ def _set_distribution_options(self): warnings.warn("Two-qubit gate density is too high, capping at 1.") adjusted_2q_density = 1 - if self.experiment_options.pauli_randomize: - self._distribution.gate_distribution = [ - GateDistribution( - prob=adjusted_2q_density, op=self.experiment_options.two_qubit_gate - ), - GateDistribution(prob=1 - adjusted_2q_density, op=GenericClifford(1)), - ] - - else: - self._distribution.gate_distribution = [ - GateDistribution( - prob=adjusted_2q_density, op=self.experiment_options.two_qubit_gate - ), - GateDistribution(prob=1 - adjusted_2q_density, op=GenericClifford(1)), - ] + self._distribution.gate_distribution = [ + GateDistribution(prob=adjusted_2q_density, op=self.experiment_options.two_qubit_gate), + GateDistribution(prob=1 - adjusted_2q_density, op=GenericClifford(1)), + ] def _sample_sequences(self) -> List[Sequence[SequenceElementType]]: """Sample layers of mirror RB using the provided distribution and user options. diff --git a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py index cd1719c5ad..6069e9e83d 100644 --- a/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/sampling_utils.py @@ -16,9 +16,8 @@ import warnings import math from abc import ABC, abstractmethod -from typing import Optional, Union, List, Tuple, Sequence, NamedTuple, Dict +from typing import Optional, Union, List, Tuple, Sequence, NamedTuple, Dict, Iterator from collections import defaultdict -from typing import Iterator from numpy.random import Generator, default_rng, BitGenerator, SeedSequence import numpy as np @@ -197,7 +196,7 @@ def gate_distribution(self, dist: List[GateDistribution]) -> None: """ super(SingleQubitSampler, type(self)).gate_distribution.fset(self, dist) - gateset = self._probs_by_gate_size(dist) + gateset = self._probs_by_gate_size(self.gate_distribution) if not math.isclose(sum(gateset[1][1]), 1): raise QiskitError( "The distribution for SingleQubitSampler should be all single qubit gates." @@ -263,6 +262,27 @@ class EdgeGrabSampler(BaseSampler): """ + @BaseSampler.gate_distribution.setter + def gate_distribution(self, dist: List[GateDistribution]) -> None: + """Set the distribution of gates used in the sampler. + + Args: + dist: A list of tuples with format ``(probability, gate)``. + """ + super(EdgeGrabSampler, type(self)).gate_distribution.fset(self, dist) + + gateset = self._probs_by_gate_size(self.gate_distribution) + + try: + norm1q = sum(gateset[1][1]) + norm2q = sum(gateset[2][1]) + except IndexError as exc: + raise QiskitError( + "The edge grab sampler requires 1-qubit and 2-qubit gates to be specified." + ) from exc + if not np.isclose(norm1q + norm2q, 1): + raise QiskitError("The edge grab sampler only supports 1- and 2-qubit gates.") + def __init__( self, gate_distribution=None, @@ -327,15 +347,9 @@ def __call__( """ num_qubits = len(qubits) gateset = self._probs_by_gate_size(self._gate_distribution) - try: - norm1q = sum(gateset[1][1]) - norm2q = sum(gateset[2][1]) - except KeyError as exc: - raise QiskitError( - "The edge grab sampler requires 1-qubit and 2-qubit gates to be specified." - ) from exc - if not np.isclose(norm1q + norm2q, 1): - raise QiskitError("The edge grab sampler only supports 1- and 2-qubit gates.") + norm1q = sum(gateset[1][1]) + norm2q = sum(gateset[2][1]) + two_qubit_gate_density = norm2q / (norm1q + norm2q) for _ in range(length): diff --git a/test/library/randomized_benchmarking/test_sampling_utils.py b/test/library/randomized_benchmarking/test_sampling_utils.py index 1dc5a7ef99..0f340904bc 100644 --- a/test/library/randomized_benchmarking/test_sampling_utils.py +++ b/test/library/randomized_benchmarking/test_sampling_utils.py @@ -15,8 +15,10 @@ """ from test.base import QiskitExperimentsTestCase +from ddt import ddt, data -from qiskit.circuit.library import XGate, CXGate +from qiskit.circuit.library import XGate, CXGate, CCXGate +from qiskit.exceptions import QiskitError from qiskit_experiments.library.randomized_benchmarking.sampling_utils import ( SingleQubitSampler, @@ -26,6 +28,7 @@ from qiskit_experiments.library.randomized_benchmarking.clifford_utils import CliffordUtils +@ddt class TestSamplingUtils(QiskitExperimentsTestCase): """Tests for the Sampler classes.""" @@ -34,18 +37,17 @@ class TestSamplingUtils(QiskitExperimentsTestCase): def test_gate_distribution(self): """Test the gate distribution is calculated correctly.""" sampler = SingleQubitSampler(seed=self.seed) - sampler.gate_distribution = [(0.8, GenericClifford(1)), (0.2, CXGate())] + sampler.gate_distribution = [(0.8, GenericClifford(1)), (0.2, XGate())] dist = sampler._probs_by_gate_size(sampler.gate_distribution) - self.assertEqual(len(dist[1][0]), 24) - self.assertAlmostEqual(sum(dist[1][1]), 0.8) - self.assertEqual(dist[2][0], [CXGate()]) - self.assertAlmostEqual(sum(dist[2][1]), 0.2) + self.assertEqual(len(dist[1][0]), 25) + for i in dist[1][0]: + self.assertTrue(i == XGate() or 0 <= i < CliffordUtils.NUM_CLIFFORD_1_QUBIT) def test_1q_custom_gate(self): """Test that the single qubit sampler works with custom gates.""" sampler = SingleQubitSampler(seed=self.seed) sampler.gate_distribution = [(1, XGate())] - layer = sampler((0,), 3) + layer = list(sampler((0,), 3)) self.assertEqual( layer, [(((0,), XGate()),), (((0,), XGate()),), (((0,), XGate()),)], @@ -66,8 +68,7 @@ def test_edgegrab(self): layer = sampler((0,), 3) for i in layer: self.assertTrue( - (i[0].op < CliffordUtils.NUM_CLIFFORD_1_QUBIT and i[0].op >= 0) - or i[0].op == CXGate() + 0 <= i[0].op < CliffordUtils.NUM_CLIFFORD_1_QUBIT or i[0].op == CXGate() ) def test_edgegrab_all_2q(self): @@ -79,3 +80,22 @@ def test_edgegrab_all_2q(self): layer = sampler(range(10), 3) for i in layer: self.assertTrue(i[0].op == CXGate()) + + def test_invalid_1q_distribution(self): + """Test that the single qubit sampler rejects incorrect + distributions.""" + sampler = SingleQubitSampler(seed=self.seed) + with self.assertRaises(QiskitError): + sampler.gate_distribution = [(0.8, GenericClifford(1)), (0.2, CXGate())] + + @data( + [(1, GenericClifford(2))], + [(0.5, GenericClifford(2)), (0.5, GenericClifford(3))], + [(0.2, GenericClifford(2)), (0.3, XGate()), (0.5, CCXGate())], + ) + def test_invalid_edgegrab_distribution(self, distribution): + """Test that the edge grab sampler rejects incorrect + distributions.""" + sampler = EdgeGrabSampler(seed=self.seed) + with self.assertRaises(QiskitError): + sampler.gate_distribution = distribution

    NKMMuQ1y;#uY_g0{5}( zWXH_~nr{TROD3+);~>k-%Z=OekwlK4Jx_Q)T-6?OH@-4-!v&{u_N;Z<#~K;#duJ*x zMl(w@+{D7dJfCI!1E6ZtM5*QUa`o%W zP3xL}Z6uj2phe4YO1B!ONk|jA_}@|MDD=nlW^-r++P%-k1G14ka8)|DJPfH6eE|w_$O*sQZr*rSO0R217igx zq%!vm7N5D{MB%35x0d468~W*s3%=xL$ZWJNTWB5`mbwX=O3A$I23@Tk`F@`wlmbt- zYh6Fv{>f4^BSpkP(Lr0P?T^e<8YL}YCZ_TQ7x?-DYiQ(t5DG=;yAHeP~Bbbg!dk48=vy@XhKO_En~&V-0ih`N zCDl^R2+yGTk<3YQ5H=oWLM)(+0HyEr9U#s1w+AYwe88{fL&J>>_!z#6ae|aiJeYT||v!FHp3Ti4UwO1{28@I^8i>z_Ipvvi2Rtm>5uwenJh*5ARdZhxJ z^3~6p39c=zQLqQE@1q5A&gPe)%v}sWuSA31yRdkgyAdoU{c7x=d1&-wUpjJB{>*F) zCZ=;iW^xIOztZ3veCr=}%i^|K+b|7pg`4|_zSSC&#m-Vd!rm`f)* zft>%jvJSYi-&t24O`hIwd35c4ZuT%^EWB9UoUP1-^5-y07bh>WjYgf{OJ@>S7EQ!+ zZIW%Y7IWqJ=N`-GsItW6<8{1EIE+&}oXCkA>Udh!9uL8b|IHKSorT$j-hbQPzURX& z>nq}IJ~fsvf_!k9?0BL_wv`;aOmw5&oGrZ7pS-*4JXgjX;Cdcn(Nm&?IJz8!hL zKt497!4xxRS*SMGLs5O;q7fm?MuT!DEz!wjBX0T7JTY;&s1sy%X_2gu%cTdTfXC|A zo-7%w377Lb!@Cb84r?18K323+ufCLdc!_WNI!&%h@MW3W%-m*)z*0n5B-Z=;8T;K< zo!~PDOh2O`6>?DUW+p z#Tey1TI zw9{QS8jaS|t{(Mn+gY0cO~C-AR*3ls9P`ZL9|<BCxH zTQLw(V_xZC1cqrV_n9O$v_E0G=9XEo*y&KU*X$d{Rz(|+uPF-V{mBEWHg!^A31`5o zT2#Y@zdM7cbP%>Qkwwq+Cq2@45|!G5tXyaTc}7KhZ@=g3-3Lzk;fw@R#+Z?Ms$~Nk zst^)u^^RvbwcC$8g683edo#hL4)o5sP?73tGZ`bNT6(^1gC5p_Z60fkpq)!`mHInr z$C*!R&UI8`p_F*kka@0aT-$z^z)g(;23Ym$p)_5dU!)gQ{@0-cPF8JX=%<*NcbC_A zyO{@Yr*?B9vQhLYw#)7DJaE*>J)gJhbWt;y9x;wVG)YcYT!oCJ0qagL)K4_hBJHNc z$n0@%PquoiVGaBd`8y`vNv0B;9;Yvyo-~wRW;Pv^Hl2NS+2}jS)z)Ba_@eG9{f;p* zz6ZYCz%cr;Fw(lW%ZnxKC;z2pvv@u}%dOFWku#Mw5vjWq zH(Z;&wkb^QeQxo)-CcpERuoDvx*cv##u#k3T2LCA(RNpps9TD*7HZaszYYO+yYxf) z*b3F(2NaOoB77m?#^f|#$VjT{2BXcDzBB9Jl3&Ni=i#mVZZP(vm(rj7vi0RZUrhY> z7bW>eRs|%&S)=~vu*W}%8<{Ts#=&GBzxlfKokC5m1Zj?JkAx#p)TJ6&P?E4)a_!y3 z9`CA;aV=9W{CsqJT6)n(#)596y?8|vF=Y?QZ|tul1|O-2n(*;+>6*558g5Jd%e_pj{V@ zcG~j&>_?IwpenO5(EJ;1Qhq^*n`SjD#ZoO$JCpFi0YElEx#D)deJKdQpB?$=<(`h} zf5wUIT4!JGCNK^b3#MoGVZLt>j@(oB<~Xak+5Pu(1#g2<29F981$$ACY z5DH&%G{11&WI2{>Q*Yw0a7UIll@%$NydGt}=3fj@nQ&c#8R2-clhpoVBFN=ywjr55 zV9xi4Dy=pPyIN_iAYz4<(hCsB;z9TRLx` zk+6#uvW+eGEQj{mg^;ZZ2WbO>+RKn9KU-6OyngX3(-RPXW%;oc;z1A{=_&Rvfi>Z| z>eI424OW!*)u4>s8QxuM%lgSDCk6FN(YnJhAuF$KObWc@xTp~9s&1pNlY;tMAO8=- z@qazW|Cul6I~d4f4|0<^-rM^Q409o2*lmpsunS#_afFxqHtW|q4?!#{aW;n|tOdFY z5~w{G%j~d(N@V{>Om{&@;2SWj$TS-x(xcCNO0RfnO_Q>KgT*dub}ih6ZX9lDr!s`V zqYEQJ>N%P=DD z@R;ZLG#^3pt%}@`$U}z>NHtUAhF4f{BD{mEIg?B;pt~1!ckQ+5GDNwjMG%Fe&-qOY z+TRxMqE{wd^;X!z@AMo#IThg+9eNzVk1Hwx{TvewW74?GtL{BCN5vDpz`>#890><= z<%76DEl8I_#to8}pZVHk`&0#ahq&)CglPJ#)3)O2T*$z0Zw#-Q>$1JeZu~ePRgk&L zGK@!H+WJq@sDZzcTA!As!35h79Wt#bm4`dpVfrhZDP-0J@;~^|eh@TCQrk)Pv*r(5 zdIeMa^$Qm@`(%F;5_IPd8HcSbq!lkHizx5l7+4_UGjeDeDPrEueTFS{ll{MwQjY>zILO!uWtTN-0Ipk;jpjZ;-v*3Bks0m zdUZyI6KcjeVJ*FW{epdQd=0!#v*6rHQES0QTsfG#>CHt_R+e6kigkx0?B>RfYzo?l zT+Pq=^2hYao@bhLx=nAD`{G<{QNON4HL)kihjH65Y$i1MnTFk$^_R_&2?QZ= z&sn+Y=~YrK3)vtqB4XLrk}W4#{{3f4#JLM`TiQ1?1q5$yv)bD>o&V`V@8=Kg)>pbL z6{Sh!NNvpF*yV@~tCj#`YQFjrVBKQYDgu!^-LE`LS~>n}7hyq&7rA1sD+lkLl_E5D z`ZjTHF3MD@DKIXf*z9NUa{oc(S{8mY){L!ino6aabBer(R=ke!iCQkY)pg{?v@XYV ziQnZ9`I_&gO8~#l0Pay4mQtesWo*^*?sTyXYTMWAR?tj@nZY&6Wy9cg4<)0cC1Kt# z9K6S=LE$ja7%r~Zujyqf{-;&A7+5Ew4f17*gUqPQ1W+{| z;Rt7UbUlZ(0Nn5L;T%5SZIx~PrSlfFg_DO&+4$iVJLIHT0jV^cr0d%?m7#Ql;jWhY zxVPh*Y)gdO=lJjctkU0=>5)jK(y)2guJ$!=&Vl*luG!vm7jhvY=GjSrT)d;~j6E8q zh)@}^o-1R{1uHDn8*KOOUs%*wAuUxizehia*d(Y8%sEyjQzc}4XGE=hfE=aj`Wpla zGG_@__HmAtrl&39!e%`_Ix{|OR;zIBT4Rp}E8~as*%U-(IgDSAh&11D82^D|FT51B zFRC@%;(=26l2bL^V_diwn+L8PacJe^$_ugWqpjrYjkfcE5*BcsVV#EC=78I2NzJrI zv}=*Gh&Z7l%xF8esD%=>*{}Qt*LM<%DYD!C+gbP}g|A8+u=)I%@9?&YGdeqqZY8Fc zj~!-NfI#%~9wb^}dpyQh97_@Tre#~rX$mVKm* z@FG+aQx@IK1p9wN_Y6)}mBcL09-@^C!b_6m?2*iid;Cp+jFI8yAGIu9(QYK#xRZ}BCfEU%FFp9Ql0OSvC+pT?UYtK_V%%qLQwbNG+p zk4q7v#wp4z_=0EsFgDGTM&{ zG47YTJ+79X+<@q!_B}qTKXQ}!95(AntOh!kK4=?pZtFqjnfEl`a8idCTzvVZJ{w0> zrfmV}n%ZWbUtMC1ZM(KqZQg&TESnU&e`c)% zjK7VsPdOf(UHu{09=~&Xet?|VH4baA>qS>1^&9<4k|+=8s<8=I=lugcW0}4iT()4l zbkFN__f^lbVpZ-o?$1uodpk4(4CWuK(B0`FlK@DK_OiL2IV`X7Ng+_oomVHk{QW+~I*c z-*-Yv_?|Z|D}kgXXRZ`A_o;Uy1#pk72m3qsV!I-mnS?%2Kc9Qv9-kz6o%zi7F{2k} z?!jLDXScP5S(YB&)j-Y5j*z{>Z<+&q?nALN_e(VSGk(rfJGCBhiZ1a>G`pQJFi^OV zD@c`vwCiv;=I$<|u-E6W_mI7MKfTXi#0VnxL;5_{AfrHz!_|^IDq`8iNh9^0>fDbt zJ~!M4V<^2ZZ#%lJz!quAwf5!@F=nF;OSAUEzuf3gM!?au3Kq-9lUxORv!7X<^d<#& zqej4wP|_!2ie)fq%DzXFxjjCO?ppACOpAEqYGjzQG9L;ZI1=T=a^TMOmoL??rbJN% z796F1lZ8(v>rTk*$~yYzs_kUu6hcK}_~rPPPo~3Wo6OIi=nbmp0TRl9!rwI3da9@d>%~r|y6wLb?AOoOrg9C6@)@~ly_4GbNqt*aA6Kzm~GH1FPY4 zOfux1^1|CKmIu|;(BDD8e5!#O8XAUOEr(Nbm780>h-B76N0LbN`G@Ive?6VRBbY=5 zKI_oZA8g?;qBXiZEB$7k22b}Izef0R9USGP6lf|pbum#uk<|1&z9pElf{$@N)9-i+ zuB@?-Ekp;SE)1?NYq5ewDZUcN{#H8a+d>pH&uOvmsec=@r-jsSe0XMYc3_@I^mwbN zHS74ROVC58nV-l)zX2P)m6CkSY$)ymBV2sfl2fT&A|v|@`FLpE(Emn_ z`%2G2V;Q5b6;e|Jd({2@GT}v=%3$6APT`&W%C`;yXheI+@$Sj=XoNggP-$`KoV!IU zQTC*Mx+EuGT9ZI_BoByMVF^EVsd-zc4!;a=c>B`2-^(&HX} zq{g0D<{5+X_93+Ri5O|N0nR6@D90`lb&1P_9hkpvuyOOk79#Q?v(JgSBoX;?E;cDo znxy;r+y#<+|H3MpwBHwa+&k)cJ&KpYmfs&&R z*veW6Ge+0aHvCb5w|w@iqn@XOeR#|W1CN>QS8=rHK&gY)cOc9XgRS&YQWiB2-m`N` zOE+ou6Oj~BQ)*CyUM%AO*#)Z4aS_7}#4Q;as0?HjW9ND=bMfBnzzmMW8%URMXM(7L z4xCf{>~VQbB#h(|+jBJRIVQ4Fn^v-U;DI-8g?wRgw#`0XdyipaZD*ue>QGO=M4*jE)Q#JE-FlXVCEqYb-5qlfHCd^G3vD6X z)E+XTp8EIs@ZF*$tf9|+=krfd9t0y0QtRkDSDiA0^8KZ96ZQfMEMIT3kIC^L3#|n4 zX3)JX1^TOzNlC?-rLdQ=^kiD%vsW1e%a$^C1Ly_@UgbYXip#$fMAgfkc0;;I@#{}u zH{_m0b%MQBWSF7tOWIEDtlqzKp)Pzbw?Nh=k1^pFE_|QMk5kv}tJ0*$vxx8p#^?-L zC%9oYl{z7ch0-cpfBsx;eLrIA=-gYLuMorTC8lyiMu+Vi(Oc|#@imVTD-8E@JYtK3 zRH~7EeaCht-dIxNHz8-|f(WZF?tWM}(0ts_wVk?rfp}eEuhekbj$ zU4ditxiY_6nI6ug5Qo}jK;K^KzIHSr@RGh}u^#;U0^Nb$^FPS1q*l+(^!PQL19^V^ z3msgFn@1BLT%4lafhh^0f=khsvB1DeU+Qj4^l-X2l&4!6^~(Ty{c|UBHt~b5dsEeu zmo_yp0n+PUZI~*+$A*A+4-p=pHWP%=ZCE$v`aIlpsYYov=J=`AU^8LVu$Dw_by!q! zZ8`dSAqC}Iyy`X@H%?9?J#|XL_H-w% z^k4`kYMF(#H)_YC5y*N4@Co=EYJdBx{j!SMdWh-cFq4G8L+4O7H%lVCs?V_EWNS#- zu3M`Cbeeise{7L*-Odc&@3P*;v#7+48zTx$p#gO6XxLnJMAuo8p{#T%>cVmv@aL&$ zeEo(<_)}K5FV^l9mNx>pc5%-ggtY)w%RzjnUrmj$5Y%Z;p?h)FjgBRtV!Zd$X@z;s z&-?Y{=`CBpX-CKh>Ky73!sm|zM=5NO&FOK>S>GxfMSkk6ZC_!nL64)2wzBjdc(K3O zb{K8P9`MbqDcc||&D{=Ku-glUJ_|g2ibR$b!)gEJ0(fnP7o!cdoKGXuGdic{YnQz2 zB&Auu5?zw)BKvp^cc-0#O6O=hv(&u{dk51sW4l!9E9db?lGHw)fVk45ke zD|^H1K1#-&rbjnLo_Il}>{6E^an}})CC!ZjVrE24!QK;GhiD#He4 zBDX#bc_%)4wvI(|wLix9uW&IFg2cXn!j4|e?QE`5Kz%jv%y&jhSCVe!{kX&@3z92r zp_Q~8@b|psYexG8$2{9nu4XqJ6rr9wZ@1HH2SR!rga`5N{8S5jK*N>*xm+Ow4F%)K zcT#k)lCDgD=_lz+>m4lQ^qRI(bh*fg_I!VMaunCAe2O(F@V(o^Ahe8peLG|Vg}O|I zIY` z-imt0YKNDo!*=4s#^q7I+~w<~^WTxPa=pzHumY{@=mXRrq{Tq@*j3c-k)$xZn)ziC z-}t7LRebvK(-@ zG&cg)v88fxeFm2u_2rLv4BnA%^|kBk&5QVm7MBwlo_77T=T`23Kc%Jm?2LF|Eg*aFde1#qBh6EX=S- zxns(gwYRb8FB0swV+|ZuZfgMO0dQA%IyGz@ECmRC){lP z4MREBl6`P>tg}am;m4PapEF+gJZ9|B{LF4D@0xlzPbSQ8?kUx6+DY~K>)$Nb%n_?& zve|Ba(Plb|@(O9aXkUY1qS;yT8fMO>ECgP5BtB|G1AC1^0&qDLtSI2*EhXlO8~#E_ zjC_v61E4E1$5qo+L;1=`UN{%$+#!R}*t!2wcF%=Uz8%^+*z;?-Yj#|E)x z#<)dj)gEQCqrND*YJSlK0_`{TuO@E_5w3B~;40Tc4ZZDZA%(9j^DRm& zkB%Q|hP-Yf_~!psJof`Xv+Ykba{qpfKsU9SKo;_*QD%P(v$F_M34Bhr>5)T#p1qmY z(;yW`LCRC1041()5heXy+r(4qM=6hX*PKH8cD6eA7HKAc10QoLx}WrKzj+Zq9s5in z|3obT`$j`2&wX+?hOIthpU;T)z}L?ywvFuabufH`RHR(oSYAf393b0u;31XaY_-Mx7Wgt|mn~Jz#iET@1c${` zih<7Sy(_Nwxk}K6N0;BTJ+U2&L>h5KaJ-;Ek4#6@f#i#M&-v#0F=o}l=qnt(kz}Gs zeJnM!Gi^WHh^rjwsry`}@?}m%uV<*s zs;@o5mSn4&7oIXkXRps47#>lEU6RJe-H`u+61j#uZrRvBW|q~0<8YVo2o$U-qo=>5 z8W`I_?YX_X;Lsb4zQC;<#B61HOJX;DQOP0>b4fLhjruT}FK2bT=P^R#Uh{L3xlbgb ziaI)rMqUW@PrlSuwPlP{ObG>$GLkjE#|7wirJ|%4Vau*I*85nY*T8}D1-6zUt{hh3 zrFPZj)4eC#4;w#2F`W*C&-ykbl&2LS{Jur=2LQep3W!GLCE7yiO2x@{z-UEV>!i|& z=n-xbisOf6Lg{OXqa<0B3cuRW^Dq|&eHbe!LUPctMU`otarZ2Q5+KGB0R#C zjq%c86s1xEn+%)4c9ex`roy)i0c{6BJHI>y4xWqf*)SXqyUs58h3R_G!ge>LCU1Tz zyhdq`*?3*;DK7WCL`X2@_ZaS%-29XIBEIgbr`(*@iBG~RPsP$Lf&UmRJ! zmclUkYIoT8W;0Q}ZpTKqfYJe~5Nk!A=Y`R)5iq$YfjbvPJ#8kHP`>m%B9LBK6~05N zqy4lvkX*_4TJUHYUJ-nR0~x2a-nfn4*N#~N{^4{SKk&g&Y%e*?k4g9)Go~K^c|f0D zw;ey!X!79VzB3`It8xaQU-ojfJii=l1Dv1UE~cSx0T_|6U<(s2%4BN|Duo^JF0&h+Ks zA{Ea${4Pz;kx-lVf%kc78nj}R{W}uZ)MP$2oK)?7w)^pTxC-ly6*K}$39bi{6OOyK zhRsQ#$4hPv!9~=2tQzU#oOS&8$ah4 z`Zx-cBz+mfB=I?8_Pn{ub)}-p{%EJlXLhd28aN-LfMF_K2bOVtuH#n_CE`t9+3JtY zPaxF>yuY8E4tG3l?HaJor*}$@bLyh7(K~wGEHI!5XvN`g zFL@uRsgws_fD6wLj^Kw%{KihBQMnf2%^c%7@RW*!iodg+@GM)(&<094`ty_rfJu|l> zUt6@4XGw{>@9avK?S9yO;MnttY@pp<@N?|_64RAa7RpEN_(jmOi6z=DIx3*nZ z3uw%A_Gu*-**?lZ70t|_WBf3GpMB33r^5TOi!DvyjC7W)J87%3n`XH(`U_Gd6V9Vm z=ATpqY_ry79BvM!23pvP^I9oF5NaRUqQh`CV6z|i|F`a_OpC`|Oh7v+Zbw6WiF9hy7y z$lptRbCw}4L3~d-D}zgka{30@J1kq|>ZIi<6fZYWIg>(oLBC4P6GWg`;-j!XG$u>n zBh5ZIj3iZRVt^Dbbrw_mjA9ry4d;HBI|pzh1kUysBOp5!l)r3nwch6$Rg~~7r?$Jt zjPtb?A2n-6C<%K{k)gnBqK}JSO3jC%H7)eerBGNNNc=7bCU5u;rNp&_UACjse z{_I?99(gJ5Bt|gfx7nR~96o!2E@Bur1T4FX9Ic8dS)K#V7>%0yDEE22q9n$Sm~ckh zFRFt(`zkMD1^V!Ba055G&zCE52gdTED$J*}UeZXJ-cl0(eaSU&OGk*<`k5@VBGzB^ zP}u=MzPZ8auyt8xq5VBQ|l>BkcG*RSg{9eEl1WhqUzyAQW zK{En+V!%ovP*~;n_{?^H9^h)g!lGj2HzExU6E?92)E;UDm-O;PlG-dVs!wGOqx8unT_!*r$G|Qp?vcn&{(f*>Lp2@(oL zL6RUjO3q18qEH1Ql5>=dWXTyM6d5Gv93=}_AW%RRRqHIj-Mx?9x9>S;clX)%{^EIx z6~>%n%(+H*$2->^Jpqb~fy&p*?`v+mUtZ{}dy0&T_nMB9ss;}PHR;~BU6A(uyvZzv6^p>u-+|pasuo>N`#GJyI9O&U zmz?lQv+&_v-DMe-;IK&N+J+Y3^gy*3Q!8Xu`!UcipOR~`&E3fEnmt!yE%m zzpS|=SO?Zj)XuhGm$8hes&#^ijvb)Uo@b&c%JA0a*I@755ib_%mcy?044vQhZE_k) zCHH)0feCo``3GC(K8!oDyoTrE-kngnn_97iw$`I&L@e>ZsD_sr@|m81{cdSOOq7i4 zMK@F9Q1rsS9gN>T)mNf7m|YE4eTlOG$^8@#ebA;7W(h7iurgC&mWWzvj`$TdkL?pK zaWFd9@<~6x2K52!$|;{V;l9~T8V#vEpXGCZGo13mIp4WaHrR(GrNW|EMV$2aG%I{He@<0txafBVdF91zHK_^0?580H4lEy5nBSsX zF?=HQq+cBLSq|cP+<&_gD*ixvS7?hb7;w2WO?+h2c?R-UXN+pQH3ROS9b=>9+*jEQ z^aLdKF?^*UbA{qU&D8~%-9j#3z^5WWPyl@c?6gb#o&IM1Kj+d@}W;T z9N;xHF>ivuJ{~F+veKjK(fV}%!|l6Hm4W=Yr_Q73b^RF_VXw`8Z}KFUgJlVnlQJTZ z1fb^0etkK#`k}_a++&69 zYmA?SpU1u!PR0xh&GyrTvFAeGK19O1%ZRpzr^G42FUHTS)`KFUh$tNuj-F`#HYiUW zJ!TvR?p&s4iT=Ke;lsDx%z#ooH#6kJ+5U6+ zXHEBF?_3c2*q$O7e(DSp0QXxb<0z}QN8Z$y@5uaAW3i-m)0o2QE4X^O=Jv}^LOgz6 z)~MGDwsJXJG6<3BKB<74Dkg*}Yzqq%DJ72!Na)AIy=wFKRm3)ja!ihBju zb3y$u{%z9KqzH`jXAse1NxEJiQ4@m_!sB2l$585tvw@K<;Hm$vGv(wb?1bqpzA(N9 z^9qFV0O+T@xDl-D_C_&6CNmOwws)_SP1W3tirF^34P*^p!+->|oCbw0c-(ie*%<-@ zA#<%5%cM%Z?wcc%9C2>9PKv(3IA8bdV}0Mbbw5D7oQ(VqgPk;v$yiGjyq+#_bt9m{QkcnKvHl2}==<6t?tY57s2-ROR=- zdmT-mui2RV_62#|*AE0LTA-76b_$CI_C)rQlcmC@>~q3lUC8a@Ou!HYo>*T3-*jqx zHqS9>?h+7r2AhPaY99}X?AfGB-Z^+X10)Fup!p-k$3y1U!IdH}snUJE#}713VuKtl zo7piPL*?K%lA%&7CEI4c6?4{a>oyr7Ym&0J!u8-}KFVm(VzXp%{vO6T5{`iwgN3C< zW+)T%ENYy7<-Eu6{jb%gOXr~Q~m9%7H)PYmsXBbc{RYI9d|JCJ&vIeFp@xW2QwjgmQ zNUT?2cX|`{gXJwbg+i$N&&9?QR*sOZ!Sp!oGQ*;7hABXs*Vz9msrWz+Ndm@h`nhfb z^g5c^XI^_SqpfSdh&%uTp*BK1Hob3lGjbF^(O4s;;+4zeH%SWupX9pRx}%ZKl9-*9 z+`HV?c`D`Uaj#DC9JqKMQz%4t(b-`FUtm{}+s(>@{j}9Px0pJk%HQY;EZmeGD95GA zg(NvWztE!Y_N%ZtV(OWIz(`t$4XT7&h?u7?PdL)7SqSLbe^xwByP}`Bt@4#={Rd?d zn|xHREX`^nJ?-wr_Ag^GnDn=ek~EbqU!trxC)hGB8{|YZUtW8Yqx3XHG)w0g8(wqA7UqWMt0&K1{-U!Fh z0_!qyZZp>=1vuJ+73!!Y(RihlW2vsq8IaIF>u#CcweeA4;AF zzHIK6W5-~@-vH!o=Fr@d1|=VOdOF~BT;5K2W2s+vB)R45590?CYyBm{u{3f4zlDi~ zSthM;LM-l7Emp~PW&i_x@bDFp@?6SULZ9}IKoNGo>xm;KKq_bPcuE{|StYTi)uzfT zHl%Y>oyzXOisw>r2x>c%J9LVqMVm5jGUw_BD?f>59`(}>;aMOTD$L4#=3wwriwN^e zpd;%@{$h@!-o|m_sOFmaJtC?H3|^Oc#f~W*}%;pZj|{kfO&tri@E8C4O@xnCTcJ;F3PW22gZo!HAzP8R-fb%#~X%9T9-*iv9V~zr0(=7{lkm zq?BCbdogrtT@tp?ulp2VlW^!6w0T>!4jO2p7xk8B&fPbirt02%|KxVAQNZ!03~+Tg zM>5n=U9~Uj%T-jZ*Un^l+UxSGq*<2S*By{o=@omkXf=IeQQIJlQ0x5b`oSy_reGtj zRqo#0D?Oz1;+C5Zfcho+K<)k)pcVZp7LO#Sp*WBy?mdk5(`7`jGfF$HBFFR=1WBWdQMY&`T2A48$rbjt(QK#_N+NC zGy%n%J(wAqn*hGp8;}coPdHo`N?ul;r>o%%=vSN0e1(3xj9%B?2-m~7j9gO+H!0K% zMj`-NG2k$e+W2|up@by?-m3foY|lOWyoI@5P}`D`dO33O+a_3mDzuOB#yDtuqt8we zzpz+Gaf5(6juWqHRIKwHf7rn8IU&SM*3RHQY3L3jht$NkCy-917edz}kCMFJ9F08} zGk4FwGzPswVcE}Lgb6%m zH*Z4B*KoCL;_YwXeX_T_Tq07)%DJ>q$p!Xo1=Xt3Taig%Qt*1|F7wevC#WEr*Z^H& z4&V0z;bAsfKlXtH#X3UfUrQD4j@3J%s@50q&~+97WSKO3v1#$B$Z_}(OX@t^e?!?% zjwbIiF?V)d9pk*#+-OTV?A}TbJ*#s&U#*$IM$j|*y(qvmIc3j`*gf>cGK0+n2P>5c zF2mZ~IcfOIx`%2#eq5j1x_v{;!g%!X7O zDi3SgxK*1qvT$97%|7YOG7~CdwbR)d{iZ)O^}Hh`82TyMsPXk-t4oC#uCuoY`xlYT4>>JZx!FAi86vX^C(eg8RkqwN* zoZh=E8T5uJ8_j!PDMkSo>$VQNRd2V`J@8f@;wKhAv`1+dql^Uw3`&#Jvylk=-pIUi z29O6e?Z}M*zI*bb*9&;{15v)%uSYRJ+;4GG-bHq$yhF&79?wkYyV0W^o+N`&#TK?B zX%up1NZrpt>S+=R3rXOF46m*`kVZ*bryGY<`Y%+d9PrF) zvEU`%9cPFned<(4>1y|TT=tecANCC4=jjfXJ}8PGOVMZW*>C%q_SBy_u|GmiGU1qm zx4n!Wxv9o(LgBWg{7UzDTN!#GmS*mbY02p}Y-`+uSQ!A#e(5ZTF|G_rbi>1_ zf~f*=7}Wci*nT3a?54SEg>*pjY{pG4mJAj&n(+j+M6pE51(ABHV~5^0ptV={g-KM` zqc^y3!WHdB%1$K2E+lT%JBxe&iOjX{;Q=<&d_p-d!By1|NV^ z)MvGSjgsZg6;g9ff=|hmxa3~Iw+}z%rGJr?T)2Bv|5)jfS5rJ3hb1>sWi15326a3*cx)Nz0Km) z6RbCHmUbg!jt>{gzTP!s7mVzu{B1r)C9K!k{~?R&0!zJR$vouMIYWnX}`K62g@{= zaO5HSOd}J8Il-+_0S3xjAxl53jUpjfR`P0k(K6Mr*Ufa!Q7-F9!9Ul~Q8)XF4Rgnb zeT8tAbmZ0Lu>r`~3cQT2t?&S@Ohrl$q=zw&yy2Ir@W#Fu#%roFVs_A74y66KWvX0O zpz~xE?;jLdT-sOPeN4=+wY?~&2Vw>slVT666;QYc7=S6f$?|=k+ce zBLXhOf8CI*O=*K9ytit88hVffNOv$2|#q(RQBYEVBG< z<;SEN8Tz4naQH|9>pJ5o6k(+DO*&Sq)y~gEV5h+ zU$9Fz`{U~U`FX#Pn^X>OQsUoBJoR%iDAoA$Y9j-B{+RanjxXZWUkBab|ELe5Kfzv|MjIp6Mm_G3<%#>W%MZ?QJuJoVml*iTSJlXDoD6k zF=VSw`197)p2x=I!hgu*bf384?<0u!Z%C-bgi`|1k9e+8DO1d>g1I|}=L@SIRqDRz zNJh(4DHSWOWNGi<^Oawfma~LH&X$W5JRuB%e>~CM(Xs8%_m@s{{rUc~QsO_Szkcdb z_a9f!*4F+vD{JXJh|IgOFgCE7g%^=hg=-C1lSaDDc_XH4EXh$S5~I!?eyfEC02o^9 zlGh3HHXbLY{-sQTIQOnU1!weD_;Z-~RgtrQ2;Lyer|{?1n$u)|D#c^x?zgA=_lwOp zb|{Pl>`4MLVu|m6X%4Q1lIhNa==6MfCNJS77=V0>cB~hb7r;lY7=F5J!>0&yA<@^V zSY-PbYwg`2{x@&U7W(|>TVI;ui2R`nr=9S^zbh9sPt93Bl|PJ`{t=tqAI8i;DPr=6 z>92nr4o>MadF<+mJ*8DnoD86gk4`KCvv+zFwy9v1oXFQ7J;7MNLL#nU-mbn*2L-tB z4>G~DCld%_X+M&@OW`Yk@1HK~=c2Iq{?Aompik8P=gbw_KmKzJJf(quE=a@4+B<(r zl{o$6_nP9YR7bX5^||FAqW2~>-=Q7s%^T%pQY4i;mznn$h;KrCCHe+7pXoJvYt<&W zd`mxD{M!QlRKxb?4E-Eciv44T1QOi-+jQ<~IGlV+AAI}CMmcd8?IaC@qQ1IWc*K13 zBb}?g?`dprEA5EbCpW(C*hSZQ+2lQuj<}nQ!yj(#iSOYIKdh(2(=H1 z)0Ou2KV?30c&l^h>2Nn=)W2^g$Wyz?0}?>+`Q1b!kC&NtBD;5mf}wc-ug@HH!aiMf zW>nT*(OJ899`G0;VBHVQZdZruf9a`GiJ1NRmk12MML2+@pCWDyb4q?V;Md|jC?Ec~ zofUO0i3E`FD}C36NaQgHWu`nU=oZUi!zRy^MEj4XU`6YE2EmGz?8=E?q9*N6%!o=h z2SMU(?kRWjR5yI@Bw^cmCqW_Vf~N?WRV-Msu|{jmn0sAo!El-Zono0kDwGGmuM{4X zC+l)r)jO$(I?bj1Txi81uXd2V6*Yk^*KK5wm+69%Pk85izhaQoii!DhF#Q^Ra+)d9 z_-Glj$a@m*ko2uivBlX3Sh%RfpC~hm%4a-7RD|daJ#N;%4Zi52p|ACFE4vnnD=^NUIJy91 zMF79BZFbO-2h0ny;N0ml2YP>+BNSc`7vtK*J> zg?fm3?O)G7JzWWRJ-q<9z(l8Z&m#f)jFK8lqu-rs(6emS{3z+eJC{!Hz7mmF&to4h z14BniQ})_Dr&>o?@-#8c~<3z8sQcH-7ED+C7C$KNBx3 zuYTY2y=%rdw>mkTjntNXPjdD?L}Y`^-cJnO7(o2gR8@UkBFvjsLe~FpARN6;?}w?UR@0>w-o|CgdS%|Yk#nmO@wkQ5GHyakAstZFJ*OU)_KC(WK`uNr;PGxdPZ92xccr|t z^E`mzBbk*KpzF)R9OTtBv&O-E`D68?+mH-^$GGw)v|d5Fjfn=&lV-y!>Y(c{&@I^C zcpO!Hgkh!+SO%J)PUH8(D{CRzgZ*FhE_@%_p}8@cOHG+d2KCT;jxp(SKi5GPn(6Tg zu92sn(?At;;$ug@+6oqVfT&%@X2ic?aO>XJ6SL9t6$u4=_su0H%7T~`&VaCk*}B6Q zp2U~BMv>6o1|&qP_a!HUij~-sy-XGXYXOY*uro72I~EKkBfec9(*t1=mX~aG5D|f} zC^`PeZ=1@JA1WnL$(_{o8gE?M&tYuHr0I4SGFvf?ObeM4x?D|&HYh{8yKC+dX(ZV4 zB6ZRP_Mf~28L)|&<63<&Se^H+XG4ItdH244n(X3Dum+FykU}wIR_)4wuV!_ZCGs&0 zE`FN~G#a;$Z#`=0pCwmoBY3D*$>@?r^|S4sLQA+&{IwT_{-FoKIJK|w1GCS# zRzJ`c&PIx<5qX%z=f3LURlLeMDbwxV<*(m>lf!;0=>C#WEF15B9UIAH2P4hhqNK_& z^}mVInCxISJ)BHgCCV$_h+%K9A(eg**K$q4?xI24Nk?VhS1imm&Dk!n8AtX|wbW*7__ z1R_lm4uT+;@PfNa)On;>loVLGza?%#aGr;{H!e`?@*v03+ZQ^fz9O^m&x*&bk$e%s}Km!=YvaDqnue1^uDGHSMLXOM1*=+b|8SpYV{ zftxOQ`#wCRWU0ho&id10+^zrnjmjScs4rvQP0USLgOO%BU$DwEHK2D7ki6_;+XbtF zKB!YtC_m=Bv|fK$&3-BCv$3H9KNedVGDkeyKdYVhGIrC-fp)8Fj5*!($^`dTFb?sq zh~jVikNqdx|KF$mVyq7wO%N7q<~>9gTmvD6{NkU_hjh?{)~c{}B7^Ep4%DTvf-tP1 zk3|y;kKS$VL2bh1uU)?vV(99X;8>7_fV$xS!dlh2{CS1L%5t*=d98;QF!BC|s#Jx1 zTqkCd%Uqo~s-%h(m9c3B5_V4XY=5^ORaiN$03TV%@88C>;y#FV<7I zYQMLS2mhzr$MAD|Zu1Pf7e< zGEm=q%F~!$IWDpXSNmjGrCaIxOh4$V+~s7&&A?z2-Tc!7(wkC+$mEtE_LX^08o-kk zv}fj(X@%@5QwbVBgQtQ^_*^Hi4kG!Ew`TrDS353joA?Y47O-;xL@_L8YbY~w8I@R{ zEB@C!7ts19md9#nm!01vg`Q!SRP-YtW*VBUdQSm$5AEBKaE zB^y~oKW`kA2e*bpCv<@CeBuQq1Nc)~+I70I1DQXV^P~U88rDTqEnsnXO!G7nG zMHwG&@ja&(`5vyvKrH~h=cd47=nYg`Pg+V;Ygc~i(*(IrYBJpC%2Kr*if-|O4rK-k zY~|~}n9&`I8m)oXYxumj(V4?a9(8$)p8*4;Ah!lCe5fLIObia>mc|`XO8{WeSHJFy zR(n45OGKqYl5j_{&0k+D+!nxm>23+QmvgUAxb`>{4G^w%Aj=1UR`e1gACy>!rm2~@ zH*~S^#lz+Efge-Fm1gcdQ=;G7QS|RaQ$Qo=3Y|t9BValWz|`s2Nz1_3*}#HnH`!B;bSq13&bE7wcA+}|=7~W=agx%0pm)HDEr7`D9 z+yB7qnQi%s%9h_emstx2jS@}3dLYx%1h@@o2f7{@-tM=!n|XQVRtt4ST+nWBSB$3I z;NA2d9lH^!GsBc90#~4K!*Sd;pSM~ai zP{JnS^bDE#6Qrr>dkJ>H_f1(v(a(VGzT$BizSucod>qtwk7|s=_7SEWbo`EoTfs4| zU{4Opn=M0Cg)6X_2{hWg>atEpxl$%!eHTVfpFN?NP2<9H6BBd6Qh0fU8ty4 zXs6q~YJ=f8u`E|I5Mg`_E->;tq-&9t=#zr?vWY9U}1p}Mb|Z|PIxGmdtV z?frJDK7B!g#0#ksw2jyv#o4m)9!6db^@n+si02FnWW3^Jfm>;Dw2G@T({if4kDNKWbZ$QLYx)mPMtzRec_GA z?sx};>AKN_SjE7#k?Dp`OINu>-)V&B*F%)aDfTpiu9 zA3%XVR_R1xK>Q5|fx=UQKahQ3a8rp>6FQZIpe@;Or355A)+8@U3~W9pmg_aiO;nt$ zUl@N%j^MfO*khRDGNuZ1RD9aZRoXz7qw7=9F#@z zOMcCF#t=5Hj=P*sz^RkflOA9#ReNm2AIrLbjfBRdA)IJ?TR)fbej$;Z`Uj)7tDvwh zYp)>6WGw~<)27YOLtj_2|22aBQw@N`++_QZOq{Lx!_mC)?qQmQJ%&T?sLF~MrNX}t z=27~yxvdVQQ&g3XB7>+w_2jWwEUpR0w?H#sTrR|ap8z+f_p}}j$_i8Q+Rbb(?9UoD zp7w#l-dkujP??Dli)A%*Wwlr&KX-IBS!sPs$89ymZV}`e4YXW-SK6KB=G#NWKMSL> zB^=UvBzy($BJ;9NFKUG=jGFJ8D$70kEAvb9T2CqN7Z!x(-e~f}0f)WbaUmU6^90we z{ds5wk(dc66z}3*5Etsqxrm35a*|u|f7(Mv461kP(z+6Cx%erQ0aP53HX87d&SxgM zF4R~}*`-@BBF-`+bMCmjNp;iDvgPTHcup1pPH=)+Gy`awpA7%K-C1v3P#;`0ZZ+Nd zy6n+AB(MI#{1qPke>8rHmd$cbtGuOz(=D)xO$jW~{VwJeuX%)3FgEyJzdADY-aQIl zLi^Qh+F`Utd-#P@8R1w4S=k2)+pXEe;P~IVCIk&kfG;3I!Z1JA4zz{8Pba8{^ktMz z4OO96eW=Hx&mYsC1P6y95iTFAIvA^_tnhrMupJigA%H|ptT$k%gCnZ)Zc$}ggj@@D zJiWiPkbc15hQBRfhgFWrTuI+tj;&y3~!+ja7Ha< zb+2mLcv%FJb%V^X?O4W#Y>6>d`1a?G=<)V|pz%&pKth?MR0Vz#1}|})zgXqN@6)4; z+2;H?{?(`}bgqo&0);F%1NM4>s2%Md*PaIfldw-tJjTB67b{_W&CyWA+KN(GMawcD z@QW}1f{3c^Znd%9Q)Wl>%IvHwqfHvmizULpzFL@b<6_iaY7rj{K(n1hGrVmpj__f4 zb6(-_EUNBp7g7hMg4cwEyy(aN;={z|%^3DN14(?wAz*LGg_N#wNih#K*|Lzi zlD0WZaVxg-S_@!YgyjpUcz4$SMOa+*#rw&3PMd7}c6D;Ji3LT>UyYQFFTW>^uSdb| zV#fI}uBe!q%V25Cn1b954$o@fq4ThhkwBBp(UZexUup5)X&_)V#OBpT5zpQsF(Y6^ z`Dnp7L*ShpgwC{BeLi#RJSaZ)V1&B${8^1kRE{GG{8Nr&eU5wr{Sn+PS5erbh?NN-s?k<6VrQl`@VIW~IeP7X!R>=*l0blL{cpW6@3+Ku8H_rRCHY5J>5%!ar|fPo*>?_>ih<94ilgx9xyx1Ynek zF$P(u{8T@7GzLAo)l&1`p1|Ft`g!;D{5REi|CI}XHQ@UB$mYu39L0(ndf61a{89}h zsuX8w!I(!)D-!(RL|_Z72fy2&#BshjXUjt<8A_S$%9ym7j|jaRuX8kT_1@O3l&G<)T(`8affLGlCH0!+f(ed*y5mfI>b4THuS&kPXMHOs*O5aB=P zdmaIneSV?M6H(#uNe9WE)XPIpoG-Dn7nSL@Gi*^=@VBt9n8*d5hv?o}Q$uLOzLd|=%9e+F$U0=|&>{b7je#s^pn4_(>*T=5RK z{M8GcmE$wYYUI2n`5hYLV_dU`XASq8HDc8F{K$h17|MCC`Kils>l0DrQI^GtH7Rg7 zxiov|#*PM!=OW68U+?A~OvC!#j&ujzt*oU2BL%^Feu3yOu*RG+u zr^s!{>Ea%zy!hSol>N#*%bL%%GB5Sl9)(n=T70MKE#|x`!<9o>iW@pkIHQoZ#7 z_DYK2iXv^P4Uby9Hdtoe=lImnee^@&idw(TGkgEfH63oZtwq0e@kHvV{uYtEbbC0X zH>>w}R}2s0(7de_+|%ive$mY8nCJQ; z7ul?g`L}uVDY-2+@rM;<@8$8T#SE$W4*ZkH(6$5eNZhLHoSfR3v;T6n_bQf?y!xyI z0Y*{6w6n(H3Dvi|26~Pm3;i?(!6Uc%YSk2t?);LpYENsc@dad=$Z>`!G9_)}*N!<~ zmAnG~<7EB0gV+}q_JPEL4ZwF`jIve?%nOed*zP7}wx_0B6Xxm+0! z&Ct%6e30wJ%iyTG~1Xi4v0hdgC;qF0#oc+WqR`EY^@R} z#0icOvCwOF*98VfT;ipv;y$E?p#p!KGI5Auzs=ty6k5m2QQ%;D7^fXO9S<7!GZEQ; zYoGt1EdSLdq*4XOM8+J!VDl)5t+!RS%ER}Nj%Hdq<*HFR%Uk%_V7_rgEly}E1)^Nu zN6FE6La2JV@3QB|k0}=YQ`frh?Is(BSyH&HRNR`?BkYb~^+$V4>q>zQ9vs^R*;`CED0wP`W*0KI z_73mpw04Ss@A?1( z7gbg1l~UmjfD0Ig0Q<6#J!5P!z~i`BA%HoCL8GKa-FJKJ0i6e6n;}j3K_+DI)#)h; z1uI1Z-{LsOTU&Gm!pwCPF-eMdBGz65@6OkPCbp%|8c*6um*bXC@Gf;R9G6h!g~uh64~lgGc$iaQ>0Na zfyJQt1>W7}_3MZl1?slYPrUahqSo%!ttc^Hp1vDroP8#1=-rI1Pm^y#ex#pVvNJft z&Y)LLw_(c_hTVuv5F|h$pWUO>ibP2UF2u&fn|jY&kZd?yTUOh%QDVRCjd}EeQRVi{ z?aqZ^kF0ul3hQj=!Soe<)|k;5_--N0dL(_~YA5;E1eXQuBT)mYIol;^Kaw#Vuq#re z#2^W}sk0oEz&y?!UsHAcdL@bH>~V31Sl3%Wf%4=j_Si{T1Ne(uI)bc=^)O#_TtR(v zzu4>UdbpuLSmaey%?V@i%qDf>)X@%T8B8j_`>hjs_0q6MXsm+%2O+CX{3MLpEt3jh zH&oBb^1&B&PkmYYC&VfiUaA+uyaJauK6t3-M^<^{Yw!GnC-C zUvJjHI91$yTlL_p25|eIvEV@IFKUh%q#t2 zHaYQaS@Hp<+!=;KZhPCpen^K3Gj#*188QnWj&4Z+-iIKNazpcA#F`2H7Bvn#C$CX~ zf44SDBq`brh6BQ+!egK%l*ZL5Xb*bF9ke~1!IDdE^JL{=+pyc@)%atXi9#7l z7xKq&2xvbqqNI?YPFjsGdUsVIM^>lSr={wj;yDmvs7xozW~uRul(b~;}RzoU(e?Qoi_E93S%WEWkeMi9{%l) z3;t1%9+x@(9qi8|^2&dshN+9zX8fyzjpoHhnEH zo@0L|7Js6t1c%~3csQT2H`8nrBwY+@C{)WMmAe-B0FU_Di`EB8#uV=f&i6sm7slBR z&xw4MS$#Kd4y)~*-ZZ^IjEqqHCoP{bD}zu&WpnPz1OYsnq7}r{)n$h}_iVuKY<^!Z zH~%M!V7)7f8j6O3~G|GCt{XjWV ziT1YwOk)4bhV{P{^Z#kJMC}|9iJ$W0+px%koh)570SSEA)SNCt8d;M+A(h5 z9<{EDV%^UGTgrGjAR=w5rwun+D4UoY6<0Ay>ePjcjo%Xg#pV?MsW$gtGw6bfl)qA< z?~sF|E5-~!@WDtgCQ~G=?+h-Y zy5%OG77QbT#`e{b65_4L+745_tlK*iD0|1Qj`4qRZ=llaixRzUFY>?;&?Qc?}M{pSbpUd>~l97 zIQDU$vSn>AIgK4{bn^NmLd9gfYZDG2lgwuLoNVLGoIOYdVDgn3!T~0{84sJD5mhE6 zEH_cyHVp=NK=zfRgxZwys%gH{7eZqRv7M2Gb?`K#~Oq2TFb8K``nvW!1 zuo{u;wdwkW4xRgQ@Nt+bgLt_fZk1+VfmP6&Xp=WuW1q(5OqhDFAXf?tIQ4olS6{UI zYd7f)!`VUSmzoLd+M?;G>D=#4h+y6iBtRUa91~`;>@Bl&aKk!M!j+D^UikUK7*Kui zMEoLVQ%{%!(WNlx!e~h^fYbHrW1AV(W94>^7IIF3UN?&Pjlp-A^bxq7&IN|3X>piyHmU%HV1CQA^-cLQ?csY=m zb&8~BqgbDus_3-3wX*|gBPciWvnQ42Uz+8r zzb~_M2(K2aw*?zbU9}14zVKKlo|2iw649raAO$!Z0S$Xs=p|d22-QzY^A^>Ak4OO=TWD^wcuHlXjFM3 z$(G2%^$v3F9PqeMwg;23;lC*r4yQiT~3swXhOm*368e)9-E zOobs>Mf)VxNqM32E@r=RN3_y75G7cGIfIg)oScpf@^UcKcmqvV^USn9OHu3E`wa4P z!y5Am3_T!g2K2Cgf~~3IJ~1W_L>?}s$*T|Ci5X7XxJifQTnKcE*0K$weiCD^k=Ft| z%VxIVY};26_IBeF{ej3#+F!Q8QR;Ce`a&^7w* zpdpd)!FG{7u%N&ChHU?LDcIigGQog0^AT8!w~b~G-+_TlG)=qyQBdK7b80ZJ=)_K8 z{n$0v+Qaa8;-=%}o6|2-AV>$qgt>jTvx$CCZi+tJWJaBoDxQuoLj|+)h0_Z|n!Fam zMY;otu4ErwmS-eSU2m_%A7pL%_?j9I@BIz3DP7(tu^|*!#z%G8Er{+sUtiz)aoS1a zM66%b)$Rvg^8EKDzbpJ6r{^o;mszt-z!i{WkGA^ecap+>x=JWc9D#OYKWPl?7=}&E zpaj$HzHl&>910eB^!zOuaX20dE5Z+FK}ikUrO`ZZSqK7KFw@um|qGMv1WONTmx*E(8- zJIKtp(%Ls!J;lL!-1qchVpw!p269DO2sy2bfPby<(dVr+xD$NmWyI!q5*&t|amPTy z8A)?_roTqrhbW@Cp_RQ7+OhuAZ=^jX^)q%nt8>B`ffI0mv{y9Y_j0B9g} zm#UnQRf&R;wCOWa#R53D+!0(AvjWd-J?w?0EtA6Dtw$||&KO};K4)B8VO)hBZ_SHG zhEee#hu=5SG4fi=Xqq>k{7xFwZo*#I8D@a~NZoE@6q z?j8bYtyO`e{Ed|$NOOptTw?L;Le==s#yMl*Fl!^_PvIov-YN@R0R&mNF}oU^su7F8G!$p~EEBWHoUbZ{Dnt@2qpT!6mKnGf3c(1- z%zcR1ehL_T9456}-U28%k}Dw(R9CQBtbI+RtVL8*Wm(8x4l4tX+2-9lw`3Bn#|4hf z7zDp4TqQEOmC4Z8OcP{ir`~prri&9_kgta&DTSiq3f|E-|G_YqzB~@x2Y!!zT#LZ8AN-6D)1*xs^BJa$6}GaPV1n z{z4G_NNBEn?|#@%O1QNVJG6OYFwv#2`oAPaxM3tirH~a4!SFQ)20$V(fo%md?D4v1 zwE5)gObhQ&x=`<<_6EW7#~?!crh%zbEGcWKxj+Qv1Cy(1hS{?Bx4IhwruL|buH)eH zC)@w0r{aGzdoK8n-0Pi<1v#BkKU)IkjcpfH(;j7HoO2^nUj>OkYI@dd0Ph}$^&2h>>bNz7ngH=f^UWLo@KIAgFdh>f6&L`^iXeAXw-75j-8!}tnVjJpl*Qna= zNQ*~%36L~S{`*@fTvm7~m}3%+sV~j~kv4c|Fz9(FXIzOUeABJGx9x`=R(Pzba8meE zbtHLnL%v~~AV9N2%tGyd`OyD_9RKzfPfpL<m&oSKdw2k8<04u+oDz_I)PAUzZ_}sxzo9D#+AP#ZU6< zKdF#^I}!hp4rjX@?$FG#%sp1u%frtPAbHygBdX71_(0->Uo@ktfx9lY<7ZH<_K1gp z>1q7n28p^eu#DAie6sm^)L&r+0z!&7tpw)me98ABK1dVX7sR_|oj}|*yt+5K4K|Px zZJ8^jtE4JXZsw?ma;(c+D8@)8mFvcgB=ekQbmL2ehvIqRGbX>iFsi?Dw<%OI0a;FQ ziZXyOO-b7&nK0lp9?I+73t%polT_R)7=4^Vh>;f%cy~DZ_ylu+-YfAn1SA3+d%;TD z)~Z8CM5+i&qF|^_LRAmz4#J1!&R@rr9h$#_@M$T=Yd-nLp2JjR6YVkTU)+z?E^|e= zi8FHh{UyQ90IB^^y6HpL*KUHHR11yS63_cJexKka^Lw}x+5m}ZJj|D|X75I?-oW$Cu6O;;w>c~yya$<1NtqPE?CcbF zoW`AwWkoxa7zw{fzSJH0Myk>kA1i?M2EsnRj%%>J&l{~B9Qz4WVB}vXPA~#4hs2SlJP545VwE$aNYbi|8m=}_r#u$ ztK9WUOAX#R|8RuDHQaubo?(`qceOo~BH^*9;sed}M+IMo4fePUV0u*+MTa4rLV2i_ zW-mrD$#zjI(q6ruLK{Zh8)Ae%Z;wB z>$a@KQLF(%V%N&pb3-9p&puupZh=3mZ~~PA5_rT^i;J(j2RfZit;ok0t(qpi-~vzg zMRafCd^s<^EU$wc+`5p;Z7>-LsL$Bkr(t!cpUhhT79-}^TqEhLX+FtJ1R1=M8H>2> zge}}RW520de6ZA{Lq|tvagb8$SIzc6XnW77CcABaR73%#i69+8QBXjt5SoULNR?hi z3?NN2gd!aT1f)vuh!AS%UFp(7FVZ1_B+q@`efBwbpZn$h#~tH-WRWqRwPsms zmfxH+>&15;=drH*scV5>amz!-j)VMNL)43OX0_pUPw7*ZH2djpe`6)-Yny&Alfn-q z+-{YcTWpRe+~uP?J3tsQPE9s-+4%Q#d`@=2?@M!W?t0bL)m48uwJW++A^U-!KY1VS z<^uD4>=;dnFH@S3gojk-tnM#C}p-u|<+=w1gc(cXLRN9Hv6 zL!NVO5^5;L1%Cv#2fo|*;gmToiaU$P4DPaT-UG2lOUC~BebGP=GCOs`HqVgz>k+tr zI?vzJEJz1DVV-0xHA$uLTS(h8aNJlCD~hP^H)F7ur~B8qwJGy;k3+pNfpV6t8q?y#i%h@W-FUxfDG(wXo&*%ZPar2w~yldwmma11Gte!Q&bEo5u@*5Q=1 z0Rz*axvy_{tNKpNXXAl`hiCMG@xk5d5$@NiikBZLBM1HzM$qaXYJNFCXYybS`EX7&ES&50R zG0~at+I8h5K!SA?V(lB#%*gG^mY~{e9s`eIeHP?0VPHv+j>!mE?0d_$E*_Bb8K8Y- z#cD?#V|Q6m4}br5*4TeQi?{Z6SJ(2jXf!x~CqT|lydW3&w>#5hY7Ve;TX4S~7a^+ZEtZJGt^-9cwe=1s@(}yeZZcGU-ZQ-Kg2pLB#GDdKKB|8m;{WZ1#d{=xmdl!Mu zhOvEuR=wlg&8w!LR1rw-+MKJZL z)BLp^6`y_-D)D=r+q^-W)j9G0%}370^!Kh3>3o83;`k)~K>0iK?&ra}=vn6Hi9QPX zdk1NwoJ$q=Pb&EyMMrs^{FZSQR->#z(=e_Nn0zq0pb;alyym8dHr+n8NLs0oeO;3S zsjjnCGiGjDyVkjDNLS}}Kzils2FpNDRq#d|_mLgN)0!15a62bE^d4OGFx%smiIgg{ zpnjSHplW=69EZx7H>uH%h(z=J|%ddk^KgI?>YT5og z0qC5FoOd;zA#^^(<6yg%2UB0AJ>t~&PAP?{A*r-FZGRs0H{ayArL_lFsmSEVc7js& z6~*(aYlG(jlEAbvJ9P*PU;En(<#ns-yJ*8xztABMc^|rnoSbaB;2-0=1na+Ulocdflaci7PnRa1-~Tx{uTM__p-^9r0Q>#8Z><`G{my;J6{a^CPzU$AoSYJ z;P9PYQ9n?Et9XMehFIT2a!Uf@f#<7#TQ41rTK$^(oeCPN_%AIVV>Q(|qZkfRrJ5F* z2774<(9XtMac`>ZOpAG)r8hYp`_xu8v!>EmXvR@x9yBiAZtQE~nkACp!l{Mrq$f3J*h27?NL3!=4fLCd7|iZ60gjWaaU_bcl(mP0=b1SlC~cm z#4aj+%Pt}vc{6l`W3+Vpz}MNXCUo&Ec(j#>)?b4kbs?}e>QHX-mQQOjPyigwb1H6j z3|EHh5wQH0yINto{qO}{s4Ioj;7S@e!S0OuJ7lO*;nH_ACww&uPEc&3h6R~8H9cGs z_zg&cFW|?8R0K0$rpP=n96Wz78mTNq;2PTRI)pGiCx?-qwJ4o67lafhO(N00E(Evt zrw+&$(BXkM#Z$!NVs3})?B&&Leb&mWzwgVv^^8Ks>HMi)qg7NtT5v#AJl-k5M9r_o?t~D@ zCf45NCgO@h(%TqU%`|$tARG)=AlCA&UCY;_*=F416!)ayYYtn+H|}1q4$gaow=~ImY*X==V_?dG-S%}&LXhrZ zF!9V8K~Ezm^pR{pa`Ay>PENQMPiHnseumF8T9tphc^ATfd!z6I0$U z1YJlqqtHXy6&Mj39hsP~R&t;0i~Aa9bv?!gHBT7l@y1_SKEa{0?eIhE$K|o>QZ8+G zmbt5=dg1w}W|7$}H9bD)n~P8bz~;)5VhK~_hXaAXaOIq!e}FVDEH$aRPa$yIj8!UpU4@SB*VNHLO(J#cqXZRWAWa5Hs;>-#A`5L=AF z`sJNvj?f2Z;Le@2Al5Ftlul2%!xqPn@cU8IIA@j`>Rw97Lg3RPa&9Wn-u}XaR@AbJ zj`c4W`Z0JW15#l{Q`Wach7fJhDL(}cU~h7vJ=T-&S)E1tyT1E?`#mbmUuGs+ZPV#s z>tK<6g;JkUQ_tbf0dEY2A7!*>)j#qN4z|u8C5gQ!IH#OCwaXJAi1KI*y1*G|0mQ`k zQE^WNs|4*&9~!XA(!kptvJ+qI@k0lyXBV4!u0Sw#KLVm9M#Ci(0`~KvN9!^jqxh_J zY;5>ve_AUa5+SYJKjPTCyE8hQl~#YzKnitq+w4ym%;2XdBel4Dc!wx1*9dclV;3z; zBGlDPi}zE8X=xQqi@*NO#KcMdv9jm&{!$_K@f?srURBZYHe60!ruL^Y+71V z&Bw>G)W8Yd&=k_Yov7WihHZj;(;)<6U3^ba2xU;?AMG=gwQ>QSdB&ye75g^(N`~#m zqR}GI2rSRDpst{+oz=_S`3Km88EU6Ou+B`uLmJ2I13!)~+FwchlHz(ta)q)oF#D?w zAA>qUHv-v8wX>F*ZCYQeq(3-v)VnDrr4E0ixuSJ}K22FB8eH>43~Zs%G_x;K|)okK*Y#WsGgMM~mZ(*tZb>(O6v1c}vE z;e~4txbIV?^W%K0$SxDuFwS}7m(D8*hz^gK2&YL|MrBBV_*WsN1J0807~A0chQrHN zpY5zILq<%{TYBh&Edt+t@J6EIE|sdJMP6r#nJRV3&`S4z6xW%2$i*Q+<1#wE*~p5S zDPsL2#pPf4${M2*-q9wTBPSna`90-|DNZ&p>b&;8xDf4E_Gl^`Y1pTgif)zZf_fLD zdfR%wnbd<9wxikKbltmUCw>#IW-+D-D6yV6qBQkTf5Lx+MzJSN0?!vx@qC~I)jbqT zx~~kk`d(U!uUpRK<`;bJKmbk@D*RX=h8l0)dQds7Zv(iObRXeUz($8h5_J@}6stUMv?=y;-?~j%Ut24x&XW^`2woW4GxzBlsmU(u z_H+62GJt$Vn24!@>sO_kf|FA$YbS#Dy(&h9B*OXlvaqaeiVdB1cb!bk8UVcxH*eUP z?0jl>m|y-8vaU=IROt@K5-$F6wO_!&XyYz0lX}9+m_(TP!6j*NVYIHgd^r^niuY7o zF)))bNuPTr|EfN|cAPhZC6t`p)d|q_3`F&xTi^b!;bJHq#C; zmrEamU8nwdEz8UaH&HWFTcZ)qX9F)+p`r-BuExjlVrfdcn^qzjNBh91h8|1cdtPec z61_QlB>dALwD$$%P`?@~>i6FMb=Dsj;lZS94^YYe z(`uzQgg$J_8FjH3D z7~rRnuc01OcJ{$Jc#FqAk2bMo6leiZ=k_cr%L3!THlC%X>c?o~;2@`>LJoxJ@rzUq z<46KcbjDeWFwZm6Cb27o`vTU5K})yO0npY=ADfz`k1G99qMt74C~Tx38DNzQJbnY? z;z0k_WlpB0A=NuX*0dsX)Vq=*+M>Obw&Ayo8-5h`GeWF+@r24Zd^_d`VnAMOFMgWi zqV4it#-pg0gFtH7akgv(eULX(P|o4`5t( ze@z_nwk{jD@AQa)?VE(@XmNBvve{PFRjfhJoQ+$L)$cnV!t5C}Lgo=%V%J^L0;3HQ z>&`k!i~*(@c;ld1e`vFSX-r0R zaX01Yx>)>L#=C)zI`Le|?j5I}WR3nCMZ1#G(2V@2Y}KM76f?@GMyTK8z9{$&SBzSGsuwC!JyM@N6KUuu{p zut?L6QLAxGE$d|2=x=k+sC~bpqXON4Mh?_{{l|Ovo(j}XH`BDAi*4M2fio5DFlp(jsa8-fYE^5+Q0V(cB zn4CV9AG4#flf%h7&a)GDA`K1ihMNzN!Ubsvw+g6Icy4s2y(4bV2XVV(XyuyoT{OpjrIOU5eT)f_VklI5P+$mv%qihtO3q#AXn^ma=ut8FT z(*ki#j5z8wHKFO_`=9uhkWsGA%U-unv%f~Tpd6{=X)Qz3`3MUOv?cxCxuwL|U)6M?|XeIKX3hZbLxFqt%!GFkT&H*zMYs}Of;R8yoD+M< zP4uPJ*0>c9vUqsF#^q?}l>$?b^F^som!^#2QukK?)9T{06M7uCTw{65uF`=Zl6fpp z-ClETGIRh~KVwcq<|<9f1wbqk#I|B%@+fX_aTl=y*_}is%0l(h2+Hn{_rAOcv%pKe zZlcJHb&QqyF8v86?oY4IO*t|23zM+zH|N5;Lp6WUN(=wwvPOZNm*+L1{FY0@&wYah(f}@Leo;bE=f@t!s4DDO;sVZDnk?~BQgN+{ z@K!`|5ze2r7cj;)`xi>|lNDmNdN^Wv2x&kEUTVjC?3X1-WTFInRC|6*@1>>DT4r{D zv`L>cm;H00Vbnch4g6h)I_GV@EDU(UsOedr`f#WI_f{DE;mHol!H~bwfS8ae8yA zsJDz_HJHS<@V50$VA#=daHWOKJ-R0KO{0nJw_uY!KB<6F3rxXwqmDCW1zIL9FR=QF zVTYUXOR06*?t~p@GAlVkxJZco$?73w`K8Z0drC2D`zoQR!3YlfTA90WF)D&Kjy=45 z-%NmVVA(wKi&UsB1ebCfpLBq%4=^>Ze9>~d&?3d@Q)mQC>G6dbCpYoLX@8Q0etQQu>C z|L}5;oc3LD94x^V#|5lij|%RPAV*%bzq>Mzqb@|J5er|K8PZ@OH*i0HkKSZkX?UA} zL-Xp3;~p7L>Rz&ovs)5xD^S`~hrP!C9gM~;BaHN{2E%T{f&O1Wn#jA={npder($A# zPJTzU+U5r4E|(cn@5=eQ%Th+Gk`B`H;6-q?v!7(5(!M!jYpX@otf49sP!eq3X&haG zo=)F+p$z~-K46~K5hd6-evgk?^PXL5sS_^bT*v1^rF%+B$(wEgL~z{TX@# zRIDHykIv<=ixa_+j(eST&3SjWAT2@rKp!plYL%14{I8jN*?~BHb|Z9mLFq>*?ZY?qUtoS5VE z6-Pk}?4g(cGspbpE4DgrBHCR~d;Uf!kX&BG$_2YspST^v1jL{*yUUHA9%*@+-?x5U zPY}of~6);Lo9RYa!TUFT<(b5iO@rNe_`H)IIY&(zw9MLbuACvwDWDvkJLrvTg)kn z4|Pr6v>EokDl-lDcme=@d?xI20yI(6ZzZ7`d-P=UdjOE50PJ+>P-!Gp@y4SyP6pm| zvR}_|t6l{7@ZnxDy;&(f@@&lZ-Z1^DlxQDi#JC(){@v1t!u8CLA#k=&u&&gq~egdK#7N$O* z#x&Dk=s(8%|HjFUh+d{n=$(_4736Y7cikm@i;$EF#F`Sk{!G#a zW{RbCvN{s4k5N4806KnQ@BQ<)942T}l@6-Mq@&L0G&uYgE-(K(w}d?4h;ITQxwu># zf&@HPAFXr7CJ*?}O?0 zX{i}F6~tO^SOHPFD`$AXlj_5gXq?OHa>ExK5g8Wx3g>aEYc+qr;qBordJHk+ zdcw=wD`p_`qd#3Y>#?TAc#sW=0uByAZ?uPH!FqacjnKMP3xhB=qN07D;~_{sRmNck zf3vAIno>Lg`8W9E>H;HB2Gq&n4_ESaL;EZ=f;{qofAtD6pJO4It@tODsR)~q$e zjKA-yyE&2~YXf1F=#h?s8>-gY{a&|usKVgnirKN-$@kZ&aqM4ca!895T;Ip+3l;ZN za(OaCJD3Ff&LDzU>OxcV#9uQ9+*c~Fx>)?^f4RCe7cThvhuV*IulqMH;lmfi)lnNz zjikfdKhb1*S_|K7UiwhnuObKceB+`C+ukiwA}AeRMxkwoq=*S|rVJOp?Wj=c@h(y41jF$9y9 z$-QBSPuYfpom^8IsM!+L8Ohy;c3$?ePc@o$BFo^~VozSLTIs|SU>Nz6r?t=| zb%A9uz|nzj`D=0()1g`WK}xQ<6!J_Z#YTANpA@GA?sVvA|orX*O2I4wf2L+NGt8Bl=O2TN20HaA+3Y4AQIO ztQkv=Yp!~vjKjaHS~*4fXj#pR!n5eN-cG_HzmEU<&e*a^fsrMKS%O)HZnc(3%y!$b zttq_N$rd0?JZjJEkT zXxyZrE5-bGFMy)=JxP)k__Y`)QPvuqHYi}!hxXli$PachY?TDF|o7vavk{<{OD@g|D z^7%Ql+TVKp#fL=MD2?`$_gt5r&Jm}e7p5pk!L6CbLMhe57@%v=5N2~f zM82DZRP5UN$b$pezWlny)e49;_R#vZ5wW|`MOnxiW?#%&Ij5hI?HciyS4B!KiJKK6 zfOr?Tdg^((wjPSEwv@?0er?mM)bdZ`gXHm06X*C|GMnmuE(@=c=qjPP5r*++Kn-3q z_{n&C+&kmu@<=nFGrWSt9}#y}H%=gZ5mW_8=%GyC{JJ%La}O8#=$2zQ&+Xz{R5tfP zW2hvW{goaHd@0w2=K$s4yWx7X>CnRmc-)mX@1fvvY z-#LeG?+HYPPI!@Lb7}Oy5FrEe8(~79rbAh3G?IiE7*&@>>fx*YLP%g{pPlL6nqQGd+qCdm%8~!2AAxsvzADJZI5t+%sg64+>OJJ>jJ21(aI+|HTcqdj4+}P zS3*KDX)#y>eZp*^Dt3QVlMD)pSbx$p^sLvZ5Ugc&?y8J@5j&ESe0(|T@U8vcJO&JZ zSL_G#z@m$NYG9H*a0j^LuLp$3ci|;Gu=&&${~6a7QI>%hoKn*?c>X~~k7YD6peW?I zYom$NASx;Ev;x|SPhtdY{58G;uV@h^!YG81@~6U{-kTx5q#b31!p{Nxtw&)OLi2V@ z2qU;5vE=Bn&fMZecJm*czE# z2hwC-scfb=-NRv!3N7)i>Tx2p_!P<;cz1fF~*(+N%KunW!k5EvxBxsvVi7U2@Wu2y$ke4&i#HiUy}(0I!mkD77q z=7~wUeYZV9>=9aF&OEn2m8GWl@9n(o?wn#vT;ITLw(kmJGD$883#q4FfknF)-)SQ2 zd>p4PHNUs>_OBMcaK5UAN_weDji`Gz;u5MtBq>OszoBuZzfpT@>*I`1>W9`U&RF|# zf6&CTILO1x-)poWM%@b>oNAVy^m_UnFYj7wUQB#fll@8IQct_iiz?yy=p>6spK;77 z!pJ@DJs2c4_J>U_e}c1-u**>+1kCB-xBs?HOM1Q!e|hUmSWX)oo6B;t;+H>a6PmYq z+RcgmH+6R!k6wZXTJVA$&$sN#E}Ayc!>$1BE%a4;F@AlxPT-B0`|USmm<)KHJ$w3* zgW)^!u?#6{@&8`Cv&7DHH`$TG`NH`Jv;q){s>Hm25Hzx+A1{J)=0f+g{KlQGw06`k`D!7swqyHY@MsNc9~VE2MpYo2B%JpXB?r%iZ7$uBi9d(Rme zU7i?Vra-<{9X-$sB___|BYfcFIAp8LaLHSS=$E=*7ycR;PV@<+2`lgJ zqp3$e40RvOp>~b=b~AX;MdB*lR#!!BaSXx0YTcN5x6|q8>Ea93AYRY>@d> zK9RV)LPgnr+(3sf|7J@tkVC%e{fXGv7Lyw~>#lk$WL9;`z@O^DpZRdd=j#*DiJ{Bi zS(HsAAR-g^E4kdNE;6pF9r4}%awXB_A3C9TdWv*X>An)9o#L0SeU0W#%DS7*6VO9C zVz%}w^3`)@{ePAt>}9AC2kUnik)B+?33(bYOc{X3^g!bc0xqiO1Gp_Gwnag-$!cGL zE_N%Y>Z&>|{;wF63IRrEsH#=QZk0)X{6ZyKn}7`;8>x&$L7%5YBo*I;c|SZ-R{faG z2q#`heZO54|9ff)wM!z!w?d=Q=1O;Q?POF<1Yo;;e(BiBE@oXNYf??fQ_7R>7>N>S zc?7oT`x0|Q%+b)?6_8Cp7k;l9_%0mNl-2ky5{%k6r$DT$!a79nq<=o)4dKlkV{ZVW zegj1o38ZxnFtKjvljDChZ+WYyGQ(F>>T6vc!=>iWFA$~+w6=n}ZU3s~V*&)G8Jccf zvB6Tqi_dy#`n5MR-#pLojVS-*CZq{8zI~m0&!!1365+w3ic^3;zlb_?jA!`f0px80 z{O*SPPa*QG;>Yq(F>4R&$KELdnV~hFB9r)_2mj-b_iEsdO zNi-J4mo-;~wIyOV4c!>q|Nby>?$T(rcPp1B5d94;ikTK^i`M+UlpH&A7u9{QG7z9r zA$A<}w9sB&NPU9y=AKcH0i>@t+e_*8w_bmKxXOg>^P@Q_+M}J*0-glI=P!E-L%=zu~#(m3?J4B+2wR zsBwqE)ee2yO*`ey2VHy&j5GS9K%8<3fbE+7to6z?anS6|7YhP37Ez^qE|(-EW=;CF z-%!y#^rWW!d$e_Du*+VB@WtWj#5H~dmzS9^*kmA`c-$P*XG%ENa2%{(S>07WB$@6p z;8RZg{^`-HmFRe`oZ+M>D0$+(W_8&a@+D>w1d;t=sfo!p9%#a8P600S)&5H#FRl20 z-G;CKZRVKBOn=q`@1Wm@gAzmLR4~+WE;O~eG7`#1R{D+5)P|v_Vt27XvM-7k2>I^>>_@_0m}E2^=$IuFBEI zC8w5XOXh*un;dgn^(%;zt}JVU0f=1CBQ$e;sr}KV_a44P`G9ElMH4o~aqt3S-6u0u z`baTyz#Mf~8dEQQutZ!v6qyF;EN5hhN3)6#w%O zPbapx`G5dKK73Z5P}CPGqQOt{mNW#n3@5!A-Bcw_?H;Zp$$g>M`}$zV(uu{B;f@GX4yi*!l`Nf?i;m!ka0%X68by0EsjeVd&T<#Dw%k^W$j^Tsu$7o6{eaK@6^$xG^n zf;&qqOpb*^TW?=j3gbq)lmbJCwWPHS`!LOdq#?S88^7TEg*UG*4&e$Nw!<8l3mnn| zaSv(PKaf>#2_>jctsOwOE&Dw%LR&dp!QEq^uM-8-3;BkGzdsd&ukBQ9kZ2CvC^ey4 znO$t`=lZ;lk{3;F7L^qn`gpUIEBZQfWmxeMKm7+9dsaMIZ!gp;?OjX|OWq)f%(Los zT8HmB+8#o>VMj1+M_eIR3990$hZWH|np#L*BPl~e?Hf-pCeTcqx3SW=2tO>Zd3>`F z39v*8-89xK$7wPfaqBV(r0)N|tL&kRx0iM5;mz{esi*w=L%zQ`*- zgT9r9*~K8=?O=QzRk2qj-Gdum8{#2_i=65HaCSZ+ znNR&wU4lV5JbJBw#hjH;EZ6bsm?Q0@+l%qiF0zU)xCR@T8(NgCiSia)1M%9LiruE_v=y(V+Yve z2775-EP3B6t6kYT;Z3e&xr9D$%C;9GO@01$hKkUq6VdQ@kP|;-7)#ANFd!zuWWt1d zepA<_DTznMO`LY(eVl2|sjc+ySp`v#uTZ7kBaaNB7u#5K3gn;EKangoelUG?Qz|Y# z!PW;vaH2p4CCnEYk1Ai-WTrF=i~2-%BDqhO_wt`be7bZie&Fb=3bJ-G12gniCS6wX zekZqeFTmre~xB5}*|0eN zRaEsRzcJ0b07hFbNRuYz_gNt7z=dQE9&jhewd6Eb|I0w8YCZmZDKPp^s$P@!N8H1C zu%X{t?DKQwYKjr6d9VEz4SMBM&BC3@5RG*x#Rke@TPB0p{WeF6|23IwrNz6z525B~ zO+qG#0pFj+W-oAO0jfSeJ+!X4Rapl**(bMJ6%&^!JyN?MbpzJDf7QRkuOIo6uk)8# z5K;~v3ighb(cKq|1(?#_Cn$KElT4s6QK6)C+<=txWEsa78Wc5VvhfV53 zp@1jM6V|KLH7+x^C5z$m3Dv{_)_-62KUEPlE%kO%CxJgfC9`Q+4XPVC4i~7&glN(K zY`evQGQXlF1E=rU;0O*lMoT;9Uq>JEn)#e+W(5+Em~r#oyhY59m=wpKha^uvSCca( zT@a2x#f35o)OBsk5xa85NKd?gQrGVJ(9G6WV#i`lYz;3}({fMp0-gTO@oVB%2V7TI zpG$`I|rm2@0-Jf-!4dAP$52Kz^l1#iwgzZ(8A;0pMfy7Y<_ z3Aeu313?+S2ZU3a3hT_p8X06$NGNK2uXMAEwDO<^samC zr_{x%t8!$dR-`XEFMR4{Uvun&_rrIA?V%P?lXnAeP390 z3V{;+&88&APf`pe*5`2C933xlJ4fdCr(-`7pp8VRY~&gF~+Hm)O(8H&rii#678Zzj{d0ESlsGB zOKm~VJks7l7S^@)W|AqdB-)%Mfz1j0_Aa!kuqN)&W2L@Bb7_K#6&qSHq@M21X8Dj| zTJQq}nPd?95f#q_U~-Mhr#V2c&Vh z;gHsCUP6FZT{2;x&+1T9&rxNKBK#MyMeSBHf2E$7yQkF`{*J1MyKcstq-o69Hho_4 z3nR4-*XE~_DwuPNWD>K0c`n>+|1#VnWO4&9n^ff*%tWhWIWD{K?xVHx!SL37zS-R? z$u}dU<0sxs{A-oPxza2|F@sHcU%CS^W8qHWAb#eXOO)zYG@9D3Tevx6*hdni`g_ub zT-cK_H6{}=CjHI|(F^ej51~nqRqp?m(6$(OuG3seo;{nYH%NsP{i0h}(9h;`pF2vv zlcn0X(&kS~LW01T3#PI!1UAywaZdOH%^b0v5PmJU>fdsB)9Kx3BBQ*-!QNPAzec;g z@Ku9yj7N*;z>NkGTS9YX-y!ssm1z{hh(m3R$>)BdfCBR`KazL#M5J?yhP5+kHv5RT zoQ3TL!9Pc?4v8(jX(o#jlcL>gdF8PBblN@c-015J39AEx#hCTG+!jbA;!89u6H~Ih zH>cGVmYU(j3b-RUGPcGG2J;M^_X6-A&^hCTLLRJeN%Vx`(R1>rb1D2)rvFfAMTaQ9 zN9qsgnYxw$rC&OihA#wJ_zTE*;ExKYSQ8S|PjmM__d}9F^{?*)2JijD9<|zYrK*YU1c5iBYo5P$n;?UDRQ#ueMx$3r}F#VR?FJl@rU3k zq=LLO{-FVBrEZ{3bDmSa%SW1on*qt(FM)>a3lSee-G1OZLqjKXK60rko0;&Oi49$I zYWgQV-`)@VVcSHJ4|(ZL%W-{|1nv{fXh4YtELX9}{4nI}B1vs0r0zLN#U&4a^MPkx zw(wt!pkm7C{D(dC8RfqoiMcX6NcLXxjXDrh)kjs@)QF5NuyiYF1gn$!WM5Bz-`4I) zL;v2BYt}b!y4SXHi(|h=riM~{n!h7=XjsA5iH=2rQtZD-_y3ve|3hU9H=X*16jFOG zF+kjT>59e{Z2sC1J@uP;-MsKe3D{WqcmV+GpkN1^^m69Sn#oBm4(z4sY!u%_mDjYuQu&W_}G7}>r6i~ z=A@)F6dhV>5Kdu++veUzS6KHtc)=!%g*EaH{t>fV|0U1S0VIoCPP?Hz=#K$lz)|jm zQ=c>;;zZ+os7>wsY7e|C15eQWjY()wnyV7>>4}uqL&dy3&(Kk)mksMmO1(MND=zj? zRD8Om-_U803%m~}p$u=>eNHS+8c02kIT59pb0j@_+nM*tsfCx7SbFYTuFji5h9N=9 zS-ok)kI~1@8<${gI_jNY&nt*E6P3;le8u039KT~y`29R|=La{7KHRCH^ZPJ31-^`7 z+kliK7-cnAAZ58@)v!%zypWhye##J&A?f@T;UqQkNtdb6XyqT7=ajne_=m|?UR+nm z`v0BDpekVqr>}Yo6q2g4DHAb-)UTM^)Cd`|KVAUw5lC3c1OQKMvkXQ=K0l25R$Tlr zA}#1`!PWbktF_Yqb1@1Pb`~PsB%f<06bY9{6AU~FT6a5ttW9HlY}-(y+PwuNyPsna zh<*uaZ}AAP+o(f}X3vSeI8FB7jWZ>Rop-+8#u_-_yD=jYM)JpvPv!W*I)qP-gZdiK z2^QbMnCVU%r`+k@G}Nn2T|GtU;rRx8$8nbYhIhP)h$H+oK9}Q0oe|WKI(0UQ) zcQ^vD&i33*G;wN?*o8Kh9$%Upc)}*967G!bY7OejtbY3P--RrBiyTwe=H+rlC`YV+8m66 zB8(gg%G%XWA5MEyn04P`{$tIu@~``ME*Hd3W(By>fw}$hC_MM;03Bi(G0F|qSb(nw z?1Q032Yt<#;N$kLkFxQVX;J_5%N?7(aVG}~1(tA589gi9c*GQ{gDf3)w!iXuF(m*i zj!K5#T&=O>ryAqW#VO^-SWy1eU3B@`6hlngnC*p6Hc$92=0}DerqA3j7)V-24zvj4 zX3kPTzD*DZ+Dg-m#fvlv*?+X=cBgM-ec{s9k?Qbbg__?j)htl-hBHSu5jm{-9y%9d zoztHhD{#K-o+Qkhe4lKkpofu}GFT$#DcaTTO3i5T$+dJvp3?8Sl;f8CiU)4OyDXdx zT88ln-HQ<{A2Y@O(11$U#H)m}l)nvkPV02YrhCr>5@9-(?RNq>V+Lma3K>aKE_~x7 z!-4-N)jx@ZBlp`*!w_uI>B?@{r7!=Krm}(q7%MgJA z&NTQ0`P&di=T;|`p~q?W__UV#}K1 ztmw(sJ@!qQBrv^Ac(W^B4OOdQ8phx=Mr#LLtQZAMAvdmEXSq`EpmSj+Lp(rG4j< zx$c5~ak@vU9xGn|X7Q(Net%v>N%T4FW7U)@t-`^j`PO+jOAU1KG_lmsJI%C-(CIp4 z#Xk0N>5!ImwXS8PSES-OmlOM+d%$`<^z-*gxR#^|1F!5FIK*cK@^|wpx|-R@i%r8z zo-$eFMvDS3zggLCFZ;h1#4IK1i62uLGA2-};M%RIYTOQt+72{;j{U((>PX$N=XRvc9 zPf`!V0EVNCbZW^B{!wa$VytF9290H3RJ1psrgpuOw&2=eWrtHlU{iXj>BgVSFeob*=I33`(l2JUw4xuA=5J zQTXyA9@teSRKCVhMD8!6|6x>3no$o_Xa0!8F1wbcZq6|6o#|04ida3;>Zu@tR}Fh>$@tpo;@L^H?^eTW(Y zo_mKRxt{1wGd}b-ewb4(;h}9A&~t*kpr=CM4#+>~ z!2d*^_g{)FQVp3OTar0dBU^hcCpuk^>i~`Co_P3Y&t9&D6%n0JI1!)3@Wob6>C4{{ zl(`<$sb+L7LOUOzgIZ$rf2bwIjcP6@kEj&hfQ-)Ib66RPK@zs_ z&8Om{1h!_^oN1^Y$^q!Cn+Ri?Qb}6q z92{7B%m(+$o_@l+Zq8*Q02Gz8^cCNy}QxKER%Z*5ryq&m*151G{GQ$e%s?k=<#XXzP_v*I#^ z_m?Au{oA0SX!arZs~D5Y!tvkwoDj#Nq@nMrfz}Zn*c| z7EK~du2eEeAgESw_US}0oLjPc!f6S`$NxSn7^jQ6lK>&M zL3$;Yr@6~}0YpxNf7_B==ed|!EPMtgMn-Ocwf}(=S6i;=Ub^h9$M)f3)?Pg4=N@K_ zH{bO!Cai-KKGLlW`ZAG6?3G3SP3~`8*Im6Z#BOqz-&v7=9Ll@vd>8H-`&gCnbs~(a z=Y%?JtOA+HdBfP9(`CC<)tL*AuOwSpvgqD{Vi_CbJ9Au$t|>NyWtqSgFeqGnzxww% zgv$eR$Ve5tqvg6eI(JkEzku&h{?vqDOl*$0m|+Ov91EYxFrwxTgY}?$eJH1Ni-utH zQ>qrqevQ}c!*SYBZ75e)2`A=$8#uwuBP15I-C;k4=3)^>Pu^WWX^xFpW14s~lTwha zMRi|;yg@ia?8?gnXcV&5v%c2ia8ti1NlXu=|HJN*yM`Fj`@xAXS`1MU#bgI>@y?Fh z?=F~yUq2l&sW+EFW(0dJKF4nXk>_6NTHQ*)w{vR+qwN$|2vf6@+hW#r6~oeaUEezJ zCG^GKrO^=lJe9L+MCb%(`~CWKtMLF2oW&AI#jLYY5C=}N*HuEzhxC6^*;t>ePSA&ze(Hd7L`K=mDN2Wa-LZ`9DXY0)Da(KLYuxm#~AJB@=dW zVT>z^9);$rPxFJ7*-NgDjQQ)Di$@cGn@-&$#@`u6_Hu(!W8f;+aY~=B*gT&>`DI`M zdmF3{6pCag+yL;wFz-pz_DNw6H{IR`} zb&of#*FR$W@JhKw$B20PI1b{GGp|Ka`9enpY+4>)(dX5A9DB3{T-eUkdt~&WCK>g} z{-hBMrnGofo#V=AAYnJQqQ~CWhZgSL`W~|s6$tWF-Q^;@sGo6LF7|Km#s5XwS4Tzl zh3$$+C@s=03L+uhG9Us10!lZ+&>c!h42{yw2*QX+NjC^GgbXd+F?4qhFmccC_kG`8 zcinaGy7&8YX6-X`_TJ~+=Z)ui-WM(S2qi#*2*)c^d3C%7>-k<@S8cg2z5sP`GYXbH zT4bIiH19y{Ap;KKoM=twV02EYX(Pj7sAaC=y8AL}_r(niV7dXonIcNJ?Qt5${MH8; z1P_tDTutCfEREF!RRC3L#7F_pUr5+{_YIM`2wRBaKX!h*2C#EI^lSl=0}0uMls2tl zoSFwMn$UqL%f5ocEmPMy{|5aQtTvI@Zp=BxY47Od0HMVl2TQt1EXrXn!j5eI zW-75bGrN#&dfqds+s2B-{4d;mM3EB~29gO}&K+n}+5;1usB9ygq}k-yi`hgHG#3T@;|M5HlZ)Pt}JTxPp5$C#623bb3b!yv%qN01#~#~coSn|$lbfvKpc z(qej7RCVv)qF#^J?eoLy*OAAI{i9?#Y#D_?Axt$3iQLnWhb+dg^RN zzY;t>_XXC3&W_<}7c%sD8u@^h>z}zPllS2C)T`>B`)V+Z*b@VdcDj(J%62axogHUX z*himAh|MU(DLD_wMFs*!(nW}?%Q_5}-XmvVStncXtj5$q65-ebNJ>`u6>P0@4sgeA zJRMwvxeUIQr(!+P33F^Px?SUt&iY|16`GmXCh=IK)$x%(=H{VaIM}4M5u;zSqsQad z#g*r+6-i!F1~b88=mb;fS~vnf3Aflr5r3!z({;jEj~Zo93E8q)Q{=vuGZwnuD`PPJ zW9>Jp8L%_L)?q*8UZs|(AB7ktS$rB4y()BY;G`dWOYT~Xq)mQUlNO@L@|4BJad&oh z4LBn4MjjNxwXpz&7a)QBj8!0V9gx<^!Lr<#CwAwcb-wD`r%m)Pa!#53jhmtQIazhN zNA)$l9kJ(gm{!+ckvNCEgna{HJ-^Czs-E#|KmbQv)Uvv6=N=Bhx09=V9cS!Bw&7DB zk(vED`!?1jUP+KW^Zd=D3zm3@ukRgTcdil691&kGROG%XW=ng#V1=MP9Cqz9=HxzR z!LQyL;hee$6Kd7uR)gM>Ymwk!-H7SDUqW+HaYh0;>&ruhuxe!-=PxMQ1HWM9L`BOZ zQe5e;7CD4PH=(X!ASnR|a4O0S(|X)!lO||{xya9j9!;$&8WzoL|Ipz8V&RAMl!Kmh zp96_5;O0fbazO*)wsG~c_ZTt)aDQ{8xRL%VcUzvneb#^sY961QqH%%D99o#%n4ZZL zmGg|;iFWr@LxEzcW8GZXx)G)RY&Kt`*k5Gd_gc|O!2a0AUFhH{Tn9X@JSMIwdi@2$ z7$3Ia3%X;!ewAI|Pk4^8I}rxRW>wR_j%|&atYhNIib}R#wBm9x4pEtp`Jr##zj%zy z+&$7~Bns&pS9e3}?c>Z>96JBHEvTCGJ3(UW-rIKbP~MQIf*kJMx1hR*M|nAMC#T$p z6Z5-KsNbY!&!VdpX9VDxy;lA>#Adbf?gPO`&>V|7Et6YHdb+!062x_WP4w2IW04_9 zPPsQz&FXNqwiM>g4JU+T!a(N2Eo0r#I&kPZYyIg0G+#Vl#}!QLXn>r*0rwo@XpY$s zKiG(zz8}JvhD}juEj@;3o9&Eq&=1VnKQC~5BjA${vHV)+6g}*&x7Gt81&(NgQjA6y zs;0G`72MA?pAH-&i%=W?*I8e-aQHyF%WZ)C6da@dtpEiN#a^OM0RWCUws_uS)1}&R z!uSE}-Map53bd`$>u+z69^-=)TPY-h;Tl=n1vvCAx}i#;W+0B_1Fr)DrwuuOW^aju zr1e+#8_Q12OUY`N^)u(tlBE*1@JPkE!{2D{CV~cA1A)cT7^k}tKO`6+=Jq%z$83HU zd*z>f^ihp9wm+|d79w*|RwJ>eUJ3n)6qdQbYQJHdIK(x7M9)!Zfalp60m$Fyau9Zn z86A4zur&Z*AI`{~K|6WHS>=s85_m}0qL&yqQq zsf|A7)UE!r+6~Y-?)MW=&;j@Cp}6z(D}m(HWK0E#gze@~_b)%hfGDmR*@562A3BkG zB49$xgtNJ^zzzT7s$cGnh9ymzdS^M0#u>FU4RKehc)h`1fA(KT-E|$n+D#ZLp0DU! zVG=Gab{L((v~*449u`j$a2{KKt}Q?Uw`I=}^tJWzs?RQ9MIK^^iVn_k->d7X(d|&R z_0Qa31jL0 zLdttT1gq>eTuIm_T+2zrBHNxs z`1hFM$Fi7AFrz#%r5{Q53Qv*nfs}}V9g!?1JnSvwi>^k=IN=rI@LNPgRWb2h39UKw zdQmYosk#!3?+iBu_0QjnxRL2U5^$M+fbUF>{pdWPopxL=RUG;t z@RA34Vc)dNfVNWm^rvT!N@cIl|KP3oKK)3f2Z$>;gPTjc%BFYSuj@!^*m6vL@pta} zRxcMDuuf3#z|h0ET*r97=E?QlqncOwTbtH`N3;R)$0G4}CMFbzt>$ZY)V>A-*ysT< zp}Sn+1X}Kof|X1O9Reg|f|=xrU&&~Xv{N%XEHT3r7|m<&i~i5E|92PwfS-qca2pVo z6m^BoPq_ZV76-+1PdeI7y$Zyq6PT8G9(!%NGF%WqkNF5re|oj0%6R+v<2afbKr!Kw za4=<}_mA((es~S$tmI5JK-FZjDe0@j{M%$vj3%X&end{51>Px_C|{m+V$#wMC<)? zkaF{i^feBv0^tJr1C~VR()Jx2bu2JDC>(k?KSF)8c5XJ*GX}zO=`!H7<<3X^kASAN zd~0}*Enj8-AN<>UY z%c|7~jd`HMBk~p@(J~x-Ppe zsCf*pzj5%}nSf6y%^;i3S!Y@{ln3LmcfvPl=|cjqSWNU z=)L96lkH^+lHJ|s;Y#tk?~m@N+%ei(LpWb1xfcDEtvJOcpC_yhq(ycygkG;E zB~cCNFbY~6KRvzmCLZSs_7x0C?-8y@Eo-AtnRI85BTw%L+-OkVJ zB(0kbjlW6pKp%usGBW>bfwv3>EEAO__NiP4PX0m7k}eGs*MsIqKOK%Xor!QlVZhs~ zw}8xCe9#5Jt1%=_eWTfqkZ3L0O=k;n{)M^5v7gFhENAaYt*?VlB(4nZ!FwSMLNQgr zfWMm0iyq8_`P~8E;$Yu@^^ei~2=NLaWH`kw#KJHKPY_0?QPxrSRzc@dgd3Bf?~y|k z;Du9J#GP~P7$I_vVE)m6wW-==nVIF4=zF@BaJekt>dQg^`m8)lEMXhii;sC?VSck& zW*86m1E*)&*DC-A$j<~TP0ytsCTVQJj?tEI3bJXP)u;jODEqkM{9zPlItU1>oO~=5 zBbPPKxqb`v$IZOZLy$kc%C^5bjB@_CasKw|ac%vD70w~`9I+=Gq>{02`~&-iD+=3k zj`T!RKmm$dvAG~o=Hn@#EG{C>VuUSrh8!UH0D+t6#X)7o)r*$CJlHv|g9#b-bae~C zcad!j$o)}LOko3tbgD7uhkawyKEGD4aZeh|FG0;!j~6Ln_pqCFaN44P15=)1gf@_* zFdqBC4sC-(`f7zd1=Ho+KChG;Xk@GA-+XnVO&2sRMG~`l;xVks7+KI!01!!RVSw9T zHTGs?S0LX(eM*NbdPFPw?a09$p}Iiu{ck8t>VucV{r68SQDfZ~z3mM--Qd%xA2?=Z z{72e&%ynu+L9sz`ww@yP4tO9W;_UAGPP!MxHh*Pj-Y;zeX)0^g>aOrY*RXkPR{8Kt}bVDO8RjL1Fv?RYoRx(ty)<1)=IdSBe@L4 zN!-j3m}=>c=BQZTir=nautU=F$f;zLJ8?oDti8=G-V}era?0Y$qX_YEV|1-QWwpUgfpkPcD(gogOpcoIHMo0h$wlcWHIH*9Q6VRB(W; z?i-x;%e}1c7n{c6maq062(W#<=TEmh6=%fv@of1yU+a&|9f-a2ETo5-5sAHaS39el zGEXTe;F|FyaLqS*LL6A@|1+_5XJYnlxQKoZ~#3{ z#QB3?5k6|)9-e2iL5s?+r^Y2TM8Csmz#mg632 z2C#N?IQB71dy;0=FZ{k)lhi%?T6n;Z#3`#pxn~u#?Nqtnr%l1e zz3Co}l+e>Yq4>>nc+($ZK}SnJWg0`E4CE8$Ie7y=5MFK0WL0aoTnH6cIsk~;;0NVT zgVyDvx%IG4pwDx!9U4|yEyp9+Zm^sA>c_MAKRN_Fu&4EWZiCeWX?+%f>DX(~LcA&QS#lnjDa_e$Ng9#_~8A-4&_qB&&OOC?vHgFG?F z+X` z12|F%KmkUCUWdZ!IJ=2Zq-zx(jbcme6v9I@o9rO?fJApi<8c6f@UJ70Gz_SSq|55( z1bmX0B(->n5Bt2?r#~c&$c6-=ep(bQs0gQ--hf|VDoWfEyVQ>WhW6z8;MvHK&l;d8 z_=_mUuJLggPqbUfUjZe+iks+VWQAk>aLh)+5Ek0+OoHT$ZT!h$)8AN9Bd?oIcntzb zqvl;ZeT$W*NXReuCh9^&FwZ&s{~DpJU%F_N)&BkRj49nE&4%O|Z$GZ_V`h_3OxBK5 z!(e)oPsIMmLNj@ z+ZP3(*8^~j4Of=cXHGW>F^s*i1^!E^KJ* z4b8^LLgQe<2X*f()9aKKhvx5mS2KUv-pL*nN*b!qjE8>cKZn96toFT#!FWAfd(vW7 z3nzglK{P|7^IRJ4mlWCQd5Ib-n#_qcfxW00qQ%AnsjQ!uRYA>`Jl51X>g%{(M7a)Y5pQ(8{%Je&|r5d5PP?Lxb7AC z(`qEdEK8xW4pv?+Fb~aU+kDUzvzibbI;OzwK%aDvcLYm*$ei~4*(&=TKsK@3q+o?{d6II$#}t%MJfXYts` z^AvESYQKgF6C~~%gxrd`9b12=VNnX}D*rJbAH;==gS7hQ;-)0xSA*A_jqd6p`aQt) z+SmBhI^-Fd3XyP%pRr9s{hOlxmAG)r6pVLVuB5aKV8M-t<;YSBiV)%R(_gJow=J}-~hR#k@D5G3FAhe)qHtQTonfe z=KO1b$=?KWD_JQ6*On8BZwm*U^eRIWSu-k?tUk3qpvk?DN%(mO0-iC*bOQhr)_itV++Z!^!P4u%| z``Z~1%n--OvdSDmObYs>Ip4mTVhGijW-5@8e=WG!P-~mky*p(B2H|2WYcBxZ5kR^GAl)Sg ztcvs}#J=E^Jp3VjTeFpXRrEF6&kUxTAFqmU$BJvBP_Ct*7yBn+20+rNZCkFDI_`#9 zbL7L;#;9M>@D2z<`17;$Iqm+0Z-U$D&Tdk_q-G*>+JYNA6b|cMUNq~8VdFZYFPx${ zKR|3JQyCG}^-Q^8#b$nOUnHaI*q^*}!56QSakO67qpY2V^1BAV;t8Yq+Me5Mg^Z|$ zqlI5K5!t!7>>hcI9_TW7fob)uFcf?qnDR;ti;TBvD|Ran`ucruq1-u7+uOF2v2M92 z+^Z6PC^@6s$PAtyg2ZE1hph9nr~~o#JH#zS9VDY7%%E~WtA~#|=UlpR-?!p4>AC-! zH3$img{b&HJ=D2cJ+>OKXu(94eyJC}K3&s_#@<7*oz}F{GSvV{WuayueOU71bF|Du zIRZO(`|4>4Gqe_Gv`|5#kjp>WkIRdkHbBn-KX;OAI$G@fu3%V`05iA=YFmsE5| zscKwZWH=89hq&#A?6>DOb+s1%gv>#o$7itxz!I;F8z{~=`GybG9gvW|6nHmN&Crtm z-WRXu(C{gB5mz5lu!jd_)MrTtxYfSKiFuK36Jvvej7i3d$>#|CfK6|f0KJR%IMS3x zuO5OuXk1RvxA@btjDK=xS9@!gT|$@fW&& zSL%kYTXNSuoue~iLvdM8qR!!2$ATH`xVCU#^h9J6tJ}bRIpiPH{wVj{f3FVx)5?cS zU}*zNGij>`zCXnxeD>bx&M!i16^w?a&Hz5^6pr$jT9}HFa>1t!-RSe1Ph{vIbOH%C zGw#GSxU^~@DF9)uVGr5l*3%^|n<0*#Lq&MoiVy5a?5oFsj%Kz@{1~qJ+lqUPv(XLS zRoevY&$3ZZz_*EGJ3=@wao+LTJ+9-^v*!{0IUN@v};nFS)S5MNXs%A z65dQQSeOPXqqrrpUhmhBkn{?{sw-|qoiBW-0lCvEW(nI2i&`v5Qj&ckDpw#CsA&GA z8qtZz0=(RtlRc3kN61{QgN^{MOtVL67t+GtVtp5&ijl;-DM97xL>(t58YA*$h=;!7H5q2RaF$pA+|yEvE$7gablEg2Af+0$RLka z%$*1|G0rMA(j$Vr&dwD4NCI6Cb79Msb9klAiQY+xrUL(^1u!4aCY2x-+3<~_#C($f zx3Ozm=v}Q4)+ou7KIXSn81th~(S-K%U_IEG<{fTEmV~^GZCupSj0*(!T(%lwD{3P zDYssQJ?pvKq5_l$s|V*J?3N7kk- zHz`ju+1)PP%FmD6AYs;zr0)Yd#|7bLM_2H64eg#Ty?v!ndcZgZu{v30K$kq+y$$Tu!Z=o z3`XlLQ}RVdYr%yc%J_oQnQCGqdoLgxc9zDjN28DKsQ)=XKE)K;3^8f-{iTER+j-!< zD>{tbNJCS4p6tT^G*aGZuw4%h_09`8`i)f(iOW`*%h3T2gz~Yi^FVb#+9)iQe^*VI zK{n=GsP-{XrZVDuS_?^t4gjB8eRjr>u9PX~;Ibj`yU?CFH#q-XgIh+1MUYX@)kc=*^?(Ck ztN6Qz$j5BI&-J&r_7WlJZb-89S3YC7FR4iWF_tgLAllqb%K=&Lx9Atma|4o%|6t*f4_sLQ|kDHO(QDm#~lzug;Ro7*yO>0v* zRw7*9zA+tIu2*d{NH#hv4102STkaRWTc1FOjBrEmxj}#_)ydjb+f|Jui@&Cp zWFqdXuSfO8vu8mxS-9@?bSDVK&!h@vB9r`>t*#@PKBXd&98bTAG_mRc5_-bCuGl`u zN{=^t^{7AIRr!|DicY`2{sBH~dJ1R6@RNZnbIg(V=znf|-tShZlIiU=6{r`DZPz5n z`33mKzgJ8LsXC?Eg>)xwv=iYBH|htHnh#oerBk~YpDo~$qvmg^O>mYSH-97hP4OBmU8+rUG zcVa9e`>@in7a7kCpRp}oG)sp3)<0!sl#Rhx`|A63>@IO0)^O(W`m03QG46u+Q0O#wjBa+Kv)PAcR-mS$JU>`d|i=I{R5tD2ayij$-a z`|obXpL)9f-ga9C6 zm_k3E9z#WEdnUk-(_3WX;Au|8>b^&Shlc>s0hP=B_S=SVQcIDyaHf|pZn;HVad#}( zk&_SJ0-+Au#M%f%I1~bye^>EzLtwdFBc?2&!`Kr99Egji;;Rt*^d>>he#J~R<&VCM z5_(pXdb@jMLX)TW*>8j-q@p+VBi+IJB5?{W&GZ-uX4qi83VuU-J!j^*@L`JQJu7DB zm=367cF5*8H9cO2kS|KwOK*V^@b`Z@+*#!U@JhxC<{>9r5P~c=WT<$Vl-Dn79@l>D z=aO{bp=FKDe{j;S;>;bhZ7-Vec5lxK+!WcCkT`8wgzb4vKeEhYddZ=A$ufmST=?wz zL$q$TTf~{ekGLp6S5%iE0G~%uJ9ths%RI!FQJTGOFD|z~^r8erq`>^3d8}z<(@MSb zQE~O~&X6iIQP;sEZm*{4Q9(izLt~AM6iM>v1y#)rPvDRsy;%5+bUoF1?)Z3@Z7uzT z`sA`CRRejQK2J7t)_VE7Vh=sE!Db}3tB*f3s}0dy?^39mJ5hC}Ga*%$u*J9pO`H)e zzv;cqcn^fXKxMG@{mPui%vq2_kyCPOhz>o8Y&;VtRf9xO;)YDt-@T+9LcUC^kGo|} zy*4H|FWQpZrDzOlGmZa#Jn4ihW1ZXyb+&2(Un%+$-iHT5b}NO{X?C5ynFk(!Ecfgx z5XA^RS}?LdZ*F^F56n|Xe#ZltL$WUL)#ju4Fe{(rlqOSW2l}vVqw6t15KJx294BAP z%U-JDUc6Rf5%@~(6cVH?chsKs9t~7=Ql7dd3fW=*cCx-cW~vF#VYsFM>Jf6z1?S+J zBrv|n`c?xVyR}fU>N#N56fp7O`Ui10ve}(-cbx?pwX>pRXwbyCdI$;YXEoc>Y71*c zD5l8Dss_czzbN5GtW~t0KRX#1Vok{sqHVNY9o*_7k2&Y!EvK?4!x;;W>_|R1Qj}#SkXV0H6?Cg&A_WL)QeS7 z6=LQ;$jIGMYrz{1MIrVCYV%p+`TdMuaJ-69|7r$^e^TICpw}ga*l7g>d!tI z%dki-gnd+Y>msL!3x2~cPxjWH�O-WsJk``b(jW)M7x>cEM#ox7?NL%=?)FXYV5> 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

  • qFkuh8>vk;`{YIQix;Md$P3&nK*j zTu*$0ib@_2<^D}#JqMm|w!}D_H$Cl*Uj?jp^?UA~l@8DF>fSHg=G*ShNe#{889+FPA$)z9ss7p*R^Cu^edJ&%GnO7G(rNEf_Jf}m6HlJ3KQE8Mu=Lp|ioX%-Y1zzAlON0#jJb~L ziv!vkUI(;QPy*iM9M+iUfzHqi!#p4)79a@@MvULe%b&gRO8-F{JsvQvf8Z0GUWhj} z8*FPY6DH$wV?~e2rznxF1@XS4%hyj<#0$~K^)0%$JOK=-gD2zCviU3o@?`u62|4q;pM{WvhxK6J223_i>+7sA6u#b2%Vfmz_L_a~^E>sk>FrL7v zk*q5KHk5j)qMf-OwXoeset#nIH%5pz6@F1fB>QtgR%PG)7&`{WOIuWY(XxC2gY%i( zgeAd=XYf?WMrpNI|Iyoeb=ldD=Rpw*g`!GZ!msYSnUyEm&v{6H+H&Oe5$xpSi-YLY zK%U$uCO(vN>=AeHJ(OgN{3cgGmOK$mKiBkvvo~ef)}9^|sXzs(i;^+pD#LOc`)h>P zZ@B19-Ebd#&(x-kbRxYWI+86yumVg9rOd;P<8p-|#*cmDiZ|-%#H*LcA1M#OaU=pB=59*ScIUwqOF_=UfAlS_!G~g{FSPnadM$X z2!mLBbu;<&S!gDo(WjtXm7>J`y97q77l6@~fgB=}!GxD{(LFd#OBKWKsGRG3<)gVw`}6emVyyWM@y3o+C($S?rv^RBqV>b&-58aem3PV<_*|2(@9swv>d8vt3~Q$m7PEB^ z_3U!<4&_I{ca%Ax+M*M5&QO@CZ}0QV6*8h(ftD{f6JiJO!-HC1|<)bjMsI!0rM!A)j#{~Fsc zr*=UR%YC7>fkMURD5iyXqp%8=wWR?YUhoo#Sk`&YRw5;LC+l6XdqRKH3QoH5YC!u_ zfAGjFUMlJ_KU<#<^-j~=Py664#MLuxLqqVI{_KI6nW)=jDb0nwy~DgJ#mQ2%R}|4{ zKBBumE#38^z6mhS-0W71HaV`g5_rh8c=Pwk(LUSwiBUf4_(Ew) zTJ3ck(dP!S`1??g4ZSH!#3_wji->}T+#0ewcjx&PpHaL9zpmWiO@EZ&&pSc%Ey&^e zj??1k2z)DS{E?iX{rc+%@GODezBQnsQfK0a4Vh`g$nVaG=bwW=fAB_l?c`*j&})>h zcJW!0NW~E+6OQtp(7I+Xh+LM?2YJ=<-r|uKo|SSgPU-9(#5DfL@@P!vm*>_svD7^_ zZQRP|RV@dH@J$wSAFpOv_C2%o6YkMRP5Q*yv2o$gVw433h@yf#V1Los%I-r7eYMXs z{l$>8-MwzUEO~UahG&>dMYuK4VY zoV0mII#vC{A};MKW>W?dMG8RN?%u+4D#u`R+~LI+aQBuv!)MAqxG_&1d%?Ao6NTd* zL~U#%0rfiB49Z9c5k)%?icN$Es#i#AwRu!;yG@oQS@_pWS4Kf_MJi#rK^f7}(AWx) z^7IA6w%o5z?{XyNe$Uu7-I`0gAJKS+;lt@Nss{PX5YIhnT?*rRNB6Pi4hMx4GdlqJS2CHzVlJ*b09h?DHLtyA-JTjnleut-r?$M@D3>ft-=dx{`e^?{ z<{8(mNF&_pd7@>gvqA&N@`a0sn~f-zt4qmfpwG-jYReB_o{wQnt0KbM+B@)<4E;(q z%JBzUhob{FcRbKTS&AYK`U@GZ7nuz95VtOag;`oWYH{BBG7fytgpyHw? z#Z}!nl_pDBZ(Jj3o5x-F?(-Kss6Zz}=@;77or0b;a3p zM2gh)&6t#Isz%HiWaY&{?pod4<9*Og)=%KUeVl;1P3(N#$@l$->s7*}SoA6Bp{zii*$z|Ou z{;nr;PGpV$kDUi%AvEulZvO(_&S*hEmFDHa^V!hnBK zl8E2jdZ(eB;G+?md@lO6+s&QQmDK9NZ>AXEY_B=mB~)nuB&FS;A$;ZfrvIg~@85Sp z7h^d|oZljUu4f}VP@;kXb@+QNI?z$hdd*^ar{WKWv+wC-B{ze`z81{Rh$F~7NsY7x zIJ1qTy)tcJXz!!WZ4v0QlXqM3+3hp17hyX_{v!g)awl15mvB48jO%Wo1#R2VGt z3|TD%o0)dD-fxrUz+s=@ySk^&0Os+0+IR=!cb}2u3G+wS`(%@Rc8JCOY4v6PA3L7# z=I1=R0`Yf2)fqQ<;WiD41s_vB_1@3Hi#Is2EBU zpt`}(SJznB!5L-Q`|3PrDyDw40;J1iv0l6a5tsY9wxKe_bo=pQRpRD;rrakLvP@ML z9N>6uB%fM_7y1omObX`YS4QpZkC8&U+9IPWIGIS=r99{7uBBfBOAgMYT-As4_u-{ZcA$43OC%L12ePEKYU&F0MNJ`~-b5F6XD19?@ z=1cB!m5Y;n7SBgv@hMwo*i)995Ii4jfYC+8jh4~B=>6Nw9HF^7+?Fl(gDJuw3TpPH zf2uX7|F;oj%<|&L&KJ=T8cF&Rslt8&TZ>pxJ*U41DQZdnW2TLh-R<86k*bpylcoDC zD_`rp?@*=D24|P8;R1hgwveID-t{W4sLyh&ZC}2K@cK8{>_=j(X>?k48t@~*CH&Yk z$`8ybQQeguGd=OVhdrLWSB?Z<>4 z0G|uW z;kQafI4912p8XNRV2Auxs?X;5C#`)DQ7kt<<0_NV5f&{VuDQpT0cCIxbd$W(wvQKN z;~SJi4IxL&BLAH(*R;x7>X8OMU{G3I~yRSx}_ku3j?@obV}zeW_dY*9GILV?fZ_ebq1St zo12Bv-mmxGp5?(VBuaDBT4N-c2xH$Dj4qCje7t&n>1(R|A-0i*ZUUGkN&gnYwk_1W{}WE}TLAtMV z)r4OKH4T(subz!ovlyhl?K&%epmceMJ&{2~jc$&F&fgI_<|AxIZp3a!70XC?`9{fQ zh!jpw&%vrLYcuHjjiws~&C@}EnI=-edg?cpX*$epnX@aYkDjszi{ksLBuDHxJ2W}~ zR!ZdJKMw4_^4S?q9PM0rUc!Czv=_gGKB~g=r~;pRhHoFQP5$n+f$x?d?C4m?9+r4V z@QJ`_Yx~kQyN|D>BgnOCyi=nVQS1@=p}5bkoSK-cC-EkZaSXrfeTeyZ_Vnxf81HyF zdjIXd>I}dQG*TFX=uB7zCwC)sV8QNI0_bJ%@GtoHTv8xyu|jLo7PlDQR`~VDco{jm zlmOHRuv;a?OmEn|@qk9)k)K^eI!GoPkBLFaMOT(Ff#Ha0svl@}LFTnzFngg3+2R+f z`-RK!KuS3$!`e{KICzFkB(8e~(^r>#xM>*tv``Iku&#Qh*m7%lc}X@m`5VO5c8FL?fm(lA8!Dc4QotZ(oqudQ%;yhY(xD1}v*1hJe!U4I?Nz_ybUb zMt?D9v;2Sy<|@*E{c!z+$lAb~^my!D!8?VpzgakGQ4iWrYm+F=j?odK@ciTD%$F~o zbWZ7xS5;E5^_2f&qjpCU)AJ5;9K9*d2fjqXSUny9IuX&Thlw%gUvMfG<1ge{iQ<$tO>W;Oz2F;hmbd5Sv!HqTk)#Z-Qqj zcQ{}R%p@ip^~(s0&-}T|b{LlJ?7WkNa=H>cHxG}7jTOlt2kwFj2{td!0#_-P*kykm zTpMV+aRtFoYsZq$vM)^oCm2OK(`^A?&q_dGf)FKb*=>eY4HmRQ5P0p{8cT)@O;Kx%H!QYh(lHas$qI%ZgW;L!O!2;zG^ znvh6&aJ#&(1}w(T+;xd5eoizsMg2xq@s@0-Qi#c^U)27+U^$dBfJe82X74rwZrR-k zi*kZaz8XNme6r0ank)??1vAu_XSI{LpFDAd0$H9QFy^;U=BSK^6hGLZ-{$^>l)sYH>S&g#Vamdlh!M6ONZt<;&|BpXLZV25vyxl;_F z2S-CF{TQPlur(m0kmZjyxC2Us6&`&wQ*|L*{_8bJ+(VUiv(Q+N^TO}IVVvHkA#~w z0D0c?*3Bp`hcVX7udg^?<=jbg;idj1-WKj-u>RyO#@W%N6GxSr^IAabaINRoeA*7J zyc1}r8+6-S$*uhwZ4P6LcZ_qXRzK7!NI>B|fn3lOU zxm@d`qr63uqd~vZGYB-d;5T8dU(u5vzh%!O2;~u1?0|ivCEZ5mg%`ifi_6I? zEH|x*FW10X#t5~Yc@l$x6T0kA9al;;Sh$b3BTBq|&u?Ql%-_>IF1Y%PHK6&=aRP~y z_BT59zPlL$=dt@9#^Vo@fSO{Olb~F?ytcippLiCq_!DaSHTh1p!%>Menv(_G8QZ8+o31)oE% zmF5&S1=)9KWB3e0`1uZoF4L<6>Ap!G|9Z@-pVm&7)I-^n{M2*6{b?B!=Uoj7RR7X{ z9yAG-|J9K0)Ea2iW1E}|Kcwr*_;uICw2Xj#OPhcpESRcOkmJE)@sR3f21Ctb20wNF zM=?XP&7gXj`gdMwH@0$OX$HQ2bd?15AJny#znvf+FXf#quCYa}ruF*&(`6Y`XZl@m zAD6GJt`lBw2N{#San5VE{4`q+9gp=fD3mCDy^W8UywiO`KBL2T9-?AS1#Vpp!dq2a zk4@j}{$eBVRBsEZdkLJ0D|GPujcQ4ru~8N0F)rB3qkF!o_B%rOGbA}&wZ_Ph#0Ttj9+|gRi6)s6Fhn;=h)n#SU z=XYNwy+8E6Cn6Dk(ZQVcSGQHc?(mwA$+L~u>6dD)v!n{qG5QS4A>n0;5o`JTR<Fuw~6ThiTm2}4VT4i2o{I9D$x_4Y(%3e2?MS=-ROx@6_19k*xO0ORu)xs#+9|J5j<|^i67a zZ?Zce9yn&sm={MYmnNIcRtMOClwqe?+K@7cRXt{qtVOGveI zM4Q2xuhQlTLp;!@o{&1Bx0lE%yrB}VaU;_|%%2oU`k8+}(^vbvXr^=_22QT%S>9Hd zPh*`+e3_UU#s%19aP$Od+%On zd+9J<-xDI&tH^`zV)8&=+}CJ3e6$&qaIXb>(wW@6JVL5iDD_hyIJk9|j5_Opo8=ZR zvB&fdhN|l-4E^xa!HWjacbd5Cg2U$uZ|fV52IUZ3?t^R3A7Bv5`~Or7`*fL~)oyp?kb$9v9nZ zJ;QqHP@6@)QVh|R2w?$UMDZE!4TOzrGBXt**;p5h56HG9B;KXG&p6BxT?mI#$vb%| zjC!Es)ph@B9E*qx)E(L61Ur6ETd|YF=_(T}T?X0rU!L>zB)qoz3@>U0xk<@)U!y51 z8*$TJ*vcZ+$>YgFAUbQ*Kf?kkF;onL5ho0J@k@i{hJ)Owm^`?qOgH|lxY9xiXH!Xa|u7YtjO7H+|zm{C6L z1!YJ~{G#@kI`FgBktAv&E9k?=MXrp07J6kanz*h{b6xvFl-{{sE+?4}DAl9+R+{-A zY=MCI?l1wa3F-W$#O_K8ZA$@HL`w@qBFunk81g@Ve7W!L&FpqFT;ZF?_DJZ}c#{)2 zpB#9%XN_`QchWkXt6DO{O^>j&li-7L4Jx{>ZZ?_B+lgkgIVDoS*)(44iDQsl!|NNrdm2lLiTTE|gxRJ7 z+~^DH9gdUg>J_CwY2zRKnKj|AEahS+mRHrJT!+4}DFdGs?xIveM6uw=X{sP(s$!b;y{XK AoQ!hckm!UeoUJb$tu#&#i#y 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