builddir::bui...::man::lmmin2(3)

πŸ“¦
version 10.0 Β· 2 versions
, in fedora 44

πŸ’– lmmin2 πŸ’– β€” Levenberg-Marquardt least-squares minimization with error estimation

okay bestie, gather round, because this is lmmin2(3) from the lmfit manual and it is lowkey iconic. it does least-squares minimization and error estimation, which is the glow-up over the legacy lmmin(3). let's get into it 🫢


✨ SYNOPSIS ✨

#include <lmmin.h>

void lmmin2( const int n_par, double *par, double *parerr, double *covar,
            const int m_dat, const void *y, const void *data,
            void *evaluate(
                 const double *par, const int m_dat,
                 const void *data, double *fvec, int *userbreak),
            const lm_control_struct *control,
            lm_status_struct *status );

extern const lm_control_struct lm_control_double;

extern const lm_control_struct lm_control_float;

extern const char *lm_infmsg[];

extern const char *lm_shortmsg[];

🌸 DESCRIPTION 🌸

so lmmin2() hunts down a vector par that minimizes the sum of squared elements of fvec-y. the vector fvec gets computed by a function you supply, evaluate(); and y is a vector of values you provide. πŸ’…

heads up bestie: on success, par represents a local minimum, not necessarily a global one 😭 β€” and it may depend on the starting value you gave it. no cap.

the legacy function lmmin(3) gives you a simplified API without error estimates, if that's more your vibe.

the Levenberg-Marquardt minimization starts off with a steepest-descent exploration of the parameter space, and then achieves rapid convergence by crossing over into the Newton-Gauss method. the way it just switches strategies mid-fit ✨


πŸŽ€ Function arguments πŸŽ€

  • n_par β€” number of free variables, i.e. the length of the parameter vector par.
  • par β€” the parameter vector, length n_par. on input it must hold a reasonable guess; on output it holds the solution found to minimize ||fvec||.
  • parerr β€” parameter error vector, either length n_par or NULL. on output, unless it's NULL, it holds the parameter uncertainties for the unweighted model, estimated from the diagonal elements of the covariance matrix and the sum of squared elements of fvec-y divided by m_dat-n_par. 🫢 if your data is weighed, use the square root of the diagonal elements of the covariance matrix for the parameter uncertainties.
  • covar β€” covariance matrix, stored as a vector of length n_par*n_par, or NULL. on output, unless it's NULL, it holds the covariance matrix.
  • m_dat β€” length of the vector fvec. must satisfy n_par <= m_dat.
  • y β€” input vector of length m_dat. it may also be the null pointer; in that case, lmmin() minimizes the squared sum of fvec instead of fvec-y.
  • data β€” this pointer is ignored by the fit algorithm, except that it shows up as an argument in all the calls to your user-supplied routine evaluate.
  • evaluate β€” pointer to a user-supplied function that computes m_dat elements of the vector fvec for a given parameter vector par. if evaluate returns with *userbreak set to a negative value, lmmin() will interrupt the fitting and terminate. πŸ’€
  • control β€” the parameter collection for tuning the fit procedure. in most cases the default &lm_control_double is adequate. if f is only computed with single-precision accuracy, you should use &lm_control_float. see also below, in NOTES, on initializing parameter records.

control has these members (for more details, peep the source file lmstruct.h):

  • double control.ftol β€” relative error desired in the sum of squares. recommended setting: somewhat above machine precision; less if fvec is computed with reduced accuracy.
  • double control.xtol β€” relative error between the last two approximations. recommended setting: as ftol.
  • double control.gtol β€” a measure for degeneracy. recommended setting: as ftol.
  • double control.epsilon β€” step used to calculate the Jacobian. recommended setting: as ftol, but definitely less than the accuracy of fvec.
  • double control.stepbound β€” initial bound to steps in the outer loop, generally between 0.01 and 100; recommended value is 100.
  • int control.patience β€” used to set the maximum number of function evaluations to patience*n_par.
  • int control.scale_diag β€” logical switch (0 or 1). if 1, then scale parameters to their initial value. this is the recommended setting. ✨
  • FILE* control.msgfile β€” progress messages get written to this file. typically stdout or stderr. the value NULL will be interpreted as stdout.
  • int control.verbosity β€” if nonzero, some progress information from within the LM algorithm is written to control.stream.
  • int control.n_maxpri β€” -1, or the maximum number of parameters to print.
  • int control.m_maxpri β€” -1, or the maximum number of residuals to print.
  • status β€” a record used to return info about the minimization process:
    • double status.fnorm β€” norm of the vector fvec;
    • int status.nfev β€” actual number of iterations;
    • int status.outcome β€” status of minimization; for the corresponding text message, print lm_infmsg[status.outcome]; for a short code, print lm_shortmsg[status.outcome].
    • int status.userbreak β€” set when termination has been forced by the user-supplied routine evaluate.

