From d9364b39fafe92044d885f47829251abd29ec40d Mon Sep 17 00:00:00 2001 From: knzwnao Date: Thu, 2 Dec 2021 05:43:16 +0900 Subject: [PATCH] cleanup --- .../curve_analysis/curve_analysis.py | 16 +++---- .../curve_analysis/curve_fit.py | 15 ++++--- .../curve_analysis/fit_function.py | 42 ++++++++++++------- .../curve_analysis/standard_analysis/decay.py | 2 +- .../error_amplification_analysis.py | 4 +- .../standard_analysis/oscillation.py | 11 +++-- .../standard_analysis/resonance.py | 19 ++++----- .../curve_analysis/visualization/curves.py | 16 +++---- .../visualization/fit_result_plotters.py | 4 +- .../database_service/db_fitval.py | 2 + qiskit_experiments/framework/base_analysis.py | 1 + .../analysis/cr_hamiltonian_analysis.py | 4 +- .../analysis/drag_analysis.py | 9 ++-- .../analysis/remsey_xy_analysis.py | 5 +-- .../characterization/analysis/t1_analysis.py | 10 ++--- .../analysis/t2ramsey_analysis.py | 6 +-- .../interleaved_rb_analysis.py | 13 +++--- .../randomized_benchmarking/rb_analysis.py | 4 +- .../randomized_benchmarking/rb_utils.py | 4 +- test/calibration/experiments/test_rabi.py | 12 +++--- test/curve_analysis/test_curve_fit.py | 39 +++++++++-------- .../test_rb_analysis.py | 3 +- test/randomized_benchmarking/test_rb_utils.py | 24 ++++++----- test/test_t1.py | 2 +- 24 files changed, 144 insertions(+), 123 deletions(-) diff --git a/qiskit_experiments/curve_analysis/curve_analysis.py b/qiskit_experiments/curve_analysis/curve_analysis.py index 7f30830b94..ca2b8f836b 100644 --- a/qiskit_experiments/curve_analysis/curve_analysis.py +++ b/qiskit_experiments/curve_analysis/curve_analysis.py @@ -582,13 +582,8 @@ def _is_target_series(datum, **filters): ) from ex if isinstance(data_processor, DataProcessor): - y_data = data_processor(data) + ydata = data_processor(data) else: - # Can we replace this with error or still worth supporting? - # Looks like this is too much flexibility. - warnings.warn( - "Use of non DataProcessor instance has been deprecated.", DeprecationWarning - ) y_nominals, y_stderrs = zip(*map(data_processor, data)) ydata = unp.uarray(y_nominals, y_stderrs) @@ -599,7 +594,7 @@ def _is_target_series(datum, **filters): shots = np.asarray([datum.get("shots", np.nan) for datum in data]) # Find series (invalid data is labeled as -1) - data_index = np.full(x_values.size, -1, dtype=int) + data_index = np.full(xdata.size, -1, dtype=int) for idx, series_def in enumerate(self.__series__): data_matched = np.asarray( [_is_target_series(datum, **series_def.filter_kwargs) for datum in data], dtype=bool @@ -611,7 +606,7 @@ def _is_target_series(datum, **filters): label="raw_data", x=xdata, y=unp.nominal_values(ydata), - y_err=unp.nominal_values(ydata), + y_err=unp.std_devs(ydata), shots=shots, data_index=data_index, metadata=metadata, @@ -980,10 +975,11 @@ def _run_analysis( analysis_results.append( AnalysisResultData( name=PARAMS_ENTRY_PREFIX + self.__class__.__name__, - value=fit_result.parameters, + value=[p.nominal_value for p in fit_result.popt], chisq=fit_result.reduced_chisq, quality=quality, extra={ + "popt_keys": fit_result.popt_keys, "dof": fit_result.dof, "covariance_mat": fit_result.pcov, "fit_models": fit_models, @@ -1006,7 +1002,7 @@ def _run_analysis( unit = None result_entry = AnalysisResultData( name=p_repr, - value=fit_result.fit_val(p_name), + value=fit_result.fitval(p_name), unit=unit, chisq=fit_result.reduced_chisq, quality=quality, diff --git a/qiskit_experiments/curve_analysis/curve_fit.py b/qiskit_experiments/curve_analysis/curve_fit.py index 93335bd339..42e5a80883 100644 --- a/qiskit_experiments/curve_analysis/curve_fit.py +++ b/qiskit_experiments/curve_analysis/curve_fit.py @@ -15,7 +15,7 @@ # pylint: disable = invalid-name from typing import List, Dict, Tuple, Callable, Optional, Union -from uncertainties import ufloat, correlated_values +from uncertainties import correlated_values, ufloat import numpy as np import scipy.optimize as opt @@ -63,8 +63,10 @@ def curve_fit( ``xrange`` the range of xdata values used for fit. Raises: - AnalysisError: if the number of degrees of freedom of the fit is - less than 1, or the curve fitting fails. + AnalysisError: + - When the number of degrees of freedom of the fit is + less than 1, or the curve fitting fails. + - When the covariance matrix doesn't converge. .. note:: ``sigma`` is assumed to be specified in the same units as ``ydata`` @@ -135,8 +137,11 @@ def fit_func(x, *params): "scipy.optimize.curve_fit failed with error: {}".format(str(ex)) ) from ex - # Keep parameter correlations in following analysis steps - fit_params = correlated_values(nom_values=popt, covariance_mat=pcov) + if np.isfinite(pcov).all(): + # Keep parameter correlations in following analysis steps + fit_params = correlated_values(nom_values=popt, covariance_mat=pcov, tags=param_keys) + else: + fit_params = [ufloat(nom, np.nan) for nom in popt] # Calculate the reduced chi-squared for fit yfits = fit_func(xdata, *popt) diff --git a/qiskit_experiments/curve_analysis/fit_function.py b/qiskit_experiments/curve_analysis/fit_function.py index f2ee2ad08a..720bc6cf55 100644 --- a/qiskit_experiments/curve_analysis/fit_function.py +++ b/qiskit_experiments/curve_analysis/fit_function.py @@ -15,24 +15,38 @@ """ # pylint: disable=invalid-name -import numpy as np import functools +from typing import Callable +import numpy as np from uncertainties import unumpy as unp -def uncertainties(fit_func): +def calc_uncertainties(fit_func: Callable) -> Callable: + """Decolator that typecast y values to float array if input parameters have no error. + + Args: + fit_func: Fit function that may return ufloat array. + + Returns: + Fit function with typecast. + """ + @functools.wraps(fit_func) - def wrapper(*ags, **kwargs) -> np.ndarray: - yvals = wrapper(*args, **kwargs) + def _wrapper(x, *args, **kwargs) -> np.ndarray: + yvals = fit_func(x, *args, **kwargs) try: + if isinstance(x, float): + # single value + return float(yvals) return yvals.astype(float) except TypeError: return yvals - return wrapper + + return _wrapper -@uncertainties +@calc_uncertainties def cos( x: np.ndarray, amp: float = 1.0, @@ -49,7 +63,7 @@ def cos( return amp * unp.cos(2 * np.pi * freq * x + phase) + baseline -@uncertainties +@calc_uncertainties def sin( x: np.ndarray, amp: float = 1.0, @@ -66,7 +80,7 @@ def sin( return amp * unp.sin(2 * np.pi * freq * x + phase) + baseline -@uncertainties +@calc_uncertainties def exponential_decay( x: np.ndarray, amp: float = 1.0, @@ -83,7 +97,7 @@ def exponential_decay( return amp * base ** (-lamb * x + x0) + baseline -@uncertainties +@calc_uncertainties def gaussian( x: np.ndarray, amp: float = 1.0, sigma: float = 1.0, x0: float = 0.0, baseline: float = 0.0 ) -> np.ndarray: @@ -95,7 +109,7 @@ def gaussian( return amp * unp.exp(-((x - x0) ** 2) / (2 * sigma ** 2)) + baseline -@uncertainties +@calc_uncertainties def cos_decay( x: np.ndarray, amp: float = 1.0, @@ -113,7 +127,7 @@ def cos_decay( return exponential_decay(x, lamb=1 / tau) * cos(x, amp=amp, freq=freq, phase=phase) + baseline -@uncertainties +@calc_uncertainties def sin_decay( x: np.ndarray, amp: float = 1.0, @@ -131,7 +145,7 @@ def sin_decay( return exponential_decay(x, lamb=1 / tau) * sin(x, amp=amp, freq=freq, phase=phase) + baseline -@uncertainties +@calc_uncertainties def bloch_oscillation_x( x: np.ndarray, px: float = 0.0, py: float = 0.0, pz: float = 0.0, baseline: float = 0.0 ): @@ -149,7 +163,7 @@ def bloch_oscillation_x( return (-pz * px + pz * px * unp.cos(w * x) + w * py * unp.sin(w * x)) / (w ** 2) + baseline -@uncertainties +@calc_uncertainties def bloch_oscillation_y( x: np.ndarray, px: float = 0.0, py: float = 0.0, pz: float = 0.0, baseline: float = 0.0 ): @@ -167,7 +181,7 @@ def bloch_oscillation_y( return (pz * py - pz * py * unp.cos(w * x) - w * px * unp.sin(w * x)) / (w ** 2) + baseline -@uncertainties +@calc_uncertainties def bloch_oscillation_z( x: np.ndarray, px: float = 0.0, py: float = 0.0, pz: float = 0.0, baseline: float = 0.0 ): diff --git a/qiskit_experiments/curve_analysis/standard_analysis/decay.py b/qiskit_experiments/curve_analysis/standard_analysis/decay.py index e69415eb53..510584b9f8 100644 --- a/qiskit_experiments/curve_analysis/standard_analysis/decay.py +++ b/qiskit_experiments/curve_analysis/standard_analysis/decay.py @@ -105,7 +105,7 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: criteria = [ fit_data.reduced_chisq < 3, - tau.stderr is None or tau.stderr < tau.value, + tau.std_dev is None or tau.std_dev < tau.nominal_value, ] if all(criteria): diff --git a/qiskit_experiments/curve_analysis/standard_analysis/error_amplification_analysis.py b/qiskit_experiments/curve_analysis/standard_analysis/error_amplification_analysis.py index 19b9ef8634..1855faa6d5 100644 --- a/qiskit_experiments/curve_analysis/standard_analysis/error_amplification_analysis.py +++ b/qiskit_experiments/curve_analysis/standard_analysis/error_amplification_analysis.py @@ -191,12 +191,12 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: - 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 + fit_d_theta = fit_data.fitval("d_theta") max_good_angle_error = self._get_option("max_good_angle_error") criteria = [ fit_data.reduced_chisq < 3, - abs(fit_d_theta) < abs(max_good_angle_error), + abs(fit_d_theta.nominal_value) < abs(max_good_angle_error), ] if all(criteria): diff --git a/qiskit_experiments/curve_analysis/standard_analysis/oscillation.py b/qiskit_experiments/curve_analysis/standard_analysis/oscillation.py index 282b3ac0bf..57309122c5 100644 --- a/qiskit_experiments/curve_analysis/standard_analysis/oscillation.py +++ b/qiskit_experiments/curve_analysis/standard_analysis/oscillation.py @@ -110,13 +110,12 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: - 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 + fit_freq = fit_data.fitval("freq") 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)), + 1.0 / 4.0 < fit_freq.nominal_value < 10.0, + (np.isnan(fit_freq.std_dev) or (fit_freq.std_dev < fit_freq.nominal_value)), ] if all(criteria): @@ -264,8 +263,8 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: criteria = [ fit_data.reduced_chisq < 3, - tau.stderr is None or tau.stderr < tau.value, - freq.stderr is None or freq.stderr < freq.value, + np.isnan(tau.std_dev) or tau.std_dev < tau.nominal_value, + np.isnan(freq.std_dev) or freq.std_dev < freq.nominal_value, ] if all(criteria): diff --git a/qiskit_experiments/curve_analysis/standard_analysis/resonance.py b/qiskit_experiments/curve_analysis/standard_analysis/resonance.py index b6f651b65c..9a8c659972 100644 --- a/qiskit_experiments/curve_analysis/standard_analysis/resonance.py +++ b/qiskit_experiments/curve_analysis/standard_analysis/resonance.py @@ -121,21 +121,20 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: 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 + fit_a = fit_data.fitval("a") + fit_b = fit_data.fitval("b") + fit_freq = fit_data.fitval("freq") + fit_sigma = fit_data.fitval("sigma") - snr = abs(fit_a) / np.sqrt(abs(np.median(curve_data.y) - fit_b)) - fit_width_ratio = fit_sigma / (max_freq - min_freq) + snr = abs(fit_a.nominal_value) / np.sqrt(abs(np.median(curve_data.y) - fit_b.nominal_value)) + fit_width_ratio = fit_sigma.nominal_value / (max_freq - min_freq) criteria = [ - min_freq <= fit_freq <= max_freq, - 1.5 * freq_increment < fit_sigma, + min_freq <= fit_freq.nominal_value <= max_freq, + 1.5 * freq_increment < fit_sigma.nominal_value, fit_width_ratio < 0.25, fit_data.reduced_chisq < 3, - (fit_sigma_err is None or fit_sigma_err < fit_sigma), + (np.isnan(fit_sigma.std_dev) or fit_sigma.std_dev < fit_sigma.nominal_value), snr > 2, ] diff --git a/qiskit_experiments/curve_analysis/visualization/curves.py b/qiskit_experiments/curve_analysis/visualization/curves.py index ba0dbcceb8..ee2dfb5ac1 100644 --- a/qiskit_experiments/curve_analysis/visualization/curves.py +++ b/qiskit_experiments/curve_analysis/visualization/curves.py @@ -70,13 +70,15 @@ def plot_curve_fit( ax.plot(xs, unp.nominal_values(ys_fit_with_error), **plot_opts) # Confidence interval of 1 sigma - ax.fill_between( - xs, - unp.nominal_values(ys_fit_with_error) - unp.std_devs(ys_fit_with_error), - unp.nominal_values(ys_fit_with_error) + unp.std_devs(ys_fit_with_error), - alpha=0.1, - color=plot_opts["color"], - ) + stdev_arr = unp.std_devs(ys_fit_with_error) + if np.isfinite(stdev_arr).all(): + ax.fill_between( + xs, + y1=unp.nominal_values(ys_fit_with_error) - stdev_arr, + y2=unp.nominal_values(ys_fit_with_error) + stdev_arr, + alpha=0.1, + color=plot_opts["color"], + ) # Formatting ax.tick_params(labelsize=labelsize) diff --git a/qiskit_experiments/curve_analysis/visualization/fit_result_plotters.py b/qiskit_experiments/curve_analysis/visualization/fit_result_plotters.py index 5725429110..16e3ed47fb 100644 --- a/qiskit_experiments/curve_analysis/visualization/fit_result_plotters.py +++ b/qiskit_experiments/curve_analysis/visualization/fit_result_plotters.py @@ -29,7 +29,7 @@ from uncertainties.core import UFloat from qiskit_experiments.curve_analysis.curve_data import SeriesDef, FitData, CurveData -from qiskit_experiments.framework import AnalysisResultDataF +from qiskit_experiments.framework import AnalysisResultData from qiskit_experiments.framework.matplotlib import get_non_gui_ax @@ -409,7 +409,7 @@ def format_val(float_val: float) -> str: value_repr = f"{val: .3g}" # write error bar if it is finite value - if fitval.std_dev is not None and not np.isinf(fitval.std_dev): + if fitval.std_dev is not None and np.isfinite(fitval.std_dev): # with stderr err, err_prefix = detach_prefix(fitval.std_dev, decimal=3) err_unit = err_prefix + res.unit diff --git a/qiskit_experiments/database_service/db_fitval.py b/qiskit_experiments/database_service/db_fitval.py index 25096f5ec1..cf4fdb180c 100644 --- a/qiskit_experiments/database_service/db_fitval.py +++ b/qiskit_experiments/database_service/db_fitval.py @@ -23,6 +23,8 @@ class FitVal: This data is serializable with the Qiskit Experiment json serializer. """ + # TODO deprecate this (replace with UFloat) + value: float stderr: Optional[float] = None unit: Optional[str] = None diff --git a/qiskit_experiments/framework/base_analysis.py b/qiskit_experiments/framework/base_analysis.py index eb883bd541..fa02927fa7 100644 --- a/qiskit_experiments/framework/base_analysis.py +++ b/qiskit_experiments/framework/base_analysis.py @@ -130,6 +130,7 @@ def _format_analysis_result(self, data, experiment_id, experiment_components=Non device_components = experiment_components # Convert ufloat to FitVal so that database service can parse + # TODO completely deprecate FitVal. We can store UFloat in database. if isinstance(data.value, UFloat): value = FitVal( value=data.value.nominal_value, diff --git a/qiskit_experiments/library/characterization/analysis/cr_hamiltonian_analysis.py b/qiskit_experiments/library/characterization/analysis/cr_hamiltonian_analysis.py index d9bbbbc931..bcdc8069e4 100644 --- a/qiskit_experiments/library/characterization/analysis/cr_hamiltonian_analysis.py +++ b/qiskit_experiments/library/characterization/analysis/cr_hamiltonian_analysis.py @@ -341,9 +341,9 @@ def _extra_database_entry(self, fit_data: curve.FitData) -> List[AnalysisResultD p1_val = fit_data.fitval(f"p{target}1") if control == "z": - coef_val = 0.5 * (p0_val.value - p1_val.value) / (2 * np.pi) + coef_val = 0.5 * (p0_val - p1_val) / (2 * np.pi) else: - coef_val = 0.5 * (p0_val.value + p1_val.value) / (2 * np.pi) + coef_val = 0.5 * (p0_val + p1_val) / (2 * np.pi) extra_entries.append( AnalysisResultData( diff --git a/qiskit_experiments/library/characterization/analysis/drag_analysis.py b/qiskit_experiments/library/characterization/analysis/drag_analysis.py index 5ff686227b..48044a68c4 100644 --- a/qiskit_experiments/library/characterization/analysis/drag_analysis.py +++ b/qiskit_experiments/library/characterization/analysis/drag_analysis.py @@ -180,14 +180,13 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: - 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").value - fit_beta_err = fit_data.fitval("beta").stderr - fit_freq0 = fit_data.fitval("freq0").value + fit_beta = fit_data.fitval("beta") + fit_freq0 = fit_data.fitval("freq0") criteria = [ fit_data.reduced_chisq < 3, - fit_beta < 1 / fit_freq0, - fit_beta_err < abs(fit_beta), + fit_beta.nominal_value < 1 / fit_freq0.nominal_value, + fit_beta.std_dev < abs(fit_beta.nominal_value), ] if all(criteria): diff --git a/qiskit_experiments/library/characterization/analysis/remsey_xy_analysis.py b/qiskit_experiments/library/characterization/analysis/remsey_xy_analysis.py index 6fd2bee1af..289c8cf1d2 100644 --- a/qiskit_experiments/library/characterization/analysis/remsey_xy_analysis.py +++ b/qiskit_experiments/library/characterization/analysis/remsey_xy_analysis.py @@ -158,12 +158,11 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: - 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 + fit_freq = fit_data.fitval("freq") criteria = [ fit_data.reduced_chisq < 3, - fit_freq_err < abs(fit_freq), + fit_freq.std_dev < abs(fit_freq.nominal_value), ] if all(criteria): diff --git a/qiskit_experiments/library/characterization/analysis/t1_analysis.py b/qiskit_experiments/library/characterization/analysis/t1_analysis.py index 5b081f3086..f7832ae408 100644 --- a/qiskit_experiments/library/characterization/analysis/t1_analysis.py +++ b/qiskit_experiments/library/characterization/analysis/t1_analysis.py @@ -66,11 +66,11 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: 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, + abs(amp.nominal_value - 1.0) < 0.1, + abs(base.nominal_value) < 0.1, + amp.std_dev is None or amp.std_dev < 0.1, + tau.std_dev is None or tau.std_dev < tau.nominal_value, + base.std_dev is None or base.std_dev < 0.1, ] if all(criteria): diff --git a/qiskit_experiments/library/characterization/analysis/t2ramsey_analysis.py b/qiskit_experiments/library/characterization/analysis/t2ramsey_analysis.py index 09b918989d..15270939b6 100644 --- a/qiskit_experiments/library/characterization/analysis/t2ramsey_analysis.py +++ b/qiskit_experiments/library/characterization/analysis/t2ramsey_analysis.py @@ -72,9 +72,9 @@ def _evaluate_quality(self, fit_data: curve.FitData) -> Union[str, None]: criteria = [ fit_data.reduced_chisq < 3, - amp.stderr is None or amp.stderr < 0.1 * amp.value, - tau.stderr is None or tau.stderr < 0.1 * tau.value, - freq.stderr is None or freq.stderr < 0.1 * freq.value, + amp.std_dev is None or amp.std_dev < 0.1 * amp.nominal_value, + tau.std_dev is None or tau.std_dev < 0.1 * tau.nominal_value, + freq.std_dev is None or freq.std_dev < 0.1 * freq.nominal_value, ] if all(criteria): diff --git a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_analysis.py index 3ed75234a7..5fd4adff16 100644 --- a/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/interleaved_rb_analysis.py @@ -101,7 +101,6 @@ class InterleavedRBAnalysis(RBAnalysis): filter_kwargs={"interleaved": False}, plot_color="red", plot_symbol=".", - plot_fit_uncertainty=True, model_description=r"a \alpha^{x} + b", ), curve.SeriesDef( @@ -112,7 +111,6 @@ class InterleavedRBAnalysis(RBAnalysis): filter_kwargs={"interleaved": True}, plot_color="orange", plot_symbol="^", - plot_fit_uncertainty=True, model_description=r"a (\alpha_c\alpha)^{x} + b", ), ] @@ -175,14 +173,15 @@ def _extra_database_entry(self, fit_data: curve.FitData) -> List[AnalysisResultD epc = scale * (1 - alpha_c) # Calculate the systematic error bounds - Eq. (5): - systematic_err_1 = scale * (abs(alpha.value - alpha_c.value) + (1 - alpha.value)) + systematic_err_1 = scale * (abs(alpha.n - alpha_c.n) + (1 - alpha.n)) systematic_err_2 = ( - 2 * (nrb * nrb - 1) * (1 - alpha.value) / (alpha.value * nrb * nrb) - + 4 * (np.sqrt(1 - alpha.value)) * (np.sqrt(nrb * nrb - 1)) / alpha.value + 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.nominal_value - systematic_err - systematic_err_r = epc.nominal_value + systematic_err + systematic_err_l = epc.n - systematic_err + systematic_err_r = epc.n + systematic_err extra_data = AnalysisResultData( name="EPC", diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_analysis.py b/qiskit_experiments/library/randomized_benchmarking/rb_analysis.py index 51a771e255..460420ecd0 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_analysis.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_analysis.py @@ -61,7 +61,6 @@ class RBAnalysis(curve.CurveAnalysis): x, amp=a, lamb=-1.0, base=alpha, baseline=b ), plot_color="blue", - plot_fit_uncertainty=True, model_description=r"a \alpha^x + b", ) ] @@ -170,11 +169,12 @@ def _extra_database_entry(self, fit_data: curve.FitData) -> List[AnalysisResultD # 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=scale * (1 - alpha), + value=epc, chisq=fit_data.reduced_chisq, quality=self._evaluate_quality(fit_data), ) diff --git a/qiskit_experiments/library/randomized_benchmarking/rb_utils.py b/qiskit_experiments/library/randomized_benchmarking/rb_utils.py index 1a13c98602..d9b71a0772 100644 --- a/qiskit_experiments/library/randomized_benchmarking/rb_utils.py +++ b/qiskit_experiments/library/randomized_benchmarking/rb_utils.py @@ -289,8 +289,6 @@ def calculate_2q_epg( (qubit_pair, gate_2_qubit_type), 0 ) + gates_per_clifford.get((inverse_qubit_pair, gate_2_qubit_type), 0) - out[qubit_pair] = { - gate_2_qubit_type: 3 / 4 * (1 - alpha_c_2q) / n_gate_2q - } + out[qubit_pair] = {gate_2_qubit_type: 3 / 4 * (1 - alpha_c_2q) / n_gate_2q} return out diff --git a/test/calibration/experiments/test_rabi.py b/test/calibration/experiments/test_rabi.py index cd49762809..981a3faaac 100644 --- a/test/calibration/experiments/test_rabi.py +++ b/test/calibration/experiments/test_rabi.py @@ -57,7 +57,7 @@ def test_rabi_end_to_end(self): result = expdata.analysis_results(0) self.assertEqual(result.quality, "good") - self.assertTrue(abs(result.value.value[1] - backend.rabi_rate) < test_tol) + self.assertAlmostEqual(result.value[1], backend.rabi_rate, delta=test_tol) backend = RabiBackend(amplitude_to_angle=np.pi / 2) @@ -66,7 +66,7 @@ def test_rabi_end_to_end(self): expdata = rabi.run(backend) result = expdata.analysis_results(0) self.assertEqual(result.quality, "good") - self.assertTrue(abs(result.value.value[1] - backend.rabi_rate) < test_tol) + self.assertAlmostEqual(result.value[1], backend.rabi_rate, delta=test_tol) backend = RabiBackend(amplitude_to_angle=2.5 * np.pi) @@ -75,7 +75,7 @@ def test_rabi_end_to_end(self): expdata = rabi.run(backend) result = expdata.analysis_results(0) self.assertEqual(result.quality, "good") - self.assertTrue(abs(result.value.value[1] - backend.rabi_rate) < test_tol) + self.assertAlmostEqual(result.value[1], backend.rabi_rate, delta=test_tol) def test_wrong_processor(self): """Test that we can override the data processing by giving a faulty data processor.""" @@ -272,9 +272,9 @@ def test_good_analysis(self): experiment_data = OscillationAnalysis().run( experiment_data, data_processor=data_processor, plot=False ) - result = experiment_data.analysis_results() - self.assertEqual(result[0].quality, "good") - self.assertTrue(abs(result[0].value.value[1] - expected_rate) < test_tol) + result = experiment_data.analysis_results(0) + self.assertEqual(result.quality, "good") + self.assertAlmostEqual(result.value[1], expected_rate, delta=test_tol) def test_bad_analysis(self): """Test the Rabi analysis.""" diff --git a/test/curve_analysis/test_curve_fit.py b/test/curve_analysis/test_curve_fit.py index 4133a9ba03..4d084c42b0 100644 --- a/test/curve_analysis/test_curve_fit.py +++ b/test/curve_analysis/test_curve_fit.py @@ -10,15 +10,13 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Test curve fitting base class.""" # pylint: disable=invalid-name -from test.base import QiskitExperimentsTestCase -from test.fake_experiment import FakeExperiment + +"""Test curve fitting base class.""" from typing import List + import numpy as np from qiskit.qobj.utils import MeasLevel - -from qiskit_experiments.framework import ExperimentData, FitVal from qiskit_experiments.curve_analysis import CurveAnalysis, fit_function from qiskit_experiments.curve_analysis.curve_data import ( SeriesDef, @@ -28,6 +26,10 @@ ) from qiskit_experiments.curve_analysis.data_processing import probability from qiskit_experiments.exceptions import AnalysisError +from qiskit_experiments.framework import ExperimentData +from test.base import QiskitExperimentsTestCase +from test.fake_experiment import FakeExperiment +from uncertainties import correlated_values def simulate_output_data(func, xvals, param_dict, **metadata): @@ -71,11 +73,14 @@ class TestFitData(QiskitExperimentsTestCase): def test_get_value(self): """Get fit value from fit data object.""" + pcov = np.diag(np.ones(3)) + popt = np.asarray([1.0, 2.0, 3.0]) + fit_params = correlated_values(popt, pcov) + data = FitData( - popt=np.asarray([1.0, 2.0, 3.0]), + popt=fit_params, popt_keys=["a", "b", "c"], - popt_err=np.asarray([0.1, 0.2, 0.3]), - pcov=np.diag(np.ones(3)), + pcov=pcov, reduced_chisq=0.0, dof=0, x_range=(0, 0), @@ -83,13 +88,13 @@ def test_get_value(self): ) a_val = data.fitval("a") - self.assertEqual(a_val, FitVal(1.0, 0.1)) + self.assertEqual(a_val, fit_params[0]) b_val = data.fitval("b") - self.assertEqual(b_val, FitVal(2.0, 0.2)) + self.assertEqual(b_val, fit_params[1]) c_val = data.fitval("c") - self.assertEqual(c_val, FitVal(3.0, 0.3)) + self.assertEqual(c_val, fit_params[2]) class TestCurveAnalysisUnit(QiskitExperimentsTestCase): @@ -328,7 +333,7 @@ def test_run_single_curve_analysis(self): ref_popt = np.asarray([ref_p0, ref_p1, ref_p2, ref_p3]) # check result data - np.testing.assert_array_almost_equal(result.value.value, ref_popt, decimal=self.err_decimal) + np.testing.assert_array_almost_equal(result.value, ref_popt, decimal=self.err_decimal) self.assertEqual(result.extra["dof"], 46) self.assertListEqual(result.extra["popt_keys"], ["p0", "p1", "p2", "p3"]) self.assertDictEqual(result.extra["fit_models"], {"curve1": r"p_0 \exp(p_1 x + p_2) + p_3"}) @@ -336,8 +341,8 @@ def test_run_single_curve_analysis(self): # special entry formatted for database result = results[1] self.assertEqual(result.name, "parameter_name") - self.assertEqual(result.value.unit, "unit") - self.assertAlmostEqual(result.value.value, ref_p1, places=self.err_decimal) + self.assertEqual(result.unit, "unit") + self.assertAlmostEqual(result.value.nominal_value, ref_p1, places=self.err_decimal) def test_run_single_curve_fail(self): """Test analysis returns status when it fails.""" @@ -426,7 +431,7 @@ def test_run_two_curves_with_same_fitfunc(self): ref_popt = np.asarray([ref_p0, ref_p1, ref_p2, ref_p3, ref_p4]) # check result data - np.testing.assert_array_almost_equal(result.value.value, ref_popt, decimal=self.err_decimal) + np.testing.assert_array_almost_equal(result.value, ref_popt, decimal=self.err_decimal) def test_run_two_curves_with_two_fitfuncs(self): """Test analysis for two curves. Curves shares fit parameters.""" @@ -480,7 +485,7 @@ def test_run_two_curves_with_two_fitfuncs(self): ref_popt = np.asarray([ref_p0, ref_p1, ref_p2, ref_p3]) # check result data - np.testing.assert_array_almost_equal(result.value.value, ref_popt, decimal=self.err_decimal) + np.testing.assert_array_almost_equal(result.value, ref_popt, decimal=self.err_decimal) def test_run_fixed_parameters(self): """Test analysis when some of parameters are fixed.""" @@ -517,7 +522,7 @@ def test_run_fixed_parameters(self): ref_popt = np.asarray([ref_p0, ref_p1, ref_p3]) # check result data - np.testing.assert_array_almost_equal(result.value.value, ref_popt, decimal=self.err_decimal) + np.testing.assert_array_almost_equal(result.value, ref_popt, decimal=self.err_decimal) def test_fixed_param_is_missing(self): """Test raising an analysis error when fixed parameter is missing.""" diff --git a/test/randomized_benchmarking/test_rb_analysis.py b/test/randomized_benchmarking/test_rb_analysis.py index 6802848bd8..187003487a 100644 --- a/test/randomized_benchmarking/test_rb_analysis.py +++ b/test/randomized_benchmarking/test_rb_analysis.py @@ -24,7 +24,8 @@ ) from qiskit_experiments.framework import ExperimentData from qiskit_experiments.library import StandardRB, InterleavedRB -from qiskit_experiments.framework import ExperimentDecoder, FitVal +from qiskit_experiments.framework import ExperimentDecoder +from qiskit_experiments.database_service.db_fitval import FitVal ATOL_DEFAULT = 1e-2 RTOL_DEFAULT = 1e-5 diff --git a/test/randomized_benchmarking/test_rb_utils.py b/test/randomized_benchmarking/test_rb_utils.py index da5b8ddbc5..d1d85832ca 100644 --- a/test/randomized_benchmarking/test_rb_utils.py +++ b/test/randomized_benchmarking/test_rb_utils.py @@ -15,6 +15,7 @@ """ from test.base import QiskitExperimentsTestCase import numpy as np +from uncertainties import ufloat from ddt import ddt, data, unpack from qiskit import QuantumCircuit @@ -33,7 +34,6 @@ from qiskit.quantum_info import Clifford import qiskit_experiments.library.randomized_benchmarking as rb from qiskit_experiments.framework import AnalysisResultData -from qiskit_experiments.database_service.db_fitval import FitVal @ddt @@ -83,22 +83,24 @@ def test_calculate_1q_epg(self): in the RB experiment, the gate counts, and an estimate about the relations between the errors of different gate types """ - epc_1_qubit = FitVal(0.0037, 0) + epc_1_qubit = ufloat(0.0037, 0) qubits = [0] gate_error_ratio = {((0,), "id"): 1, ((0,), "rz"): 0, ((0,), "sx"): 1, ((0,), "x"): 1} gates_per_clifford = {((0,), "rz"): 10.5, ((0,), "sx"): 8.15, ((0,), "x"): 0.25} epg = rb.RBUtils.calculate_1q_epg(epc_1_qubit, qubits, gate_error_ratio, gates_per_clifford) error_dict = { - ((0,), "rz"): FitVal(0, 0), - ((0,), "sx"): FitVal(0.0004432101747785104, 0), - ((0,), "x"): FitVal(0.0004432101747785104, 0), + ((0,), "rz"): ufloat(0, 0), + ((0,), "sx"): ufloat(0.0004432101747785104, 0), + ((0,), "x"): ufloat(0.0004432101747785104, 0), } for gate in ["x", "sx", "rz"]: expected_epg = error_dict[((0,), gate)] actual_epg = epg[(0,)][gate] - self.assertTrue(np.allclose(expected_epg.value, actual_epg.value, atol=0.001)) - self.assertTrue(np.allclose(expected_epg.stderr, actual_epg.stderr, atol=0.001)) + self.assertAlmostEqual( + expected_epg.nominal_value, actual_epg.nominal_value, delta=0.001 + ) + self.assertAlmostEqual(expected_epg.std_dev, actual_epg.std_dev, delta=0.001) def test_calculate_2q_epg(self): """Testing the calculation of 2 qubit error per gate @@ -106,7 +108,7 @@ def test_calculate_2q_epg(self): in the RB experiment, the gate counts, and an estimate about the relations between the errors of different gate types """ - epc_2_qubit = FitVal(0.034184849962675984, 0) + epc_2_qubit = ufloat(0.034184849962675984, 0) qubits = [1, 4] gate_error_ratio = { ((1,), "id"): 1, @@ -146,13 +148,13 @@ def test_calculate_2q_epg(self): ) error_dict = { - ((1, 4), "cx"): FitVal(0.012438847900902494, 0), + ((1, 4), "cx"): ufloat(0.012438847900902494, 0), } expected_epg = error_dict[((1, 4), "cx")] actual_epg = epg[(1, 4)]["cx"] - self.assertTrue(np.allclose(expected_epg.value, actual_epg.value, atol=0.001)) - self.assertTrue(np.allclose(expected_epg.stderr, actual_epg.stderr, atol=0.001)) + self.assertAlmostEqual(expected_epg.nominal_value, actual_epg.nominal_value, delta=0.001) + self.assertAlmostEqual(expected_epg.std_dev, actual_epg.std_dev, delta=0.001) def test_coherence_limit(self): """Test coherence_limit.""" diff --git a/test/test_t1.py b/test/test_t1.py index 5499fec60b..5749be31a5 100644 --- a/test/test_t1.py +++ b/test/test_t1.py @@ -152,7 +152,7 @@ def test_t1_analysis(self): res, _ = T1Analysis()._run_analysis(data) result = res[1] self.assertEqual(result.quality, "good") - self.assertAlmostEqual(result.value.value, 25e-9, delta=3) + self.assertAlmostEqual(result.value.nominal_value, 25e-9, delta=3) def test_t1_metadata(self): """