예제 #1
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three
            - absolute amp is within [0.9, 1.1]
            - base is less than 0.1
            - amp error is less than 0.1
            - tau error is less than its value
            - base error is less than 0.1
        """
        amp = fit_data.fitval("amp")
        tau = fit_data.fitval("tau")
        base = fit_data.fitval("base")

        criteria = [
            fit_data.reduced_chisq < 3,
            abs(amp.value - 1.0) < 0.1,
            abs(base.value) < 0.1,
            amp.stderr is None or amp.stderr < 0.1,
            tau.stderr is None or tau.stderr < tau.value,
            base.stderr is None or base.stderr < 0.1,
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #2
0
    def _extra_database_entry(self, fit_data: curve.FitData) -> List[AnalysisResultData]:
        """Calculate EPC."""
        nrb = 2**self._num_qubits
        scale = (nrb - 1) / nrb

        alpha = fit_data.fitval("alpha")
        alpha_c = fit_data.fitval("alpha_c")

        # Calculate epc_est (=r_c^est) - Eq. (4):
        epc = scale * (1 - alpha_c)

        # Calculate the systematic error bounds - Eq. (5):
        systematic_err_1 = scale * (abs(alpha.n - alpha_c.n) + (1 - alpha.n))
        systematic_err_2 = (
            2 * (nrb * nrb - 1) * (1 - alpha.n) / (alpha.n * nrb * nrb)
            + 4 * (np.sqrt(1 - alpha.n)) * (np.sqrt(nrb * nrb - 1)) / alpha.n
        )

        systematic_err = min(systematic_err_1, systematic_err_2)
        systematic_err_l = epc.n - systematic_err
        systematic_err_r = epc.n + systematic_err

        extra_data = AnalysisResultData(
            name="EPC",
            value=epc,
            chisq=fit_data.reduced_chisq,
            quality=self._evaluate_quality(fit_data),
            extra={
                "EPC_systematic_err": systematic_err,
                "EPC_systematic_bounds": [max(systematic_err_l, 0), systematic_err_r],
            },
        )

        return [extra_data]
예제 #3
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three
            - absolute amp is within [0.4, 0.6]
            - base is less is within [0.4, 0.6]
            - amp error is less than 0.1
            - tau error is less than its value
            - base error is less than 0.1
        """
        amp = fit_data.fitval("amp")
        tau = fit_data.fitval("tau")
        base = fit_data.fitval("base")

        criteria = [
            fit_data.reduced_chisq < 3,
            abs(amp.nominal_value - 0.5) < 0.1,
            abs(base.nominal_value - 0.5) < 0.1,
            curve.is_error_not_significant(amp, absolute=0.1),
            curve.is_error_not_significant(tau),
            curve.is_error_not_significant(base, absolute=0.1),
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #4
0
    def _extra_database_entry(self, fit_data: curve.FitData) -> List[AnalysisResultData]:
        """Calculate Hamiltonian coefficients from fit values."""
        extra_entries = []

        for control in ("z", "i"):
            for target in ("x", "y", "z"):
                p0_val = fit_data.fitval(f"p{target}0")
                p1_val = fit_data.fitval(f"p{target}1")

                if control == "z":
                    coef_val = 0.5 * (p0_val - p1_val) / (2 * np.pi)
                else:
                    coef_val = 0.5 * (p0_val + p1_val) / (2 * np.pi)

                extra_entries.append(
                    AnalysisResultData(
                        name=f"omega_{control}{target}",
                        value=coef_val,
                        chisq=fit_data.reduced_chisq,
                        device_components=[Qubit(q) for q in self._physical_qubits],
                        extra={"unit": "Hz"},
                    )
                )

        return extra_entries
예제 #5
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three,
            - an error on the frequency smaller than the frequency.
        """
        fit_freq = fit_data.fitval("freq").value
        fit_freq_err = fit_data.fitval("freq").stderr

        criteria = [
            fit_data.reduced_chisq < 3,
            fit_freq_err < abs(fit_freq),
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #6
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared less than 3,
            - a peak within the scanned frequency range,
            - a standard deviation that is not larger than the scanned frequency range,
            - a standard deviation that is wider than the smallest frequency increment,
            - a signal-to-noise ratio, defined as the amplitude of the peak divided by the
              square root of the median y-value less the fit offset, greater than a
              threshold of two, and
            - a standard error on the sigma of the Gaussian that is smaller than the sigma.
        """
        curve_data = self._data()

        max_freq = np.max(curve_data.x)
        min_freq = np.min(curve_data.x)
        freq_increment = np.mean(np.diff(curve_data.x))

        fit_a = fit_data.fitval("a").value
        fit_b = fit_data.fitval("b").value
        fit_freq = fit_data.fitval("freq").value
        fit_sigma = fit_data.fitval("sigma").value
        fit_sigma_err = fit_data.fitval("sigma").stderr

        snr = abs(fit_a) / np.sqrt(abs(np.median(curve_data.y) - fit_b))
        fit_width_ratio = fit_sigma / (max_freq - min_freq)

        criteria = [
            min_freq <= fit_freq <= max_freq,
            1.5 * freq_increment < fit_sigma,
            fit_width_ratio < 0.25,
            fit_data.reduced_chisq < 3,
            (fit_sigma_err is None or fit_sigma_err < fit_sigma),
            snr > 2,
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #7
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three
            - relative error of tau is less than its value
            - relative error of freq is less than its value
        """
        tau = fit_data.fitval("tau")
        freq = fit_data.fitval("freq")

        criteria = [
            fit_data.reduced_chisq < 3,
            tau.stderr is None or tau.stderr < tau.value,
            freq.stderr is None or freq.stderr < freq.value,
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #8
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three,
            - a DRAG parameter value within the first period of the lowest number of repetitions,
            - an error on the drag beta smaller than the beta.
        """
        fit_beta = fit_data.fitval("beta")
        fit_freq0 = fit_data.fitval("freq0")

        criteria = [
            fit_data.reduced_chisq < 3,
            fit_beta.nominal_value < 1 / fit_freq0.nominal_value,
            curve.is_error_not_significant(fit_beta),
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #9
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three
            - relative error of tau is less than its value
            - relative error of freq is less than its value
        """
        tau = fit_data.fitval("tau")
        freq = fit_data.fitval("freq")

        criteria = [
            fit_data.reduced_chisq < 3,
            curve.is_error_not_significant(tau),
            curve.is_error_not_significant(freq),
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #10
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three,
            - more than a quarter of a full period,
            - less than 10 full periods, and
            - an error on the fit frequency lower than the fit frequency.
        """
        fit_freq = fit_data.fitval("freq").value
        fit_freq_err = fit_data.fitval("freq").stderr

        criteria = [
            fit_data.reduced_chisq < 3,
            1.0 / 4.0 < fit_freq < 10.0,
            (fit_freq_err is None or (fit_freq_err < fit_freq)),
        ]

        if all(criteria):
            return "good"

        return "bad"
예제 #11
0
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared less than 3,
            - a peak within the scanned frequency range,
            - a standard deviation that is not larger than the scanned frequency range,
            - a standard deviation that is wider than the smallest frequency increment,
            - a signal-to-noise ratio, defined as the amplitude of the peak divided by the
              square root of the median y-value less the fit offset, greater than a
              threshold of two, and
            - a standard error on the kappa of the Lorentzian that is smaller than the kappa.
        """
        freq_increment = np.mean(np.diff(fit_data.x_data))

        fit_a = fit_data.fitval("a")
        fit_b = fit_data.fitval("b")
        fit_freq = fit_data.fitval("freq")
        fit_kappa = fit_data.fitval("kappa")

        snr = abs(fit_a.n) / np.sqrt(abs(np.median(fit_data.y_data) - fit_b.n))
        fit_width_ratio = fit_kappa.n / np.ptp(fit_data.x_data)

        criteria = [
            fit_data.x_range[0] <= fit_freq.n <= fit_data.x_range[1],
            1.5 * freq_increment < fit_kappa.n,
            fit_width_ratio < 0.25,
            fit_data.reduced_chisq < 3,
            curve.is_error_not_significant(fit_kappa),
            snr > 2,
        ]

        if all(criteria):
            return "good"

        return "bad"
    def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]:
        """Algorithmic criteria for whether the fit is good or bad.

        A good fit has:
            - a reduced chi-squared lower than three,
            - a measured angle error that is smaller than the allowed maximum good angle error.
              This quantity is set in the analysis options.
        """
        fit_d_theta = fit_data.fitval("d_theta").value

        criteria = [
            fit_data.reduced_chisq < 3,
            abs(fit_d_theta) < abs(self.options.max_good_angle_error),
        ]

        if all(criteria):
            return "good"

        return "bad"
    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)

        for control in ("z", "i"):
            for target in ("x", "y", "z"):
                p0_val = fit_data.fitval(f"p{target}0")
                p1_val = fit_data.fitval(f"p{target}1")

                if control == "z":
                    coef_val = 0.5 * (p0_val - p1_val) / (2 * np.pi)
                else:
                    coef_val = 0.5 * (p0_val + p1_val) / (2 * np.pi)

                outcomes.append(
                    AnalysisResultData(
                        name=f"omega_{control}{target}",
                        value=coef_val,
                        chisq=fit_data.reduced_chisq,
                        quality=quality,
                        extra={
                            "unit": "Hz",
                            **metadata,
                        },
                    ))

        return outcomes
예제 #14
0
    def _extra_database_entry(
            self, fit_data: curve.FitData) -> List[AnalysisResultData]:
        """Calculate EPC."""
        extra_entries = []

        # Calculate EPC
        alpha = fit_data.fitval("alpha")
        scale = (2**self._num_qubits - 1) / (2**self._num_qubits)
        epc = scale * (1 - alpha)

        extra_entries.append(
            AnalysisResultData(
                name="EPC",
                value=epc,
                chisq=fit_data.reduced_chisq,
                quality=self._evaluate_quality(fit_data),
            ))

        # Calculate EPG
        if not self.options.gate_error_ratio:
            # we attempt to get the ratio from the backend properties
            if not self.options.error_dict:
                gate_error_ratio = RBUtils.get_error_dict_from_backend(
                    backend=self._backend, qubits=self._physical_qubits)
            else:
                gate_error_ratio = self.options.error_dict
        else:
            gate_error_ratio = self.options.gate_error_ratio

        count_ops = []
        for meta in self._data(label="raw_data").metadata:
            count_ops += meta.get("count_ops", [])

        if len(count_ops) > 0 and gate_error_ratio is not None:
            gates_per_clifford = RBUtils.gates_per_clifford(count_ops)
            num_qubits = len(self._physical_qubits)

            if num_qubits == 1:
                epg_dict = RBUtils.calculate_1q_epg(
                    epc,
                    self._physical_qubits,
                    gate_error_ratio,
                    gates_per_clifford,
                )
            elif num_qubits == 2:
                epg_1_qubit = self.options.epg_1_qubit
                epg_dict = RBUtils.calculate_2q_epg(
                    epc,
                    self._physical_qubits,
                    gate_error_ratio,
                    gates_per_clifford,
                    epg_1_qubit=epg_1_qubit,
                )
            else:
                # EPG calculation is not supported for more than 3 qubits RB
                epg_dict = None

            if epg_dict:
                for qubits, gate_dict in epg_dict.items():
                    for gate, value in gate_dict.items():
                        extra_entries.append(
                            AnalysisResultData(
                                f"EPG_{gate}",
                                value,
                                chisq=fit_data.reduced_chisq,
                                quality=self._evaluate_quality(fit_data),
                                device_components=[Qubit(i) for i in qubits],
                            ))
        return extra_entries
예제 #15
0
    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)

        # Calculate EPC
        alpha = fit_data.fitval("alpha")
        scale = (2**num_qubits - 1) / (2**num_qubits)
        epc = scale * (1 - alpha)

        outcomes.append(
            AnalysisResultData(
                name="EPC",
                value=epc,
                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