MF_nonlinfit MD_nonlinfit ME_nonlinfit
MF_nonlinfitwW MD_nonlinfitwW ME_nonlinfitwW
Functionfit z=f(x,y) data to a model-function which may be nonlinear in its parameters
Syntax C/C++#include <MFstd.h>
float MF_nonlinfit( fVector A, iVector AStatus, unsigned npars,
    fVector X, fVector Y, fMatrix Z, ui htZ, ui lenZ,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws),
    VF_NONLINFITOPTIONS *FitOpts,
    MF_NONLINFITWORKSPACE *WorkSpace );
 
float MF_nonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
    fVector X, fVector Y, fMatrix Z, fMatrix InvVar, ui htZ, ui lenZ,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws),
    VF_NONLINFITOPTIONS *FitOpts,
    MF_NONLINFITWORKSPACE *WorkSpace );
Syntax C/C++ simplified#include <MFstd.h>
float MF_nonlinfit( fVector A, iVector AStatus, unsigned npars,
    fVector X, fVector Y, fMatrix Z, ui htZ, ui lenZ,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws) );
 
float MF_nonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
    fVector X, fVector Y, fMatrix Z, fMatrix InvVar, ui htZ, ui lenZ,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws) );
C++ MatObj#include <OptiVec.h>
void vector<T>::nonlinfit( const vector<int>& AStatus,
    const vector<T>& X, const vector<T>& Y, const matrix<T>& MZ,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws),
    VF_NONLINFITOPTIONS *FitOpts,
    MF_NONLINFITWORKSPACE *WorkSpace );
 
void vector<T>::nonlinfitwW( matrix<T> Covar, const vector<int>& AStatus,
    const vector<T>& X, const vector<T>& Y, const matrix<T>& MZ, const matrix<T>& MInvVar,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws),
    VF_NONLINFITOPTIONS *FitOpts,
    MF_NONLINFITWORKSPACE *WorkSpace );
 
void vector<T>::nonlinfitwW( matrix<T>* Covar, const vector<int>& AStatus,
    const vector<T>& X, const vector<T>& Y, const matrix<T>& MZ, const matrix<T>& MInvVar,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws),
    VF_NONLINFITOPTIONS *FitOpts,
    MF_NONLINFITWORKSPACE *WorkSpace );
C++ MatObj simplified#include <OptiVec.h>
void vector<T>::nonlinfit( const vector<int>& AStatus,
    const vector<T>& X, const vector<T>& Y, const matrix<T>& MZ,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws) );
 
void vector<T>::nonlinfitwW( matrix<T> Covar, const vector<int>& AStatus,
    const vector<T>& X, const vector<T>& Y, const matrix<T>& MZ, const matrix<T>& MInvVar,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws) );
 
void vector<T>::nonlinfitwW( matrix<T>* Covar, const vector<int>& AStatus,
    const vector<T>& X, const vector<T>& Y, const matrix<T>& MZ, const matrix<T>& MInvVar,
    void modelfunc(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y , fVector A),
    void derivatives(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws) );
Pascal/Delphiuses MFnlfit;
function MF_nonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
    X, Y: fVector; MZ: fMatrix; htZ, lenZ:UIntSize;
    ModelFunc, Derivatives: Pointer;
    FitOpts: PVF_NONLINFITOPTIONS;
    WorkSpace: PMF_NONLINFITWORKSPACE ): Single;
 
function MF_nonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
    X, Y: fVector; MZ, MInvVar: fMatrix; htZ, lenZ:UIntSize;
    ModelFunc, Derivatives: Pointer;
    FitOpts: PVF_NONLINFITOPTIONS;
    WorkSpace: PMF_NONLINFITWORKSPACE ): Single;

Syntax of user-supplied ModelFunc and Derivatives:
procedure ModelFunc( ZModel:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; A:fVector );
procedure Derivatives( dZdAi:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; ipar:UInt; A:fVector; ws:PMF_NONLINFITWORKSPACE );
Pascal/Delphi simplifieduses MFnlfit;
function MF_nonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
    X, Y: fVector; MZ: fMatrix; htZ, lenZ:UIntSize;
    ModelFunc, Derivatives: Pointer ): Single;
 
function MF_nonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
    X, Y: fVector; MZ, MInvVar: fMatrix; htZ, lenZ:UIntSize;
    ModelFunc, Derivatives: Pointer ): Single;
DescriptionThe input data X, Y, MZ (and MInvVar) are used to evaluate the parameter array A with npars elements ai of an arbitrary model function z = f(x,y).

