Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate FitVal and support saving/loading UFloat #564

Merged
Merged
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
cd67ca7
add fit function wrapper
nkanazawa1989 Nov 30, 2021
a733d9a
offload error propagation to uncertainties package
nkanazawa1989 Dec 1, 2021
d875ba7
remove FitVal from experiments (replaced with ufloat)
nkanazawa1989 Dec 1, 2021
4050a5f
use better alias
nkanazawa1989 Dec 1, 2021
b204540
replace np function with unp
nkanazawa1989 Dec 1, 2021
2b19a10
keep fit parameter correlation
nkanazawa1989 Dec 1, 2021
2ad7511
cleanup
nkanazawa1989 Dec 1, 2021
394b564
lint
nkanazawa1989 Dec 2, 2021
d5a234a
minor fix
nkanazawa1989 Dec 2, 2021
2d97ba5
fix import
nkanazawa1989 Dec 2, 2021
87ba919
reno
nkanazawa1989 Dec 2, 2021
c1ee1f6
Merge branch 'main' into upgrade/curve_analysis_uncertainties
nkanazawa1989 Dec 6, 2021
9aaeab4
Update qiskit_experiments/curve_analysis/curve_data.py
nkanazawa1989 Dec 6, 2021
47e92ed
Update qiskit_experiments/curve_analysis/fit_function.py
nkanazawa1989 Dec 6, 2021
13724db
Update qiskit_experiments/curve_analysis/fit_function.py
nkanazawa1989 Dec 6, 2021
9405937
Update releasenotes/notes/upgrade-curve-fit-4dc01b1db55ee398.yaml
nkanazawa1989 Dec 6, 2021
a238d97
add error if finite
nkanazawa1989 Dec 6, 2021
602bf79
add safeguard for nan stdev
nkanazawa1989 Dec 6, 2021
9e9715b
update decorator name
nkanazawa1989 Dec 6, 2021
ab23437
Merge branch 'upgrade/curve_analysis_uncertainties' of github.com:nka…
nkanazawa1989 Dec 6, 2021
6e149e9
tag issue to TODO
nkanazawa1989 Dec 6, 2021
707ffec
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Dec 6, 2021
af3f489
black
nkanazawa1989 Dec 6, 2021
3b822b6
update tutorials
nkanazawa1989 Dec 6, 2021
320e444
fix bug
nkanazawa1989 Dec 6, 2021
3066dbc
black
nkanazawa1989 Dec 6, 2021
f8922fc
fix bug
nkanazawa1989 Dec 6, 2021
8ba8e48
replace FitVal with UFloat in database
nkanazawa1989 Dec 8, 2021
432529b
add 3 sigma area
nkanazawa1989 Dec 8, 2021
ef79416
replace util function name
nkanazawa1989 Dec 8, 2021
97113d3
update docs
nkanazawa1989 Dec 8, 2021
2a9b9a4
Merge branch 'main' into upgrade/curve_analysis_uncertainties
nkanazawa1989 Dec 8, 2021
670d4be
change until function name to be more precise
nkanazawa1989 Dec 8, 2021
776af49
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Dec 10, 2021
7b4e8e8
rerun tutorials
nkanazawa1989 Dec 10, 2021
674f9d0
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Jan 28, 2022
486ad8a
update unitest to use UFloat
nkanazawa1989 Jan 28, 2022
266ef45
undone db analysis result and update serializer
nkanazawa1989 Jan 28, 2022
ceaf29e
Merge branch 'upgrade/curve_analysis_uncertainties' into upgrade/repl…
nkanazawa1989 Jan 29, 2022
1a8d257
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Feb 2, 2022
90acfc7
Convert FitVal to UFloat at construction
chriseclectic Feb 2, 2022
6185179
review comments
nkanazawa1989 Feb 2, 2022
1d4be17
tox
chriseclectic Feb 2, 2022
f386b74
deprecation reno
chriseclectic Feb 2, 2022
001e583
Merge branch 'upgrade/replace_fitval' into upgrade/replace_fitvale
chriseclectic Feb 2, 2022
4f15461
Merge pull request #6 from chriseclectic/upgrade/replace_fitvale
nkanazawa1989 Feb 2, 2022
9fb7cf7
lint
nkanazawa1989 Feb 2, 2022
e97c17e
Merge branch 'upgrade/replace_fitval' of github.com:nkanazawa1989/qis…
nkanazawa1989 Feb 2, 2022
15e7883
lint
nkanazawa1989 Feb 2, 2022
3d006a2
fix dataclass initialization bug
nkanazawa1989 Feb 2, 2022
5b58124
fix unit handling in cr ham analysis
nkanazawa1989 Feb 2, 2022
9e54068
fix test
nkanazawa1989 Feb 2, 2022
478b4f4
add UFloat alias to framework init
nkanazawa1989 Feb 2, 2022
b475b51
monkey patching Variable and AffineScalarFunc
nkanazawa1989 Feb 4, 2022
c623146
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Feb 7, 2022
0ad881d
update GaussianAnalysis to use new properties
nkanazawa1989 Feb 7, 2022
8598323
update fit function
nkanazawa1989 Feb 7, 2022
e220e5d
remove monkey patch
nkanazawa1989 Feb 7, 2022
229da32
Merge branch 'upgrade/update_sqrt_lorentzian' into upgrade/replace_fi…
nkanazawa1989 Feb 7, 2022
b81fc7a
regenerate qv test cache
nkanazawa1989 Feb 7, 2022
72cf66a
fix test
nkanazawa1989 Feb 7, 2022
9ded893
add branching for all parameters entry
nkanazawa1989 Feb 7, 2022
ebafdda
lint
nkanazawa1989 Feb 7, 2022
0db84bd
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Feb 7, 2022
f0b7d66
revert notebooks
nkanazawa1989 Feb 7, 2022
5a0684c
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into upgr…
nkanazawa1989 Feb 7, 2022
26e2a4b
update type check
nkanazawa1989 Feb 7, 2022
31905c3
remove not existing classes from docs tree
nkanazawa1989 Feb 7, 2022
6847877
remove ambiguous reference from reno
nkanazawa1989 Feb 7, 2022
bc066a4
alleviate timeout of cr ham tomo test
nkanazawa1989 Feb 8, 2022
800a171
Review comments
nkanazawa1989 Feb 8, 2022
90329b3
Merge branch 'main' into upgrade/replace_fitval
nkanazawa1989 Feb 8, 2022
04649cd
update Tphi to remove explicit cast into UFloat and access to depreca…
nkanazawa1989 Feb 8, 2022
7c42f54
Merge branch 'main' into upgrade/replace_fitval
nkanazawa1989 Feb 9, 2022
0c9c9fb
Merge branch 'main' into upgrade/replace_fitval
nkanazawa1989 Feb 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions qiskit_experiments/calibration_management/update_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ def get_value(exp_data: ExperimentData, param_name: str, index: Optional[int] =
# must be passed to analysis results so we don't block indefinitely
candidates = exp_data.analysis_results(param_name, block=False)
if isinstance(candidates, list):
return candidates[index].value.value
return candidates[index].value.nominal_value
else:
return candidates.value.value
return candidates.value.nominal_value


class Frequency(BaseUpdater):
Expand Down
9 changes: 8 additions & 1 deletion qiskit_experiments/curve_analysis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,15 @@
plot_curve_fit
plot_errorbar
plot_scatter

Utilities
*********
.. autosummary::
:toctree: ../stubs/

is_error_not_significant
"""
from .curve_analysis import CurveAnalysis
from .curve_analysis import CurveAnalysis, is_error_not_significant
from .curve_data import CurveData, SeriesDef, FitData, ParameterRepr, FitOptions
from .curve_fit import (
curve_fit,
Expand Down
69 changes: 49 additions & 20 deletions qiskit_experiments/curve_analysis/curve_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@
"""
# pylint: disable=invalid-name

import copy
import dataclasses
import functools
import inspect
import warnings
from abc import ABC
from typing import Any, Dict, List, Tuple, Callable, Union, Optional
from uncertainties import unumpy as unp

import numpy as np
from qiskit.providers import Backend
import uncertainties
from uncertainties import unumpy as unp

from qiskit.providers import Backend
from qiskit_experiments.curve_analysis.curve_data import (
CurveData,
SeriesDef,
Expand All @@ -44,7 +46,6 @@
BaseAnalysis,
ExperimentData,
AnalysisResultData,
FitVal,
Options,
)

Expand Down Expand Up @@ -72,8 +73,6 @@ class CurveAnalysis(BaseAnalysis, ABC):
- ``name``: Name of the curve. This is arbitrary data field, but should be unique.
- ``plot_color``: String color representation of this series in the plot.
- ``plot_symbol``: String formatter of the scatter of this series in the plot.
- ``plot_fit_uncertainty``: A Boolean signaling whether to plot fit uncertainty
nkanazawa1989 marked this conversation as resolved.
Show resolved Hide resolved
for this series in the plot.

- ``__fixed_parameters__``: A list of parameter names fixed during the fitting.
These parameters should be provided in some way. For example, you can provide
Expand Down Expand Up @@ -574,22 +573,17 @@ def _is_target_series(datum, **filters):

x_key = self.options.x_key
try:
x_values = np.asarray([datum["metadata"][x_key] for datum in data], dtype=float)
xdata = np.asarray([datum["metadata"][x_key] for datum in data], dtype=float)
except KeyError as ex:
raise DataProcessorError(
f"X value key {x_key} is not defined in circuit metadata."
) from ex

if isinstance(data_processor, DataProcessor):
y_data = data_processor(data)

y_nominals = unp.nominal_values(y_data)
y_stderrs = unp.std_devs(y_data)
ydata = data_processor(data)
else:
y_nominals, y_stderrs = zip(*map(data_processor, data))

y_nominals = np.asarray(y_nominals, dtype=float)
y_stderrs = np.asarray(y_stderrs, dtype=float)
ydata = unp.uarray(y_nominals, y_stderrs)

# Store metadata
metadata = np.asarray([datum["metadata"] for datum in data], dtype=object)
Expand All @@ -598,7 +592,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
Expand All @@ -608,9 +602,9 @@ def _is_target_series(datum, **filters):
# Store raw data
raw_data = CurveData(
label="raw_data",
x=x_values,
y=y_nominals,
y_err=y_stderrs,
x=xdata,
y=unp.nominal_values(ydata),
y_err=unp.std_devs(ydata),
shots=shots,
data_index=data_index,
metadata=metadata,
Expand Down Expand Up @@ -878,7 +872,7 @@ def _run_analysis(
analysis_results.append(
AnalysisResultData(
name=PARAMS_ENTRY_PREFIX + self.__class__.__name__,
value=FitVal(fit_result.popt, fit_result.popt_err),
value=[p.nominal_value for p in fit_result.popt],
chisq=fit_result.reduced_chisq,
quality=quality,
extra={
Expand All @@ -903,12 +897,20 @@ def _run_analysis(
p_name = param_repr
p_repr = param_repr
unit = None

fit_val = fit_result.fitval(p_name)
if unit:
metadata = copy.copy(self.options.extra)
metadata["unit"] = unit
else:
metadata = self.options.extra

result_entry = AnalysisResultData(
name=p_repr,
value=fit_result.fitval(p_name, unit),
value=fit_val,
chisq=fit_result.reduced_chisq,
quality=quality,
extra=self.options.extra,
extra=metadata,
)
analysis_results.append(result_entry)

Expand Down Expand Up @@ -961,3 +963,30 @@ def _run_analysis(
figures = []

return analysis_results, figures


def is_error_not_significant(
val: Union[float, uncertainties.UFloat],
fraction: float = 1.0,
absolute: Optional[float] = None,
) -> bool:
"""Check if the standard error of given value is not significant.

Args:
val: Input value to evaluate. This is assumed to be float or ufloat.
fraction: Valid fraction of the nominal part to its standard error.
This function returns ``False`` if the nominal part is
smaller than the error by this fraction.
absolute: Use this value as a threshold if given.

Returns:
``True`` if the standard error of given value is not significant.
"""
if isinstance(val, float):
return True

threshold = absolute if absolute is not None else fraction * val.nominal_value
if np.isnan(val.std_dev) or val.std_dev < threshold:
return True

return False
23 changes: 6 additions & 17 deletions qiskit_experiments/curve_analysis/curve_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
from typing import Any, Dict, Callable, Union, List, Tuple, Optional, Iterable

import numpy as np

import uncertainties
from qiskit_experiments.exceptions import AnalysisError
from qiskit_experiments.framework import FitVal


@dataclasses.dataclass(frozen=True)
Expand All @@ -42,9 +41,6 @@ class SeriesDef:
# Symbol to represent data points of this line.
plot_symbol: str = "o"

# Whether to plot fit uncertainty for this line.
plot_fit_uncertainty: bool = False

# Latex description of this fit model
model_description: Optional[str] = None

Expand Down Expand Up @@ -83,14 +79,11 @@ class FitData:
"""Set of data generated by the fit function."""

# Order sensitive fit parameter values
popt: np.ndarray
popt: List[uncertainties.UFloat]

# Order sensitive parameter name list
popt_keys: List[str]

# Order sensitive fit parameter uncertainty
popt_err: np.ndarray

# Covariance matrix
pcov: np.ndarray

Expand All @@ -106,26 +99,22 @@ class FitData:
# Y data range
y_range: Tuple[float, float]

def fitval(self, key: str, unit: Optional[str] = None) -> FitVal:
def fitval(self, key: str) -> uncertainties.UFloat:
"""A helper method to get fit value object from parameter key name.

Args:
key: Name of parameters to extract.
unit: Optional. Unit of this value.

Returns:
FitVal object.
A UFloat object which functions as a standard Python float object
but with automatic error propagation.

Raises:
ValueError: When specified parameter is not defined.
"""
try:
index = self.popt_keys.index(key)
return FitVal(
value=self.popt[index],
stderr=self.popt_err[index],
unit=unit,
)
return self.popt[index]
except ValueError as ex:
raise ValueError(f"Parameter {key} is not defined.") from ex

Expand Down
25 changes: 18 additions & 7 deletions qiskit_experiments/curve_analysis/curve_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from typing import List, Dict, Tuple, Callable, Optional, Union

import numpy as np
import uncertainties
import scipy.optimize as opt
from qiskit_experiments.exceptions import AnalysisError
from qiskit_experiments.curve_analysis.data_processing import filter_data
Expand Down Expand Up @@ -62,8 +63,9 @@ 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.

.. note::
``sigma`` is assumed to be specified in the same units as ``ydata``
Expand Down Expand Up @@ -92,7 +94,7 @@ def fit_func(x, *params):
return func(x, **dict(zip(param_keys, params)))

else:
param_keys = None
param_keys = [f"p{i}" for i in range(len(p0))]
param_p0 = p0
if bounds:
param_bounds = bounds
Expand Down Expand Up @@ -134,7 +136,17 @@ def fit_func(x, *params):
"scipy.optimize.curve_fit failed with error: {}".format(str(ex))
) from ex

popt_err = np.sqrt(np.diag(pcov))
if np.isfinite(pcov).all():
# Keep parameter correlations in following analysis steps
fit_params = uncertainties.correlated_values(
nom_values=popt, covariance_mat=pcov, tags=param_keys
)
else:
# Ignore correlations, add standard error if finite.
fit_params = [
uncertainties.ufloat(nominal_value=n, std_dev=s if np.isfinite(s) else np.nan)
for n, s in zip(popt, np.sqrt(np.diag(pcov)))
]

# Calculate the reduced chi-squared for fit
yfits = fit_func(xdata, *popt)
Expand All @@ -148,9 +160,8 @@ def fit_func(x, *params):
ydata_range = np.min(ydata), np.max(ydata)

return FitData(
popt=popt,
popt_keys=param_keys,
popt_err=popt_err,
popt=list(fit_params),
popt_keys=list(param_keys),
pcov=pcov,
reduced_chisq=reduced_chisq,
dof=dof,
Expand Down
Loading