12
12
"""Fit models that are used for curve fitting."""
13
13
14
14
from abc import ABC , abstractmethod
15
- from typing import Callable , List , Optional
15
+ from typing import Callable , List , Optional , Union
16
16
17
17
import numpy as np
18
18
19
19
from qiskit_experiments .exceptions import AnalysisError
20
20
21
21
22
22
class FitModel (ABC ):
23
- """Base class of fit models.
23
+ r """Base class of fit models.
24
24
25
25
This is a function-like object that implements a fit model as a ``__call__`` magic method,
26
26
thus it behaves like a Python function that the SciPy curve_fit solver accepts.
@@ -29,22 +29,74 @@ class FitModel(ABC):
29
29
This class ties together the fit function and associated parameter names to
30
30
perform correct parameter mapping among multiple objective functions with different signatures,
31
31
in which some parameters may be excluded from the fitting when they are fixed.
32
+
33
+ Examples:
34
+
35
+ Given we have two functions :math:`F_1(x_1, p_0, p_1, p_2)` and :math:`F_2(x_2, p_0, p_3)`.
36
+ During the fit, we assign :math:`p_1=2` and exclude it from the fitting.
37
+ This is formulated with set operation as follows:
38
+
39
+ .. math::
40
+
41
+ \Theta_1 = \{ p_0, p_1, p_2 \}, \Theta_2 = \{p_0, p_3\}, \Theta_{\rm fix} = \{p_1\}
42
+
43
+ Note that :class:`FitModel` subclass is instantiated with a list of
44
+ :math:`F_1` and :math:`F_2` (``fit_functions``) together with
45
+ a list of :math:`\Theta_1` and :math:`\Theta_2` (``signatures``) and
46
+ :math:`\Theta_{\rm fix}` (``fixed_parameters``).
47
+ The signature of new fit model instance will be
48
+ :math:`\Theta = (\Theta_1 \cup \Theta_2) - \Theta_{\rm fix} = \{ p_0, p_2, p_3\}`.
49
+ The fit function that this model provides is accordingly
50
+
51
+ .. math::
52
+
53
+ F(x, \Theta) = F(x_0 \oplus x_1, p_0, p_2, p_3).
54
+
55
+ This function might be called from the scipy curve fit algorithm
56
+ which only takes variadic arguments (i.e. agnostic to parameter names).
57
+
58
+ .. math::
59
+
60
+ F(x, {\rm *args}) = F(x,\bar{p}_0, \bar{p}_1, \bar{p}_2)
61
+
62
+ The fit model internally maps :math:`\bar{p}_0 \rightarrow p_0`,
63
+ :math:`\bar{p}_1 \rightarrow p_2`, and :math:`\bar{p}_2 \rightarrow p_3`
64
+ while assigning :math:`p_1=2` when its called from the curve fitting algorithm.
65
+ Note that this mapping is performed in the ``__call__`` method.
66
+ The function signature :math:`\Theta` is provided with the property :attr:`signature`.
67
+
68
+ Notes:
69
+
70
+ This class is usually instantiated with the :class:`SeriesDef` in the
71
+ ``__init_subclass__`` method of :class:`CurveAnalysis` subclasses.
72
+ User doesn't need to take care of input values to the constructor
73
+ unless one manually instantiates the class for debugging purpose.
32
74
"""
33
75
34
76
def __init__ (
35
77
self ,
36
78
fit_functions : List [Callable ],
37
79
signatures : List [List [str ]],
38
- fit_models : Optional [List [str ]] = None ,
80
+ fit_models : Optional [Union [ List [str ], str ]] = None ,
39
81
fixed_parameters : Optional [List [str ]] = None ,
40
82
):
41
83
"""Create new fit model.
42
84
43
85
Args:
44
- fit_functions: List of callables that defines fit function of a single series.
45
- signatures: List of parameter names of a single series.
46
- fit_models: List of string representation of fit functions.
47
- fixed_parameters: List of parameter names that are fixed in the fit.
86
+ fit_functions: List of callables that forms the fit model for a
87
+ particular curve analysis class. It may consists of multiple curves.
88
+ signatures: List of argument names that each fit function callable takes.
89
+ The length of the list should be identical to the ``fit_functions``.
90
+ fit_models: String representation of fit functions.
91
+ Because this is just a metadata, the format of input value doesn't matter.
92
+ It may be a single string description for the entire fit model, or
93
+ list of descriptions for each fit functions. If not provided,
94
+ "not defined" is stored in the experiment result metadata.
95
+ fixed_parameters: List of parameter names that are not considered to be fit parameter.
96
+ The value of parameter is provided by analysis default setting or users,
97
+ which is fixed during the curve fitting. Arbitrary number of parameters
98
+ in the fit model can be fixed, however, every parameter should be
99
+ defined in the model.
48
100
49
101
Raises:
50
102
AnalysisError: When ``fit_functions`` and ``signatures`` don't match.
@@ -54,8 +106,14 @@ def __init__(
54
106
55
107
self ._fit_functions = fit_functions
56
108
self ._signatures = signatures
57
- self ._fit_models = fit_models or [None for _ in range (len (fit_functions ))]
58
109
110
+ # String representation of the fit model. This is stored as a list of string.
111
+ if not fit_models or isinstance (fit_models , str ):
112
+ fit_models = [fit_models ]
113
+ self ._fit_models = fit_models
114
+
115
+ # No validation is performed since this class is always instantiated from the
116
+ # curve analysis class itself. The validation is performed there.
59
117
if not fixed_parameters :
60
118
fixed_parameters = []
61
119
self ._fixed_params = {p : None for p in fixed_parameters }
@@ -121,13 +179,17 @@ class SingleFitFunction(FitModel):
121
179
the fit parameters and the fixed parameters :math:`\Theta_{\rm fix}`.
122
180
The function :math:`f` is usually set by :attr:`SeriesDef.fit_func` which is
123
181
a standard python function.
182
+
183
+ .. seealso::
184
+
185
+ Class :class:`FitModel`.
124
186
"""
125
187
126
188
def __call__ (self , x : np .ndarray , * params ) -> np .ndarray :
127
189
"""Compute values of fit functions.
128
190
129
191
Args:
130
- x: Composite X values array.
192
+ x: Input X values array.
131
193
*params: Variadic argument provided from the fitter.
132
194
133
195
Returns:
@@ -166,6 +228,10 @@ class CompositeFitFunction(FitModel):
166
228
This data represents the location where the function with index ``i``
167
229
is returned and where the x values :math:`x_i` comes from.
168
230
One must set this data indices before calling the composite fit function.
231
+
232
+ .. seealso::
233
+
234
+ Class :class:`FitModel`.
169
235
"""
170
236
171
237
def __init__ (
@@ -182,7 +248,7 @@ def __call__(self, x: np.ndarray, *params) -> np.ndarray:
182
248
"""Compute values of fit functions.
183
249
184
250
Args:
185
- x: Composite X values array.
251
+ x: Input X values array.
186
252
*params: Variadic argument provided from the fitter.
187
253
188
254
Returns:
0 commit comments