Arguments:
Avector of size npars; returns the coefficients
Covarmatrix of dimensions [npars, npars]; returns the covariances of the coefficients
AStatusvector of size npars; decides which parameters are treated as free or as fixed
nparstotal number of parameters
X, Yvectors of size lenZ and htZ, respectively, spanning the x-y coordinate system of the matrix MZ
MZ, MInvVarmatrices of dimensions [htZ, lenZ], holding the input data and, in the weighted variant, the inverse of their variances
modelfuncuser-defined model function
derivativesuser-defined function, calculating the partial derivatives with respect to all parameters (may be NULL / nil, in which case the partial derivatives are calculated numerically)
FitOptspointer to a structure containing options, see chap. 13.3
WorkSpacepointer to a structure holding internal variables, see chap. 13.3
Return Value"goodness-of-fit" value. Depending on the function variant and the chosen figure-of-merit, this is:
MF_nonlinfitwW with FitOptions.FigureOfMerit=0 (least-square fitting): c2 (chi-square) = S) (MZmod[i,j] - MZ[i,j] )2 * MInvVar[i,j] );
MF_nonlinfitwW with FitOptions.FigureOfMerit=1 (robust fitting): |c| (chi-abs) = S( abs(MZmod[i,j] - MZ[i,j] ) * MInvVar[i,j] );
MF_nonlinfit with FitOptions.FigureOfMerit=0 (least-square fitting, all std errors assumed=1.0): c2 = S( (MZmod[i,j] - MZ[i,j] )2 ];
MF_nonlinfit with FitOptions.FigureOfMerit=1 (robust fitting): |c| (chi-abs) = S( abs(MZmod[i,j] - MZ[i,j] ) );
where MZmod means the theoretical MZ values as calculated from the model function with the best parameter set found. For robust fitting, MInvVar actually does not have the meaning of inverse variances; one could choose weights as inverse absolute uncertainties instead.
 
The model function (and, consequently, the vector A as well) may actually contain more parameters than you wish to treat as adjustable. This is why you have to provide an additional vector, AStatus, which contains the necessary information about which parameters are to be held fixed at their input values (AStatus[i] = 0) and which are free (AStatus[i] = 1). All parameters must be initialized in A prior to calling MF_nonlinfit. The better your initial guess of the parameters, the faster MF_nonlinfit shall converge. The argument npars denotes the total number of parameters in A (not only the free parameters!).

You must provide a model function "modelfunc" which, for given vectors of x and y values, must calculate the corresponding "theoretical" z values. In C/C++, it has to be defined as

Model function for C/C++ void _cdecl MyFunc( fMatrix Z, ui htZ, ui lenZ, fVector X, fVector Y , fVector A)
{
  for (ui i=0; i<htZ; i++ )
    for (ui j=0; j<lenZ; j++ )
      MZ[i][j] = f( X[j], Y[i] );
}
f( X[j], Y[i] )
is any arbitrary function, which may be as complicated as you like and your application needs. The only condition is that it have no singularities, at least within the parameter space specified by upper and lower boundaries (see NONLINFITOPTIONS).
In addition to the model function, MF_nonlinfit needs the partial derivatives of MZ with respect to all parameters A[ipar], according to your model. If you know them analytically, you should write a function MyDerivs. If you happen to know only some, but not all of the partial derivatives, you may rely on MF_nonlinfit_autoDeriv to calculate the unknown derivatives numerically.
Partial derivatives coded for C/C++
 
void _cdecl MyDerivs( fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, fVector A, MF_NONLINFITWORKSPACE *ws )
{
  ui i;
  switch( ipar )
  {
    case 0:
    for(i=0; i<htZ; i++ )
      for( j=0; j<lenZ; j++ )
        dZdAi[i][j] = part_derv_MZ_w_resp_to_A0( X[j], Y[i] );
    break;
    case 1:
    for(i=0; i<htZ; i++ )
      for( j=0; j<lenZ; j++ )
        dZdAi[i][j] = part_derv_MZ_w_resp_to_A1( X[j], Y[i] );
    break;
    default: /* for all derivatives we don't know: */
      MF_nonlinfit_autoDeriv( dZdAi, htZ, lenZ, X, Y, ipar, A, ws );
  }
}

