mpfit overview
mpfit is a wrapper around the cMPFIT library for Nim.
Usage of the library is centered around a single fit procedure, with signature:
proc fit*[T](f: FuncProto[T], pS: openArray[T], x, y, ey: openArray[T]): (seq[T], mp_result) =
the first argument is a user defined function (see below), the following arguments are:
- pS: the first guess for the parameters
- x: data for x
- y: data for y
- ey: errors for y
The FuncProto[T] type is simply a specific signature for a proc, which takes a sequence of parameters and a value. It is the user defined function to be fitted.
Internally the function and the data is stored in a VarStruct object:
type VarStruct*[T] = ref object x: seq[T] y: seq[T] ey: seq[T] f: FuncProto[T]
This is done, because the C library accepts a function to be fitted of the form:
mp_func* = proc (m: cint; n: cint; x: ptr cdouble; fvec: ptr cdouble; dvec: ptr ptr cdouble; private_data: var pointer): cint {.cdecl.}
where m is the number of data points, n the number of parameters, x a pointer to the sequence of parameters, fvec a pointer to the sequence of deviates and dvec allows for user computed derivates (which are currently not implemented).
The last parameter private_data is an opaque pointer and the reason for the VarStruct object. We hand the user data and user function to the mp_func via a cast to a pointer. A funcImpl wrapper proc of the signature mp_func casts this opaque pointer back to VarStruct[float] (yes, currently it explicitly casts back to float, so the allowed signature is actually only FuncProto[float] for the time being), and calls the user function with the data computing the deviates:
for i in 0 ..< m: f = ff(pCall, x[i]) dy[i] = (y[i] - f) / ey[i]
where ff is the user function and pCall the parameters as a seq[float] (since they have to be handed as a ptr cdouble we have to convert to seq[float] first).
For an example see the https://github.com/Vindaar/nim-mpfit/blob/master/README.org.
Types
FuncProto[T] = proc (p: seq[T]; x: T): T
MpConfig = object ftol*: float ## NOTE: the user may set the value explicitly; OR, if the passed ## value is zero, then the "Default" value will be substituted by ## mpfit(). ## Relative chi-square convergence criterium Default: 1e-10 xtol*: float ## Relative parameter convergence criterium Default: 1e-10 gtol*: float ## Orthogonality convergence criterium Default: 1e-10 epsfcn*: float ## Finite derivative step size Default: MP_MACHEP0 stepFactor*: float ## Initial step bound Default: 100.0 covtol*: float ## Range tolerance for covariance calculation Default: 1e-14 maxiter*: int ## Maximum number of iterations. If maxiter == MP_NO_ITER, ## then basic error checking is done, and parameter ## errors/covariances are estimated based on input ## parameter values, but no fitting iterations are done. ## Default: 200 ## maxfev*: int ## Maximum number of function evaluations, or 0 for no limit ## Default: 0 (no limit) nprint*: int ## Default: 1 doUserScale*: bool ## Scale variables by user values? ## 1 = yes, user scale values in diag; ## 0 = no, variables scaled internally (Default) noFiniteCheck*: bool ## Disable check for infinite quantities from user? ## 0 = do not perform check (Default) ## 1 = perform check
Procs
func chiSq(res: mp_result): float {....raises: [], tags: [].}
- given an mp_result, return the chi^2 of the fit
func cov(res: mp_result): seq[seq[float]] {....raises: [], tags: [].}
- given an mp_result, return the covariance matrix of the fit parameters as a nested seq of shape [npar, npar]
proc echoResult(x: openArray[float]; res: mp_result; xact: openArray[float] = @[]) {....raises: [ValueError], tags: [].}
-
A convenience proc to echo the fit parameters and their errors as well as the properties of the fit, e.g. chi^2 etc.
The first argument x are the final resulting fit paramters (the first return value of fit, xact are the actual values (e.g.. your possibly known parameters you want to compare with in case the fit was only a cross check) and res is the mp_result object, the second return value of the fit proc.
func error(res: mp_result): seq[float] {....raises: [], tags: [].}
- given an mp_result, return the errors of the fit parameters
proc fit[T](userFunc: FuncProto[T]; pS: openArray[T]; x, y, ey: openArray[T]; bounds: seq[tuple[l, u: float]] = @[]; config = none[MpConfig]()): ( seq[T], mp_result)
-
The actual fit procedure, which needs to be called by the user. userFunc is the function to be fitted to the data x, y and ey, where ey is the error on y.
It's possible to set bounds on the fit parameters, by handing a seq (one element per parameter) of lower l and upper u bound values.
proc pretty(x: openArray[float]; res: mp_result; xact: openArray[float] = @[]; unicode = true; precision = -1; prefix = " "): string {. ...raises: [ValueError], tags: [].}
-
A convenience proc to echo the fit parameters and their errors as well as the properties of the fit, e.g. chi^2 etc.
The first argument x are the final resulting fit paramters (the first return value of fit, xact are the actual values (e.g.. your possibly known parameters you want to compare with in case the fit was only a cross check) and res is the mp_result object, the second return value of the fit proc.
func reducedChiSq(res: mp_result): float {....raises: [], tags: [].}
-
given an mp_result, return the reduced chi^2 of the fit, i.e.
reducedChiSq = \chi^2 / d.o.f = \chi^2 / (# data points - # parameters)
Exports
-
mp_par, MP_ERR_NPOINTS, MP_ERR_FUNC, MP_RDWARF, mp_func, mp_iterproc, MP_OK_BOTH, mpfit, MP_ERR_DOF, MP_DWARF, MP_XTOL, MP_ERR_NAN, MP_ERR_NFREE, MP_OK_CHI, MP_FTOL, MP_ERR_PARAM, MP_NO_ITER, MP_ERR_MEMORY, MP_GTOL, mp_par_struct, MP_ERR_BOUNDS, MP_OK_DIR, mp_config_struct, mp_config, MP_GIANT, MP_ERR_INPUT, mp_result_struct, mpfinite, MP_MACHEP0, MP_MAXITER, MP_RGIANT, mp_result, MP_ERR_INITBOUNDS, MP_OK_PAR, MPFIT_VERSION