lmmin_fit.cpp.html mathcode2html   
 Source file:   lmmin_fit.cpp
 Converted:   Sun Aug 7 2016 at 13:45:52
 This documentation file will not reflect any later changes in the source file.

$$\phantom{******** If you see this on the webpage then the browser could not locate *********}$$
$$\phantom{******** jsMath/easy/load.js or the variable root is set wrong in this file *********}$$
$$\newcommand{\vector}[1]{\left[\begin{array}{c} #1 \end{array}\right]}$$ $$\newenvironment{matrix}{\left[\begin{array}{cccccccccc}} {\end{array}\right]}$$ $$\newcommand{\A}{{\cal A}}$$ $$\newcommand{\W}{{\cal W}}$$

/*
Up
*/

#ifdef _WIN32
  #include <windows.h>
  #include <time.h>
  #include <float.h>
  #define sleep Sleep
#else
  #include <stdlib.h>
  #define BOOL int
  #define TRUE 1
  #define FALSE 0
#endif

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <math.h>
#include <string.h>
#include <vector>
using std::vector;

#include "lmmin_fit.h"
#include "callbk_reportstream.h"
#include "lmmin.h"

#define UNSET_VALUE 86738.82583

class qub_lmmin_state
{
public:
  lmmin_CurveFunc curve;
  int Nparam;
  double *params;
  double *lo, *hi;
  int *can_fit;
  int Ndata;
  float *yy, *ww;
  lmmin_IterFunc on_iter;
  callbk_reportfun on_report;
  void *obj;
  int max_iter;
  double toler;
  float *ff;
  double *ssr;
  int iter;
  vector<int> useCpar;
  int Ncurvepar;
  bool stop;

  qub_lmmin_state(lmmin_CurveFunc _curve, int _Nparam, double *_params, double *_lo, double *_hi, int *_can_fit,
			      int _Ndata, float *_yy, float *_ww, lmmin_IterFunc _on_iter, callbk_reportfun _on_report, void *_obj,
			      int _max_iter, double _toler, float *_ff, double *_ssr)
    : curve(_curve), Nparam(_Nparam), params(_params), lo(_lo), hi(_hi), can_fit(_can_fit),
      Ndata(_Ndata), yy(_yy), ww(_ww), on_iter(_on_iter), on_report(_on_report), obj(_obj),
      max_iter(_max_iter), toler(_toler), ff(_ff), ssr(_ssr), iter(0), stop(false)
  {}
};

void qub_lmmin_eval( double* par, int QUBFAST_VAR_NOT_USED m_dat, double* fvec, 
		     qub_lmmin_state *self, int *info )
{
  if ( self->stop ) {
    *info = -1;
    return;
  }
  bool outOfBounds = false;
  for (int i=self->Ncurvepar-1; i>=0; --i) {
    double lim = self->lo[ self->useCpar[i] ];
    if ( (fabs(lim - UNSET_VALUE) > 1e-8) && (lim > par[i]) )
      outOfBounds = true;
    lim = self->hi[ self->useCpar[i] ];
    if ( (fabs(lim - UNSET_VALUE) > 1e-8) && (lim < par[i]) )
      outOfBounds = true;
    if ( outOfBounds )
      break;
    self->params[ self->useCpar[i] ] = par[i];
  }
  if ( outOfBounds ) {
    for (int i=self->Ndata-1; i>=0; --i)
      fvec[i] = 1e10;
    return;
  }
  self->curve(self->obj, self->params, self->ff);
  double ssr = 0.0;
  for (int i=self->Ndata-1; i>=0; --i) {
    double resid = self->ww[i] * (self->yy[i] - self->ff[i]);
    fvec[i] = resid;
    ssr += resid * resid;
  }
  * self->ssr = ssr;
}

void qub_lmmin_print( QUBFAST_VAR_NOT_USED int n_par, QUBFAST_VAR_NOT_USED double* par, QUBFAST_VAR_NOT_USED int m_dat, QUBFAST_VAR_NOT_USED double* fvec, 
		      qub_lmmin_state *self, QUBFAST_VAR_NOT_USED int iflag, QUBFAST_VAR_NOT_USED int iter, QUBFAST_VAR_NOT_USED int nfev )
{
  self->iter = iter;
  if ( self->on_iter && ! self->on_iter(self->obj, self->params, self->iter) )
    self->stop = true;
}


QUBFAST_API int qub_lmmin_fit(lmmin_CurveFunc curve, int Nparam, double *params, double *lo, double *hi, int *can_fit,
			      int Ndata, float *yy, float *ww, lmmin_IterFunc on_iter, callbk_reportfun on_report, void *obj,
			      int max_iter, double toler, float *ff, double *ssr)
{
  *ssr = 0.0;
  qub_lmmin_state self(curve, Nparam, params, lo, hi, can_fit, Ndata, yy, ww, on_iter, on_report, obj, max_iter, toler, ff, ssr);
  lm_control_type control;
  control.maxcall = max_iter;
  control.stepbound = 100.0;
  control.epsilon = toler;
  control.ftol = toler;
  control.xtol = toler;
  control.gtol = toler;
  control.curvature = NULL;
  
  for (int i=0; i<Nparam; ++i)
    if ( can_fit[i] )
      self.useCpar.push_back(i);
  self.Ncurvepar = (int) self.useCpar.size();
  
  vector<double> curvepars( self.Ncurvepar );
  for (int i=0; i<self.Ncurvepar; ++i)
    curvepars[i] = params[self.useCpar[i]];

  lm_minimize( Ndata, self.Ncurvepar, &(curvepars[0]),
	       (lm_evaluate_ftype*)qub_lmmin_eval, (lm_print_ftype*)qub_lmmin_print, &self, &control );
  
  for (int i=self.Ncurvepar-1; i>=0; --i)
    params[ self.useCpar[i] ] = curvepars[i];

  // make sure the ssr and fit curve are for final params:
  vector<double> fvec(Ndata);
  int info;
  qub_lmmin_eval( &(curvepars[0]), Ndata, &(fvec[0]), &self, &info);

#if defined(_WIN32)
	unsigned int fstat = _clearfp(); // just in case
	_fpreset();
#endif  
  
  return self.iter;
}