πŸ¦‹ NOTES πŸ¦‹

πŸ“ Initializing parameter records. πŸ“

the parameter record control should always be initialized from the supplied default records:

lm_control_struct control = lm_control_double; /* or _float */

after this, parameters may be overwritten:

control.patience = 500; /* allow more iterations */
control.verbosity = 15; /* for verbose monitoring */

an application written this way is guaranteed to work even if new parameters are added to lm_control_struct. πŸ‘‘

conversely, addition of parameters is not considered an API change; it may happen without an increment of the major version number. iykyk πŸ™ˆ


🌈 EXAMPLES 🌈

🧚 Fitting a surface 🧚

fit a data set y(t) by a function f(t;p) where t is a two-dimensional vector:

#include "lmmin.h"
#include <stdio.h>

/* fit model: a plane p0 + p1*tx + p2*tz */
double f( double tx, double tz, const double *p )
{
    return p[0] + p[1]*tx + p[2]*tz;
}

/* data structure to transmit data arays and fit model */
typedef struct {
    double *tx, *tz;
    double *y;
    double (*f)( double tx, double tz, const double *p );
} data_struct;

/* function evaluation, determination of residues */
void evaluate_surface( const double *par, int m_dat,
    const void *data, double *fvec, int *userbreak )
{
    /* for readability, explicit type conversion */
    data_struct *D;
    D = (data_struct*)data;

    int i;
    for ( i = 0; i < m_dat; i++ )
    fvec[i] = D->y[i] - D->f( D->tx[i], D->tz[i], par );
}

int main()
{
    /* parameter vector */
    int n_par = 3; /* number of parameters in model function f */
    double par[3] = { -1, 0, 1 }; /* arbitrary starting value */
    double parerr[3];
    double covar[9];

    /* data points */
    int m_dat = 4;
    double tx[4] = { -1, -1,  1,  1 };
    double tz[4] = { -1,  1, -1,  1 };
    double y[4]  = {  0,  1,  1,  2 };

    data_struct data = { tx, tz, y, f };

    /* auxiliary parameters */
    lm_status_struct status;
    lm_control_struct control = lm_control_double;
    control.verbosity = 3;

    /* perform the fit */
    printf( "Fitting:\n" );
    lmmin2( n_par, par, parerr, covar, m_dat, (const void*) &data,
            evaluate_surface, &control, &status );

    /* print results */
    printf( "\nResults:\n" );
    printf( "status after %d function evaluations:\n  %s\n",
            status.nfev, lm_infmsg[status.outcome] );

    printf("obtained parameters:\n");
    int i;
    for ( i=0; i<n_par; ++i )
    printf("  par[%i] = %12g +- %12g\n", i, par[i], parerr[i]);
    printf("obtained norm:\n  %12g\n", status.fnorm );

    printf("fitting data as follows:\n");
    double ff;
    for ( i=0; i<m_dat; ++i ){
        ff = f(tx[i], tz[i], par);
        printf( "  t[%2d]=%12g,%12g y=%12g fit=%12g residue=%12g\n",
                i, tx[i], tz[i], y[i], ff, y[i] - ff );
    }

    return 0;
}

⭐ More examples ⭐

for more examples, check the homepage and the demo/ and test/ directories in the source distribution. 🫢


πŸ‘‘ COPYING πŸ‘‘

Copyright (C):

1980-1999 University of Chicago
2004-2018 Joachim Wuttke, Forschungszentrum Juelich GmbH

Software: FreeBSD License

Documentation: Creative Commons Attribution Share Alike


πŸ”₯ SEE ALSO πŸ”₯

lmmin(3), lmcurve(3) lmcurve2(3)

Homepage: https://jugit.fz-juelich.de/mlz/lmfit


πŸ’€ BUGS πŸ’€

please send bug reports and suggestions to the author <j.wuttke@fz-juelich.de>. bestie don't be shy, he wants the feedback fr fr πŸ™ˆ


and that's the whole page, babes β€” this beauty is perl v5.42.0, dated 2026-01-16, and it lives at builddir::bui...::man::lmmin2(3). go fit something slay βœ¨πŸ’–

πŸ“¦ where this page comes from