A simple example of using the InMin library from "C" language

This example shows how to run the simplest possible Levenberg-Marquardt minimisation using the InMin library. In this example I use the "C"-language only to illustrate the "native" interface of the library. The InMin library is also easily usable from many other languages including C++, Python and others.

Set-up

To use the InMin Levenberg-Marquardt algorithm it is necessary to include the "inmin/inmin_lm.h" header:

#include "inmin/inmin_lm.h"

and when building the program it is necessary to link against the InMin library (on Linux systems adding the -linmin switch should be sufficient).

The function to minimise

The function to be minimised in this example is extremely simple: it is a second order polynomial computed at four values, with the target and the ordinate values being equal. The things to note:

  • In this case I use the obs array which is global. In a real application one would use the data parameter which is passed to the function to be minimised
  • The current parameter values for which the function to be minimised are passed in the first argument of the function as a pointer to an array. The number of parameters is not passed in -- if this is determined at run time then it should be encoded in the structure pointed to by data
  • The residuals should be placed in the res array. Sufficient memory is always already allocated in the array pointed to by the res pointer
const double obs[4] = { 1, 2, 3, 4};

void myfn(const double *x,
            double *res,
            void *data)
{
size_t i=0;
for(i=0; i<4; ++i)
 {
   res[i]=obs[i]-(x[0]+obs[i]*x[1]+obs[i]*obs[i]*x[2]);
 }
}

Inputs

The main input to the Levenberg-Marquardt routine is the structure inmin_lm_in, which contains specification about the problem to be solved and various options controlling the optimisation. It is best to initialise this structure with zeros in order to ensure all defaults are set correctly:

inmin_lm_in in;
memset(&in, 0,
       sizeof(inmin_lm_in));

The next step is to specify the number of parameters (N), the number of residuals (M) and the function to specify (f):

in.N=3;
in.M=4;
in.f=myfn;

myfn is in this function to minimise as described above.

The final inputs are the tolerances which control for how long the algorithm runs:

in.ftol=in.xtol=in.gtol=1e-9;
in.maxfev=100;

Starting point

The point at which the algorithm is separately passed to the minimisation function as a pointer to an array. This allows easy restart of the algorithm at many different points. In the example, this array is the pinit array.

Output structure

The Levenberg-Marquardt minimisation stores the results of computation in a structure of type inmin_lm_out. The pointers in this structure must be initialised by the user to point to arrays in memory which are of sufficient lengths to hold the results. In this case we use a stack-allocated array pres to hold the best-fitting point output by the algorithm and the covar parameter is initialised to NULL to turn off computation of the covariance matrix.

double pres[3];
inmin_lm_out out;
out.x=pres;
out.covar=NULL;

The complete program

Here is the complete program:

#include <memory.h>
#include <stdio.h>

#include "inmin/inmin_lm.h"

const double obs[4] = { 1, 2, 3, 4};

void myfn(const double *x,
            double *res,
            void *data)
{
size_t i=0;
for(i=0; i<4; ++i)
 {
   res[i]=obs[i]-(x[0]+obs[i]*x[1]+obs[i]*obs[i]*x[2]);
 }
}

int main(void)
{
  inmin_lm_in in;
  memset(&in, 0,
         sizeof(inmin_lm_in));
  in.N=3;
  in.M=4;
  in.f=myfn;
  in.ftol=in.xtol=in.gtol=1e-9;
  in.maxfev=100;

  double pinit[3] = {0, 0 ,0};

  double pres[3];
  inmin_lm_out out;
  out.x=pres;
  out.covar=NULL;

  inmin_lm_run(&in,
            pinit,
            &out,
            NULL);
 printf("Result: %f, %f, %f \n", pres[0], pres[1], pres[2]);

}