A call to MF_nonlinfit will look like:
MF_nonlinfit( A, AStatus, npars, X, Y, MZ, htZ, lenZ, MyFunc, MyDerivs, &FitOpts, &WorkSpace );
or, in simplified syntax (only, if no explicit call to MF_nonlinfit_autoDeriv has to be made:
MF_nonlinfit( A, AStatus, npars, X, Y, MZ, htZ, lenZ, MyFunc, MyDerivs );
In case you do not know any of the partial derivatives, do not define MyDerivs, but call MF_nonlinfit with derivatives = NULL:
MF_nonlinfit( A, AStatus, npars, X, Y, MZ, htZ, lenZ, MyFunc, NULL );
 
Model function for Pascal/Delphi In Pascal/Delphi, the model function has to be defined as
procedure MyFunc( MZ:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; A:fVector );
var i, j:UIntSize;
begin
  for i:=0 to htZ-1 do
    for j:=0 to lenZ-1 do
      MF_Pelement( MZ, htZ, lenZ, i, j )^ :=
        f( VF_element( X, j ), VF_element( Y, i ) );
end;
f( Xj, Yi )
is any arbitrary function, which may be as complicated as you like and your application needs. The only condition is that it have no singularities, at least within the parameter space specified by upper and lower boundaries (see NONLINFITOPTIONS).
In addition to the model function, MF_nonlinfit needs the partial derivatives of MZ with respect to all parameters A[ipar], according to your model. If you know them analytically, you should write a function MyDerivs. If you happen to know only some, but not all of the partial derivatives, you may rely on MF_nonlinfit_autoDeriv to calculate the unknown derivatives numerically.
Partial derivatives coded for Pascal/Delphi
 
procedure MyDerivs( dZdAi:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; ipar:UInt; A:fVector; ws:PMF_NONLINFITWORKSPACE );
var i, j:UIntSize;
begin
  case ipar of
    0: begin
      for i:=0 to htZ-1 do
        for j:=0 to lenZ-1 do
          MF_Pelement( dZdAi, htZ, lenZ, i, j )^ :=
          part_derv_MZ_w_resp_to_A0(VF_element( X, j ), VF_element( Y, i ));
       end;
    1: begin
      for i:=0 to htZ-1 do
        for j:=0 to lenZ-1 do
          MF_Pelement( dZdAi, htZ, lenZ, i, j )^ :=
          part_derv_MZ_w_resp_to_A1(VF_element( X, j ), VF_element( Y, i ));
       end;
  else (* for all derivatives we don't know: *)
    MF_nonlinfit_autoDeriv( dZdAi, htZ, lenZ, X, Y, ipar, A, ws );
  end;
end;

A call to MF_nonlinfit will look like:
MF_nonlinfit( A, AStatus, npars, MZ, htZ, lenZ, X, Y, @MyFunc, @MyDerivs, @FitOpts, @WorkSpace );
or, in simplified syntax (only, if no explicit call to MF_nonlinfit_autoDeriv has to be made:
MF_nonlinfit( A, AStatus, npars, MZ, htZ, lenZ, X, Y, @MyFunc, @MyDerivs );
Note the address-of operator in front of "MyFunc." and "MyDerivs". In case you do not know any of the partial derivatives, do not define MyDerivs, but call MF_nonlinfit with derivatives = nil:
MF_nonlinfit( A, AStatus, npars, MZ, htZ, lenZ, X, Y, @MyFunc, nil );

In the weighted variant, MF_nonlinfitwW, the matrix MInvVar has to contain the inverse of the variances of the individual X-Y-Z data points, and the matrix MCovar will be filled with the covariances of the parameters ai on output: MCovari,j = covariance( ai, aj ).
 
Both C/C++ and Pascal/Delphi: For the many different options controlling nonlinear data-fitting functions, please consult chapter 13.3. Helper functions for breaking off excessively long fitting runs and for the monitoring of these often very time-consuming procedures are summarized in chapter 13.5 and, in the special case of MF_nonlinfit, described here.
Multi-threading restrictionsThe multi-threading restrictions, present in OptiVec versions up to and including 6.1, have been lifted with v6.2.

These functions may not be called while the FPU is set to reduced accuracy, or else they might hang in an infinite loop. See V_setFPAccuracy.

Error handlingIf the number of free parameters (i.e., those with AStatus[i] = 1) exceeds the total number of data points, an error message "Invalid parameter(s)" is generated and the program aborted.
Return valuein case of success: goodness-of-fit parameter c2 (chi-square);
in case of failure: -1
See alsoVF_setNonlinfitOptions,   VF_nonlinfit,   MF_multiNonlinfit,   MF_linfit,   chapter 13,  FITDEMO*.*

MatrixLib Table of Contents  OptiVec home