예제 #1
0
void lmmin( int n_par, double *par, int m_dat, const void *data, 
            void (*evaluate) (const double *par, int m_dat, const void *data,
                              double *fvec, int *info),
            const lm_control_struct *control, lm_status_struct *status,
            void (*printout) (int n_par, const double *par, int m_dat,
                              const void *data, const double *fvec,
                              int printflags, int iflag, int iter, int nfev) )
{

/*** allocate work space. ***/

    double *fvec, *diag, *fjac, *qtf, *wa1, *wa2, *wa3, *wa4;
    int *ipvt, j;

    int n = n_par;
    int m = m_dat;

    /* One malloc call to allocate several arrays (Frank Polchow, 2013) */
    fvec = (double *) malloc( (2*m+5*n+n*m)*sizeof(double) + n*sizeof(int));
    if (NULL==fvec) {//fail in allocation
        status->info = 9;
        return;
    }
    diag = (double *) &fvec[m];
    qtf  = (double *) &diag[n];
    fjac = (double *) &qtf[n];
    wa1  = (double *) &fjac[n*m];
    wa2  = (double *) &wa1[n];
    wa3  = (double *) &wa2[n];
    wa4  = (double *) &wa3[n];
    ipvt = (int    *) &wa4[m];

    /* default diagonal */
    if( ! control->scale_diag )
        for( j=0; j<n_par; ++j )
            diag[j] = 1;

/*** perform fit. ***/

    status->info = 0;

    /* this goes through the modified legacy interface: */
    lm_lmdif(
        m, n, par, fvec, control->ftol, control->xtol, control->gtol,
        control->maxcall * (n+1), control->epsilon, diag,
        ( control->scale_diag ? 1 : 2 ), control->stepbound, &(status->info),
        &(status->nfev), fjac, ipvt, qtf, wa1, wa2, wa3, wa4,
        evaluate, printout, control->printflags, data );

    if ( printout )
        (*printout)(
            n, par, m, data, fvec, control->printflags, -1, 0, status->nfev );
    status->fnorm = lm_enorm(m, fvec);
    if ( status->info < 0 )
        status->info = 11;

/*** clean up. ***/
    free(fvec);

} /*** lmmin. ***/
예제 #2
0
void lm_minimize(int m_dat, int n_par, double *par,
		 lm_evaluate_ftype * evaluate, lm_print_ftype * printout,
		 void *data, lm_control_type * control)
{

/*** allocate work space. ***/

    double *fvec, *diag, *fjac, *qtf, *wa1, *wa2, *wa3, *wa4;
    int *ipvt;

    int n = n_par;
    int m = m_dat;

    if (!(fvec = (double *) malloc(m * sizeof(double))) ||
	!(diag = (double *) malloc(n * sizeof(double))) ||
	!(qtf = (double *) malloc(n * sizeof(double))) ||
	!(fjac = (double *) malloc(n * m * sizeof(double))) ||
	!(wa1 = (double *) malloc(n * sizeof(double))) ||
	!(wa2 = (double *) malloc(n * sizeof(double))) ||
	!(wa3 = (double *) malloc(n * sizeof(double))) ||
	!(wa4 = (double *) malloc(m * sizeof(double))) ||
	!(ipvt = (int *) malloc(n * sizeof(int)))) {
	control->info = 9;
	return;
    }

/*** perform fit. ***/

    control->info = 0;
    control->nfev = 0;

    /* this goes through the modified legacy interface: */
    lm_lmdif(m, n, par, fvec, control->ftol, control->xtol, control->gtol,
	     control->maxcall * (n + 1), control->epsilon, diag, 1,
	     control->stepbound, &(control->info),
	     &(control->nfev), fjac, ipvt, qtf, wa1, wa2, wa3, wa4,
	     evaluate, printout, data);

    (*printout) (n, par, m, fvec, data, -1, 0, control->nfev);
    control->fnorm = lm_enorm(m, fvec);
    if (control->info < 0)
	control->info = 10;

/*** clean up. ***/

    free(fvec);
    free(diag);
    free(qtf);
    free(fjac);
    free(wa1);
    free(wa2);
    free(wa3);
    free(wa4);
    free(ipvt);
} /*** lm_minimize. ***/
예제 #3
0
void lm_printout_std( int n_par, const double *par, int m_dat,
                      const void *data, const double *fvec,
                      int printflags, int iflag, int iter, int nfev)
/*
 *       data  : for soft control of printout behaviour, add control
 *                 variables to the data struct
 *       iflag : 0 (init) 1 (outer loop) 2(inner loop) -1(terminated)
 *       iter  : outer loop counter
 *       nfev  : number of calls to *evaluate
 */
{
    int i;

    if( !printflags )
        return;

    if( printflags & 1 ){
        /* location of printout call within lmdif */
        if (iflag == 2) {
            printf("trying step in gradient direction  ");
        } else if (iflag == 1) {
            printf("determining gradient (iteration %2d)", iter);
        } else if (iflag == 0) {
            printf("starting minimization              ");
        } else if (iflag == -1) {
            printf("terminated after %3d evaluations   ", nfev);
        }
    }

    if( printflags & 2 ){
        printf("  par: ");
        for (i = 0; i < n_par; ++i)
            printf(" %18.11g", par[i]);
        printf(" => norm: %18.11g", lm_enorm(m_dat, fvec));
    }

    if( printflags & 3 )
        printf( "\n" );

    if ( (printflags & 8) || ((printflags & 4) && iflag == -1) ) {
        printf("  residuals:\n");
        for (i = 0; i < m_dat; ++i)
            printf("    fvec[%2d]=%12g\n", i, fvec[i] );
    }
}
예제 #4
0
파일: lm_eval.c 프로젝트: gunawanw9/libavg
void lm_print_default( int n_par, double* par, int m_dat, double* fvec,
                       void *data, int iflag, int iter, int nfev )
/*
 *       data  : for soft control of printout behaviour, add control
 *                 variables to the data struct
 *       iflag : 0 (init) 1 (outer loop) 2(inner loop) -1(terminated)
 *       iter  : outer loop counter
 *       nfev  : number of calls to *evaluate
 */
{
    double f, y, t;
    int i;
    lm_data_type *mydata;
    mydata = (lm_data_type*)data;

    if (iflag==2) {
        printf ("trying step in gradient direction\n");
    } else if (iflag==1) {
        printf ("determining gradient (iteration %d)\n", iter);
    } else if (iflag==0) {
        printf ("starting minimization\n");
    } else if (iflag==-1) {
        printf ("terminated after %d evaluations\n", nfev);
    }

    printf( "  par: " );
    for( i=0; i<n_par; ++i )
        printf( " %12g", par[i] );
    printf ( " => norm: %12g\n", lm_enorm( m_dat, fvec ) );

    if ( iflag == -1 ) {
        printf( "  fitting data as follows:\n" );
        for( i=0; i<m_dat; ++i ) {
            t = (mydata->user_t)[i];
            y = (mydata->user_y)[i];
            f = mydata->user_func( t, par );
            printf( "    t[%2d]=%12g y=%12g fit=%12g residue=%12g\n",
                    i, t, y, f, y-f );
        }
    }
}
예제 #5
0
파일: lmmin.c 프로젝트: drsuuzzz/BaseFinder
void lm_qrfac(int m, int n, double* a, int pivot, int* ipvt,
           double* rdiag, double* acnorm, double* wa)
{
/*
 *     this subroutine uses householder transformations with column
 *     pivoting (optional) to compute a qr factorization of the
 *     m by n matrix a. that is, qrfac determines an orthogonal
 *     matrix q, a permutation matrix p, and an upper trapezoidal
 *     matrix r with diagonal elements of nonincreasing magnitude,
 *     such that a*p = q*r. the householder transformation for
 *     column k, k = 1,2,...,min(m,n), is of the form
 *
 *			    t
 *	    i - (1/u(k))*u*u
 *
 *     where u has 0.s in the first k-1 positions. the form of
 *     this transformation and the method of pivoting first
 *     appeared in the corresponding linpack subroutine.
 *
 *     parameters:
 *
 *	m is a positive integer input variable set to the number
 *	  of rows of a.
 *
 *	n is a positive integer input variable set to the number
 *	  of columns of a.
 *
 *	a is an m by n array. on input a contains the matrix for
 *	  which the qr factorization is to be computed. on output
 *	  the strict upper trapezoidal part of a contains the strict
 *	  upper trapezoidal part of r, and the lower trapezoidal
 *	  part of a contains a factored form of q (the non-trivial
 *	  elements of the u vectors described above).
 *
 *	pivot is a logical input variable. if pivot is set true,
 *	  then column pivoting is enforced. if pivot is set false,
 *	  then no column pivoting is done.
 *
 *	ipvt is an integer output array of length lipvt. ipvt
 *	  defines the permutation matrix p such that a*p = q*r.
 *	  column j of p is column ipvt(j) of the identity matrix.
 *	  if pivot is false, ipvt is not referenced.
 *
 *	rdiag is an output array of length n which contains the
 *	  diagonal elements of r.
 *
 *	acnorm is an output array of length n which contains the
 *	  norms of the corresponding columns of the input matrix a.
 *	  if this information is not needed, then acnorm can coincide
 *	  with rdiag.
 *
 *	wa is a work array of length n. if pivot is false, then wa
 *	  can coincide with rdiag.
 *
 */
    int i, j, k, kmax, minmn;
    double ajnorm, sum, temp;
    static double p05 = 0.05;

// *** compute the initial column norms and initialize several arrays.

    for ( j=0; j<n; j++ )
    {
	acnorm[j] = lm_enorm(m, &a[j*m]);
	rdiag[j] = acnorm[j];
	wa[j] = rdiag[j];
	if ( pivot )
            ipvt[j] = j;
    }
#if BUG
    printf( "qrfac\n" );
#endif

// *** reduce a to r with householder transformations.

    minmn = MIN(m,n);
    for ( j=0; j<minmn; j++ )
    {
        if ( !pivot ) goto pivot_ok;

// *** bring the column of largest norm into the pivot position.

        kmax = j;
        for ( k=j+1; k<n; k++ )
            if (rdiag[k] > rdiag[kmax])
		kmax = k;
        if (kmax == j) goto pivot_ok; // bug fixed in rel 2.1

        for ( i=0; i<m; i++ )
	{
            temp        = a[j*m+i];
            a[j*m+i]    = a[kmax*m+i];
            a[kmax*m+i] = temp;
	}
        rdiag[kmax] = rdiag[j];
        wa[kmax] = wa[j];
        k = ipvt[j];
        ipvt[j] = ipvt[kmax];
        ipvt[kmax] = k;

    pivot_ok:

// *** compute the Householder transformation to reduce the
//     j-th column of a to a multiple of the j-th unit vector.

        ajnorm = lm_enorm( m-j, &a[j*m+j] );
        if (ajnorm == 0.)
        {
            rdiag[j] = 0;
            continue;
        }

        if (a[j*m+j] < 0.)
            ajnorm = -ajnorm;
        for ( i=j; i<m; i++ )
            a[j*m+i] /= ajnorm;
        a[j*m+j] += 1;

// *** apply the transformation to the remaining columns
//     and update the norms.

        for ( k=j+1; k<n; k++ )
        {
            sum = 0;

            for ( i=j; i<m; i++ )
                sum += a[j*m+i]*a[k*m+i];

            temp = sum/a[j+m*j];

            for ( i=j; i<m; i++ )
                a[k*m+i] -= temp * a[j*m+i];

            if ( pivot && rdiag[k] != 0. )
            {
                temp = a[m*k+j]/rdiag[k];
                temp = MAX( 0., 1-temp*temp );
                rdiag[k] *= sqrt(temp);
                temp = rdiag[k]/wa[k];
                if ( p05*SQR(temp) <= LM_MACHEP )
                {
                    rdiag[k] = lm_enorm( m-j-1, &a[m*k+j+1]);
                    wa[k] = rdiag[k];
                }
            }
        }

	rdiag[j] = -ajnorm;
    }
}
예제 #6
0
파일: lmmin.c 프로젝트: drsuuzzz/BaseFinder
void lm_lmpar(int n, double* r, int ldr, int* ipvt, double* diag, double* qtb,
              double delta, double* par, double* x, double* sdiag,
              double* wa1, double* wa2)
{
/*     given an m by n matrix a, an n by n nonsingular diagonal
 *     matrix d, an m-vector b, and a positive number delta,
 *     the problem is to determine a value for the parameter
 *     par such that if x solves the system
 *
 *	    a*x = b ,	  sqrt(par)*d*x = 0 ,
 *
 *     in the least squares sense, and dxnorm is the euclidean
 *     norm of d*x, then either par is 0. and
 *
 *	    (dxnorm-delta) .le. 0.1*delta ,
 *
 *     or par is positive and
 *
 *	    abs(dxnorm-delta) .le. 0.1*delta .
 *
 *     this subroutine completes the solution of the problem
 *     if it is provided with the necessary information from the
 *     qr factorization, with column pivoting, of a. that is, if
 *     a*p = q*r, where p is a permutation matrix, q has orthogonal
 *     columns, and r is an upper triangular matrix with diagonal
 *     elements of nonincreasing magnitude, then lmpar expects
 *     the full upper triangle of r, the permutation matrix p,
 *     and the first n components of (q transpose)*b. on output
 *     lmpar also provides an upper triangular matrix s such that
 *
 *	     t	 t		     t
 *	    p *(a *a + par*d*d)*p = s *s .
 *
 *     s is employed within lmpar and may be of separate interest.
 *
 *     only a few iterations are generally needed for convergence
 *     of the algorithm. if, however, the limit of 10 iterations
 *     is reached, then the output par will contain the best
 *     value obtained so far.
 *
 *     parameters:
 *
 *	n is a positive integer input variable set to the order of r.
 *
 *	r is an n by n array. on input the full upper triangle
 *	  must contain the full upper triangle of the matrix r.
 *	  on output the full upper triangle is unaltered, and the
 *	  strict lower triangle contains the strict upper triangle
 *	  (transposed) of the upper triangular matrix s.
 *
 *	ldr is a positive integer input variable not less than n
 *	  which specifies the leading dimension of the array r.
 *
 *	ipvt is an integer input array of length n which defines the
 *	  permutation matrix p such that a*p = q*r. column j of p
 *	  is column ipvt(j) of the identity matrix.
 *
 *	diag is an input array of length n which must contain the
 *	  diagonal elements of the matrix d.
 *
 *	qtb is an input array of length n which must contain the first
 *	  n elements of the vector (q transpose)*b.
 *
 *	delta is a positive input variable which specifies an upper
 *	  bound on the euclidean norm of d*x.
 *
 *	par is a nonnegative variable. on input par contains an
 *	  initial estimate of the levenberg-marquardt parameter.
 *	  on output par contains the final estimate.
 *
 *	x is an output array of length n which contains the least
 *	  squares solution of the system a*x = b, sqrt(par)*d*x = 0,
 *	  for the output par.
 *
 *	sdiag is an output array of length n which contains the
 *	  diagonal elements of the upper triangular matrix s.
 *
 *	wa1 and wa2 are work arrays of length n.
 *
 */
    int i, iter, j, nsing;
    double dxnorm, fp, fp_old, gnorm, parc, parl, paru;
    double sum, temp;
    static double p1 = 0.1;
    static double p001 = 0.001;

#if BUG
    printf( "lmpar\n" );
#endif

// *** compute and store in x the gauss-newton direction. if the
//     jacobian is rank-deficient, obtain a least squares solution.

    nsing = n;
    for ( j=0; j<n; j++ )
    {
	wa1[j] = qtb[j];
	if ( r[j*ldr+j] == 0 && nsing == n )
            nsing = j;
	if (nsing < n)
            wa1[j] = 0;
    }
#if BUG
    printf( "nsing %d ", nsing );
#endif
    for ( j=nsing-1; j>=0; j-- )
    {
        wa1[j] = wa1[j]/r[j+ldr*j];
        temp = wa1[j];
        for ( i=0; i<j; i++ )
            wa1[i] -= r[j*ldr+i]*temp;
    }

    for ( j=0; j<n; j++ )
	x[ ipvt[j] ] = wa1[j];

// *** initialize the iteration counter.
//     evaluate the function at the origin, and test
//     for acceptance of the gauss-newton direction.

    iter = 0;
    for ( j=0; j<n; j++ )
	wa2[j] = diag[j]*x[j];
    dxnorm = lm_enorm(n,wa2);
    fp = dxnorm - delta;
    if (fp <= p1*delta)
    {
#if BUG
	printf( "lmpar/ terminate (fp<delta/10\n" );
#endif
        *par = 0;
        return;
    }

// *** if the jacobian is not rank deficient, the newton
//     step provides a lower bound, parl, for the 0. of
//     the function. otherwise set this bound to 0..

    parl = 0;
    if (nsing >= n)
    {
	for ( j=0; j<n; j++ )
            wa1[j] = diag[ ipvt[j] ] * wa2[ ipvt[j] ] / dxnorm;

	for ( j=0; j<n; j++ )
        {
            sum = 0.;
            for ( i=0; i<j; i++ )
                sum += r[j*ldr+i]*wa1[i];
            wa1[j] = (wa1[j] - sum)/r[j+ldr*j];
        }
	temp = lm_enorm(n,wa1);
	parl = fp/delta/temp/temp;
    }

// *** calculate an upper bound, paru, for the 0. of the function.

    for ( j=0; j<n; j++ )
    {
	sum = 0;
	for ( i=0; i<=j; i++ )
            sum += r[j*ldr+i]*qtb[i];
	wa1[j] = sum/diag[ ipvt[j] ];
    }
    gnorm = lm_enorm(n,wa1);
    paru = gnorm/delta;
    if (paru == 0.)
	paru = LM_DWARF/MIN(delta,p1);

// *** if the input par lies outside of the interval (parl,paru),
//     set par to the closer endpoint.

    *par = MAX( *par,parl);
    *par = MIN( *par,paru);
    if ( *par == 0.)
	*par = gnorm/dxnorm;
#if BUG
    printf( "lmpar/ parl %.4e  par %.4e  paru %.4e\n", parl, *par, paru );
#endif

// *** iterate.

    for ( ; ; iter++ ) {

// *** evaluate the function at the current value of par.

        if ( *par == 0.)
            *par = MAX(LM_DWARF,p001*paru);
        temp = sqrt( *par );
        for ( j=0; j<n; j++ )
            wa1[j] = temp*diag[j];
        lm_qrsolv( n, r, ldr, ipvt, wa1, qtb, x, sdiag, wa2);
        for ( j=0; j<n; j++ )
            wa2[j] = diag[j]*x[j];
        dxnorm = lm_enorm(n,wa2);
        fp_old = fp;
        fp = dxnorm - delta;

// ***	 if the function is small enough, accept the current value
//	 of par. also test for the exceptional cases where parl
//	 is 0. or the number of iterations has reached 10.

        if ( fabs(fp) <= p1*delta
             || (parl == 0. && fp <= fp_old && fp_old < 0.)
             || iter == 10 )
            break; // the only exit from this loop

// *** compute the Newton correction.

        for ( j=0; j<n; j++ )
            wa1[j] = diag[ ipvt[j] ] * wa2[ ipvt[j] ] / dxnorm;

        for ( j=0; j<n; j++ )
        {
            wa1[j] = wa1[j]/sdiag[j];
            for ( i=j+1; i<n; i++ )
                wa1[i] -= r[j*ldr+i]*wa1[j];
        }
        temp = lm_enorm( n, wa1);
        parc = fp/delta/temp/temp;

// *** depending on the sign of the function, update parl or paru.

        if (fp > 0)
            parl = MAX(parl, *par);
        else if (fp < 0)
            paru = MIN(paru, *par);
        // the case fp==0 is precluded by the break condition 

// *** compute an improved estimate for par.

        *par = MAX(parl, *par + parc);

    }

}
예제 #7
0
파일: lmmin.c 프로젝트: drsuuzzz/BaseFinder
void lm_lmdif( int m, int n, double* x, double* fvec, double ftol, double xtol,
               double gtol, int maxfev, double epsfcn, double* diag, int mode,
               double factor, int *info, int *nfev, 
               double* fjac, int* ipvt, double* qtf,
               double* wa1, double* wa2, double* wa3, double* wa4,
               lm_evaluate_ftype *evaluate, lm_print_ftype *printout,
               void *data )
{
/*
 *   the purpose of lmdif is to minimize the sum of the squares of
 *   m nonlinear functions in n variables by a modification of
 *   the levenberg-marquardt algorithm. the user must provide a
 *   subroutine evaluate which calculates the functions. the jacobian
 *   is then calculated by a forward-difference approximation.
 *
 *   the multi-parameter interface lm_lmdif is for users who want
 *   full control and flexibility. most users will be better off using
 *   the simpler interface lmfit provided above.
 *
 *   the parameters are the same as in the legacy FORTRAN implementation,
 *   with the following exceptions:
 *      the old parameter ldfjac which gave leading dimension of fjac has
 *        been deleted because this C translation makes no use of two-
 *        dimensional arrays;
 *      the old parameter nprint has been deleted; printout is now controlled
 *        by the user-supplied routine *printout;
 *      the parameter field *data and the function parameters *evaluate and
 *        *printout have been added; they help avoiding global variables.
 *
 *   parameters:
 *
 *	m is a positive integer input variable set to the number
 *	  of functions.
 *
 *	n is a positive integer input variable set to the number
 *	  of variables. n must not exceed m.
 *
 *	x is an array of length n. on input x must contain
 *	  an initial estimate of the solution vector. on output x
 *	  contains the final estimate of the solution vector.
 *
 *	fvec is an output array of length m which contains
 *	  the functions evaluated at the output x.
 *
 *	ftol is a nonnegative input variable. termination
 *	  occurs when both the actual and predicted relative
 *	  reductions in the sum of squares are at most ftol.
 *	  therefore, ftol measures the relative error desired
 *	  in the sum of squares.
 *
 *	xtol is a nonnegative input variable. termination
 *	  occurs when the relative error between two consecutive
 *	  iterates is at most xtol. therefore, xtol measures the
 *	  relative error desired in the approximate solution.
 *
 *	gtol is a nonnegative input variable. termination
 *	  occurs when the cosine of the angle between fvec and
 *	  any column of the jacobian is at most gtol in absolute
 *	  value. therefore, gtol measures the orthogonality
 *	  desired between the function vector and the columns
 *	  of the jacobian.
 *
 *	maxfev is a positive integer input variable. termination
 *	  occurs when the number of calls to lm_fcn is at least
 *	  maxfev by the end of an iteration.
 *
 *	epsfcn is an input variable used in determining a suitable
 *	  step length for the forward-difference approximation. this
 *	  approximation assumes that the relative errors in the
 *	  functions are of the order of epsfcn. if epsfcn is less
 *	  than the machine precision, it is assumed that the relative
 *	  errors in the functions are of the order of the machine
 *	  precision.
 *
 *	diag is an array of length n. if mode = 1 (see below), diag is
 *        internally set. if mode = 2, diag must contain positive entries
 *        that serve as multiplicative scale factors for the variables.
 *
 *	mode is an integer input variable. if mode = 1, the
 *	  variables will be scaled internally. if mode = 2,
 *	  the scaling is specified by the input diag. other
 *	  values of mode are equivalent to mode = 1.
 *
 *	factor is a positive input variable used in determining the
 *	  initial step bound. this bound is set to the product of
 *	  factor and the euclidean norm of diag*x if nonzero, or else
 *	  to factor itself. in most cases factor should lie in the
 *	  interval (.1,100.). 100. is a generally recommended value.
 *
 *	info is an integer output variable that indicates the termination
 *        status of lm_lmdif as follows:
 *
 *        info < 0  termination requested by user-supplied routine *evaluate;
 *
 *	  info = 0  improper input parameters;
 *
 *	  info = 1  both actual and predicted relative reductions
 *		    in the sum of squares are at most ftol;
 *
 *	  info = 2  relative error between two consecutive iterates
 *		    is at most xtol;
 *
 *	  info = 3  conditions for info = 1 and info = 2 both hold;
 *
 *	  info = 4  the cosine of the angle between fvec and any
 *		    column of the jacobian is at most gtol in
 *		    absolute value;
 *
 *	  info = 5  number of calls to lm_fcn has reached or
 *		    exceeded maxfev;
 *
 *	  info = 6  ftol is too small. no further reduction in
 *		    the sum of squares is possible;
 *
 *	  info = 7  xtol is too small. no further improvement in
 *		    the approximate solution x is possible;
 *
 *	  info = 8  gtol is too small. fvec is orthogonal to the
 *		    columns of the jacobian to machine precision;
 *
 *	nfev is an output variable set to the number of calls to the
 *        user-supplied routine *evaluate.
 *
 *	fjac is an output m by n array. the upper n by n submatrix
 *	  of fjac contains an upper triangular matrix r with
 *	  diagonal elements of nonincreasing magnitude such that
 *
 *		 t     t	   t
 *		p *(jac *jac)*p = r *r,
 *
 *	  where p is a permutation matrix and jac is the final
 *	  calculated jacobian. column j of p is column ipvt(j)
 *	  (see below) of the identity matrix. the lower trapezoidal
 *	  part of fjac contains information generated during
 *	  the computation of r.
 *
 *	ipvt is an integer output array of length n. ipvt
 *	  defines a permutation matrix p such that jac*p = q*r,
 *	  where jac is the final calculated jacobian, q is
 *	  orthogonal (not stored), and r is upper triangular
 *	  with diagonal elements of nonincreasing magnitude.
 *	  column j of p is column ipvt(j) of the identity matrix.
 *
 *	qtf is an output array of length n which contains
 *	  the first n elements of the vector (q transpose)*fvec.
 *
 *	wa1, wa2, and wa3 are work arrays of length n.
 *
 *	wa4 is a work array of length m.
 *
 *   the following parameters are newly introduced in this C translation:
 *
 *      evaluate is the name of the subroutine which calculates the functions.
 *        a default implementation lm_evaluate_default is provided in lm_eval.c;
 *        alternatively, evaluate can be provided by a user calling program.
 *        it should be written as follows:
 *
 *        void evaluate ( double* par, int m_dat, double* fvec, 
 *                       void *data, int *info )
 *        {
 *           // for ( i=0; i<m_dat; ++i )
 *           //     calculate fvec[i] for given parameters par;
 *           // to stop the minimization, 
 *           //     set *info to a negative integer.
 *        }
 *
 *      printout is the name of the subroutine which nforms about fit progress.
 *        a default implementation lm_print_default is provided in lm_eval.c;
 *        alternatively, printout can be provided by a user calling program.
 *        it should be written as follows:
 *
 *        void printout ( int n_par, double* par, int m_dat, double* fvec, 
 *                       void *data, int iflag, int iter, int nfev )
 *        {
 *           // iflag : 0 (init) 1 (outer loop) 2(inner loop) -1(terminated)
 *           // iter  : outer loop counter
 *           // nfev  : number of calls to *evaluate
 *        }
 *
 *      data is an input pointer to an arbitrary structure that is passed to
 *        evaluate. typically, it contains experimental data to be fitted.
 *
 */
    int i, iter, j;
    double actred, delta, dirder, eps, fnorm, fnorm1, gnorm, par, pnorm,
        prered, ratio, step, sum, temp, temp1, temp2, temp3, xnorm;
    static double p1 = 0.1;
    static double p5 = 0.5;
    static double p25 = 0.25;
    static double p75 = 0.75;
    static double p0001 = 1.0e-4;

    *nfev = 0; // function evaluation counter
    iter = 1;  // outer loop counter
    par = 0;   // levenberg-marquardt parameter 
    delta = 0; // just to prevent a warning (initialization within if-clause)
    xnorm = 0; // dito

    temp = MAX(epsfcn,LM_MACHEP);
    eps = sqrt(temp); // used in calculating the Jacobian by forward differences

// *** check the input parameters for errors.

    if ( (n <= 0) || (m < n) || (ftol < 0.)
	|| (xtol < 0.) || (gtol < 0.) || (maxfev <= 0) || (factor <= 0.) )
    {
        *info = 0; // invalid parameter
        return;
    }
    if ( mode == 2 )  /* scaling by diag[] */
    {
	for ( j=0; j<n; j++ )  /* check for nonpositive elements */
        {
            if ( diag[j] <= 0.0 )
            {
                *info = 0; // invalid parameter
                return;
            }
        }	
    }
#if BUG
    printf( "lmdif\n" );
#endif

// *** evaluate the function at the starting point and calculate its norm.

    *info = 0;
    (*evaluate)( x, m, fvec, data, info );
    (*printout)( n, x, m, fvec, data, 0, 0, ++(*nfev) );
    if ( *info < 0 ) return;
    fnorm = lm_enorm(m,fvec);

// *** the outer loop.

    do { 
#if BUG 
        printf( "lmdif/ outer loop iter=%d nfev=%d fnorm=%.10e\n",
                iter, *nfev, fnorm );
#endif

// O** calculate the jacobian matrix.

        for ( j=0; j<n; j++ )
        {
            temp = x[j];
            step = eps * fabs(temp);
            if (step == 0.) step = eps;
            x[j] = temp + step;
            *info = 0;
            (*evaluate)( x, m, wa4, data, info );
            (*printout)( n, x, m, wa4, data, 1, iter, ++(*nfev) );
            if ( *info < 0 ) return;  // user requested break
            x[j] = temp;
            for ( i=0; i<m; i++ )
                fjac[j*m+i] = (wa4[i] - fvec[i]) / step;
        }
#if BUG>1
        // DEBUG: print the entire matrix
        for ( i=0; i<m; i++ )
        {
            for ( j=0; j<n; j++ )
                printf( "%.5e ", y[j*m+i] );
            printf( "\n" );
        }
#endif

// O** compute the qr factorization of the jacobian.

        lm_qrfac( m, n, fjac, 1, ipvt, wa1, wa2, wa3);

// O** on the first iteration ... 

        if (iter == 1)
        {
            if (mode != 2)
//      ... scale according to the norms of the columns of the initial jacobian.
            {
                for ( j=0; j<n; j++ )
                {
                    diag[j] = wa2[j];
                    if ( wa2[j] == 0. )
                        diag[j] = 1.;
                }
            }

//      ... calculate the norm of the scaled x and 
//          initialize the step bound delta.

            for ( j=0; j<n; j++ )
                wa3[j] = diag[j] * x[j];

            xnorm = lm_enorm( n, wa3 );
            delta = factor*xnorm;
            if (delta == 0.)
                delta = factor;
        }

// O** form (q transpose)*fvec and store the first n components in qtf.

        for ( i=0; i<m; i++ )
            wa4[i] = fvec[i];

        for ( j=0; j<n; j++ )
        {
            temp3 = fjac[j*m+j];
            if (temp3 != 0.)
            {
                sum = 0;
                for ( i=j; i<m; i++ )
                    sum += fjac[j*m+i] * wa4[i];
                temp = -sum / temp3;
                for ( i=j; i<m; i++ )
                    wa4[i] += fjac[j*m+i] * temp;
            }
            fjac[j*m+j] = wa1[j];
            qtf[j] = wa4[j];
        }

// O** compute the norm of the scaled gradient and test for convergence.

        gnorm = 0;
        if ( fnorm != 0 )
        {
            for ( j=0; j<n; j++ )
            {
                if ( wa2[ ipvt[j] ] == 0 ) continue;
                
                sum = 0.;
                for ( i=0; i<=j; i++ )
                    sum += fjac[j*m+i] * qtf[i] / fnorm;
                gnorm = MAX( gnorm, fabs(sum/wa2[ ipvt[j] ]) );
            }
        }

        if ( gnorm <= gtol )
        {
            *info = 4;
            return;
        }

// O** rescale if necessary.

        if ( mode != 2 )
        {
            for ( j=0; j<n; j++ )
                diag[j] = MAX(diag[j],wa2[j]);
        }

// O** the inner loop.

        do {
#if BUG 
            printf( "lmdif/ inner loop iter=%d nfev=%d\n", iter, *nfev );
#endif

// OI* determine the levenberg-marquardt parameter.

            lm_lmpar( n,fjac,m,ipvt,diag,qtf,delta,&par,wa1,wa2,wa3,wa4 );

// OI* store the direction p and x + p. calculate the norm of p.

            for ( j=0; j<n; j++ )
            {
                wa1[j] = -wa1[j];
                wa2[j] = x[j] + wa1[j];
                wa3[j] = diag[j]*wa1[j];
            }
            pnorm = lm_enorm(n,wa3);

// OI* on the first iteration, adjust the initial step bound.

            if ( *nfev<= 1+n ) // bug corrected by J. Wuttke in 2004
                delta = MIN(delta,pnorm);

// OI* evaluate the function at x + p and calculate its norm.

            *info = 0;
            (*evaluate)( wa2, m, wa4, data, info );
            (*printout)( n, x, m, wa4, data, 2, iter, ++(*nfev) );
            if ( *info < 0 ) return;  // user requested break

            fnorm1 = lm_enorm(m,wa4);
#if BUG 
            printf( "lmdif/ pnorm %.10e  fnorm1 %.10e  fnorm %.10e"
                    " delta=%.10e par=%.10e\n",
                    pnorm, fnorm1, fnorm, delta, par );
#endif

// OI* compute the scaled actual reduction.

            if ( p1*fnorm1 < fnorm )
                actred = 1 - SQR( fnorm1/fnorm );
            else
                actred = -1;

// OI* compute the scaled predicted reduction and 
//     the scaled directional derivative.

            for ( j=0; j<n; j++ )
            {
                wa3[j] = 0;
                for ( i=0; i<=j; i++ )
                    wa3[i] += fjac[j*m+i]*wa1[ ipvt[j] ];
            }
            temp1 = lm_enorm(n,wa3) / fnorm;
            temp2 = sqrt(par) * pnorm / fnorm;
            prered = SQR(temp1) + 2 * SQR(temp2);
            dirder = - ( SQR(temp1) + SQR(temp2) );

// OI* compute the ratio of the actual to the predicted reduction.

            ratio = prered!=0 ? actred/prered : 0;
#if BUG 
            printf( "lmdif/ actred=%.10e prered=%.10e ratio=%.10e"
                    " sq(1)=%.10e sq(2)=%.10e dd=%.10e\n",
                    actred, prered, prered!=0 ? ratio : 0.,
                    SQR(temp1), SQR(temp2), dirder );
#endif

// OI* update the step bound.

            if (ratio <= p25)
            {
                if (actred >= 0.)
                    temp = p5;
                else
                    temp = p5*dirder/(dirder + p5*actred);
                if ( p1*fnorm1 >= fnorm || temp < p1 )
                    temp = p1;
                delta = temp * MIN(delta,pnorm/p1);
                par /= temp;
            }
            else if ( par == 0. || ratio >= p75 )
            {
                delta = pnorm/p5;
                par *= p5;
            }

// OI* test for successful iteration...

            if (ratio >= p0001)
            {

//     ... successful iteration. update x, fvec, and their norms.

                for ( j=0; j<n; j++ )
                {
                    x[j] = wa2[j];
                    wa2[j] = diag[j]*x[j];
                }
                for ( i=0; i<m; i++ )
                    fvec[i] = wa4[i];
                xnorm = lm_enorm(n,wa2);
                fnorm = fnorm1;
                iter++;
            }
#if BUG 
            else {
                printf( "ATTN: iteration considered unsuccessful\n" );
            } 
#endif

// OI* tests for convergence ( otherwise *info = 1, 2, or 3 )

            *info = 0; // do not terminate (unless overwritten by nonzero value)
            if ( fabs(actred) <= ftol && prered <= ftol && p5*ratio <= 1 )
                *info = 1;
            if (delta <= xtol*xnorm)
                *info += 2;
            if ( *info != 0)
                return;

// OI* tests for termination and stringent tolerances.

            if ( *nfev >= maxfev)
                *info = 5;
            if ( fabs(actred) <= LM_MACHEP &&
                 prered <= LM_MACHEP && p5*ratio <= 1 )
                *info = 6;
            if (delta <= LM_MACHEP*xnorm)
                *info = 7;
            if (gnorm <= LM_MACHEP)
                *info = 8;
            if ( *info != 0)
                return;

// OI* end of the inner loop. repeat if iteration unsuccessful.

        } while (ratio < p0001);

// O** end of the outer loop.

    } while (1);
	
}
예제 #8
0
파일: lmmin.cpp 프로젝트: MrTheodor/gromacs
static void lm_qrfac(const int m, const int n, double* A, int* Pivot, double* Rdiag,
                     double* Acnorm, double* W)
/*
 *     This subroutine uses Householder transformations with column pivoting
 *     to compute a QR factorization of the m by n matrix A. That is, qrfac
 *     determines an orthogonal matrix Q, a permutation matrix P, and an
 *     upper trapezoidal matrix R with diagonal elements of nonincreasing
 *     magnitude, such that A*P = Q*R. The Householder transformation for
 *     column k, k = 1,2,...,n, is of the form
 *
 *          I - 2*w*wT/|w|^2
 *
 *     where w has zeroes in the first k-1 positions.
 *
 *     Parameters:
 *
 *      m is an INPUT parameter set to the number of rows of A.
 *
 *      n is an INPUT parameter set to the number of columns of A.
 *
 *      A is an m by n array. On INPUT, A contains the matrix for which the
 *        QR factorization is to be computed. On OUTPUT the strict upper
 *        trapezoidal part of A contains the strict upper trapezoidal part
 *        of R, and the lower trapezoidal part of A contains a factored form
 *        of Q (the non-trivial elements of the vectors w described above).
 *
 *      Pivot is an integer OUTPUT array of length n that describes the
 *        permutation matrix P. Column j of P is column Pivot(j) of the
 *        identity matrix.
 *
 *      Rdiag is an OUTPUT array of length n which contains the diagonal
 *        elements of R.
 *
 *      Acnorm is an OUTPUT array of length n which contains the norms of
 *        the corresponding columns of the input matrix A. If this information
 *        is not needed, then Acnorm can share storage with Rdiag.
 *
 *      W is a work array of length n.
 *
 */
{
    int i, j, k, kmax;
    double ajnorm, sum, temp;

#ifdef LMFIT_DEBUG_MESSAGES
    printf("debug qrfac\n");
#endif

    /** Compute initial column norms;
        initialize Pivot with identity permutation. ***/
    for (j = 0; j < n; j++) {
        W[j] = Rdiag[j] = Acnorm[j] = lm_enorm(m, &A[j*m]);
        Pivot[j] = j;
    }

    /** Loop over columns of A. **/
    assert(n <= m);
    for (j = 0; j < n; j++) {

        /** Bring the column of largest norm into the pivot position. **/
        kmax = j;
        for (k = j+1; k < n; k++)
            if (Rdiag[k] > Rdiag[kmax])
                kmax = k;

        if (kmax != j) {
            /* Swap columns j and kmax. */
            k = Pivot[j];
            Pivot[j] = Pivot[kmax];
            Pivot[kmax] = k;
            for (i = 0; i < m; i++) {
                temp = A[j*m+i];
                A[j*m+i] = A[kmax*m+i];
                A[kmax*m+i] = temp;
            }
            /* Half-swap: Rdiag[j], W[j] won't be needed any further. */
            Rdiag[kmax] = Rdiag[j];
            W[kmax] = W[j];
        }

        /** Compute the Householder reflection vector w_j to reduce the
            j-th column of A to a multiple of the j-th unit vector. **/
        ajnorm = lm_enorm(m-j, &A[j*m+j]);
        if (ajnorm == 0) {
            Rdiag[j] = 0;
            continue;
        }

        /* Let the partial column vector A[j][j:] contain w_j := e_j+-a_j/|a_j|,
           where the sign +- is chosen to avoid cancellation in w_jj. */
        if (A[j*m+j] < 0)
            ajnorm = -ajnorm;
        for (i = j; i < m; i++)
            A[j*m+i] /= ajnorm;
        A[j*m+j] += 1;

        /** Apply the Householder transformation U_w := 1 - 2*w_j.w_j/|w_j|^2
            to the remaining columns, and update the norms. **/
        for (k = j+1; k < n; k++) {
            /* Compute scalar product w_j * a_j. */
            sum = 0;
            for (i = j; i < m; i++)
                sum += A[j*m+i] * A[k*m+i];

            /* Normalization is simplified by the coincidence |w_j|^2=2w_jj. */
            temp = sum / A[j*m+j];

            /* Carry out transform U_w_j * a_k. */
            for (i = j; i < m; i++)
                A[k*m+i] -= temp * A[j*m+i];

            /* No idea what happens here. */
            if (Rdiag[k] != 0) {
                temp = A[m*k+j] / Rdiag[k];
                if (fabs(temp) < 1) {
                    Rdiag[k] *= sqrt(1 - SQR(temp));
                    temp = Rdiag[k] / W[k];
                } else
                    temp = 0;
                if (temp == 0 || 0.05 * SQR(temp) <= LM_MACHEP) {
                    Rdiag[k] = lm_enorm(m-j-1, &A[m*k+j+1]);
                    W[k] = Rdiag[k];
                }
            }
        }

        Rdiag[j] = -ajnorm;
    }
} /*** lm_qrfac. ***/
예제 #9
0
파일: lmmin.cpp 프로젝트: MrTheodor/gromacs
static void lm_lmpar(const int n, double* r, const int ldr, const int* Pivot,
                     const double* diag, const double* qtb, const double delta,
                     double* par, double* x, double* Sdiag, double* aux, double* xdi)
/*     Given an m by n matrix A, an n by n nonsingular diagonal matrix D,
 *     an m-vector b, and a positive number delta, the problem is to
 *     determine a parameter value par such that if x solves the system
 *
 *          A*x = b  and  sqrt(par)*D*x = 0
 *
 *     in the least squares sense, and dxnorm is the Euclidean norm of D*x,
 *     then either par=0 and (dxnorm-delta) < 0.1*delta, or par>0 and
 *     abs(dxnorm-delta) < 0.1*delta.
 *
 *     Using lm_qrsolv, this subroutine completes the solution of the
 *     problem if it is provided with the necessary information from the
 *     QR factorization, with column pivoting, of A. That is, if A*P = Q*R,
 *     where P is a permutation matrix, Q has orthogonal columns, and R is
 *     an upper triangular matrix with diagonal elements of nonincreasing
 *     magnitude, then lmpar expects the full upper triangle of R, the
 *     permutation matrix P, and the first n components of Q^T*b. On output
 *     lmpar also provides an upper triangular matrix S such that
 *
 *          P^T*(A^T*A + par*D*D)*P = S^T*S.
 *
 *     S is employed within lmpar and may be of separate interest.
 *
 *     Only a few iterations are generally needed for convergence of the
 *     algorithm. If, however, the limit of 10 iterations is reached, then
 *     the output par will contain the best value obtained so far.
 *
 *     Parameters:
 *
 *      n is a positive integer INPUT variable set to the order of r.
 *
 *      r is an n by n array. On INPUT the full upper triangle must contain
 *        the full upper triangle of the matrix R. On OUTPUT the full upper
 *        triangle is unaltered, and the strict lower triangle contains the
 *        strict upper triangle (transposed) of the upper triangular matrix S.
 *
 *      ldr is a positive integer INPUT variable not less than n which
 *        specifies the leading dimension of the array R.
 *
 *      Pivot is an integer INPUT array of length n which defines the
 *        permutation matrix P such that A*P = Q*R. Column j of P is column
 *        Pivot(j) of the identity matrix.
 *
 *      diag is an INPUT array of length n which must contain the diagonal
 *        elements of the matrix D.
 *
 *      qtb is an INPUT array of length n which must contain the first
 *        n elements of the vector Q^T*b.
 *
 *      delta is a positive INPUT variable which specifies an upper bound
 *        on the Euclidean norm of D*x.
 *
 *      par is a nonnegative variable. On INPUT par contains an initial
 *        estimate of the Levenberg-Marquardt parameter. On OUTPUT par
 *        contains the final estimate.
 *
 *      x is an OUTPUT array of length n which contains the least-squares
 *        solution of the system A*x = b, sqrt(par)*D*x = 0, for the output par.
 *
 *      Sdiag is an array of length n needed as workspace; on OUTPUT it
 *        contains the diagonal elements of the upper triangular matrix S.
 *
 *      aux is a multi-purpose work array of length n.
 *
 *      xdi is a work array of length n. On OUTPUT: diag[j] * x[j].
 *
 */
{
    int i, iter, j, nsing;
    double dxnorm, fp, fp_old, gnorm, parc, parl, paru;
    double sum, temp;
    static double p1 = 0.1;

    /*** Compute and store in x the Gauss-Newton direction. If the Jacobian
         is rank-deficient, obtain a least-squares solution. ***/

    nsing = n;
    for (j = 0; j < n; j++) {
        aux[j] = qtb[j];
        if (r[j*ldr+j] == 0 && nsing == n)
            nsing = j;
        if (nsing < n)
            aux[j] = 0;
    }
    for (j = nsing-1; j >= 0; j--) {
        aux[j] = aux[j] / r[j+ldr*j];
        temp = aux[j];
        for (i = 0; i < j; i++)
            aux[i] -= r[j*ldr+i] * temp;
    }

    for (j = 0; j < n; j++)
        x[Pivot[j]] = aux[j];

    /*** Initialize the iteration counter, evaluate the function at the origin,
         and test for acceptance of the Gauss-Newton direction. ***/

    for (j = 0; j < n; j++)
        xdi[j] = diag[j] * x[j];
    dxnorm = lm_enorm(n, xdi);
    fp = dxnorm - delta;
    if (fp <= p1 * delta) {
#ifdef LMFIT_DEBUG_MESSAGES
        printf("debug lmpar nsing=%d, n=%d, terminate[fp<=p1*del]\n", nsing, n);
#endif
        *par = 0;
        return;
    }

    /*** If the Jacobian is not rank deficient, the Newton step provides a
         lower bound, parl, for the zero of the function. Otherwise set this
         bound to zero. ***/

    parl = 0;
    if (nsing >= n) {
        for (j = 0; j < n; j++)
            aux[j] = diag[Pivot[j]] * xdi[Pivot[j]] / dxnorm;

        for (j = 0; j < n; j++) {
            sum = 0;
            for (i = 0; i < j; i++)
                sum += r[j*ldr+i] * aux[i];
            aux[j] = (aux[j] - sum) / r[j+ldr*j];
        }
        temp = lm_enorm(n, aux);
        parl = fp / delta / temp / temp;
    }

    /*** Calculate an upper bound, paru, for the zero of the function. ***/

    for (j = 0; j < n; j++) {
        sum = 0;
        for (i = 0; i <= j; i++)
            sum += r[j*ldr+i] * qtb[i];
        aux[j] = sum / diag[Pivot[j]];
    }
    gnorm = lm_enorm(n, aux);
    paru = gnorm / delta;
    if (paru == 0)
        paru = LM_DWARF / MIN(delta, p1);

    /*** If the input par lies outside of the interval (parl,paru),
         set par to the closer endpoint. ***/

    *par = MAX(*par, parl);
    *par = MIN(*par, paru);
    if (*par == 0)
        *par = gnorm / dxnorm;

    /*** Iterate. ***/

    for (iter = 0;; iter++) {

        /** Evaluate the function at the current value of par. **/
        if (*par == 0)
            *par = MAX(LM_DWARF, 0.001 * paru);
        temp = sqrt(*par);
        for (j = 0; j < n; j++)
            aux[j] = temp * diag[j];

        lm_qrsolv(n, r, ldr, Pivot, aux, qtb, x, Sdiag, xdi);
        /* return values are r, x, Sdiag */

        for (j = 0; j < n; j++)
            xdi[j] = diag[j] * x[j]; /* used as output */
        dxnorm = lm_enorm(n, xdi);
        fp_old = fp;
        fp = dxnorm - delta;

        /** If the function is small enough, accept the current value
            of par. Also test for the exceptional cases where parl
            is zero or the number of iterations has reached 10. **/
        if (fabs(fp) <= p1 * delta ||
            (parl == 0 && fp <= fp_old && fp_old < 0) || iter == 10) {
#ifdef LMFIT_DEBUG_MESSAGES
            printf("debug lmpar nsing=%d, iter=%d, "
                   "par=%.4e [%.4e %.4e], delta=%.4e, fp=%.4e\n",
                   nsing, iter, *par, parl, paru, delta, fp);
#endif
            break; /* the only exit from the iteration. */
        }

        /** Compute the Newton correction. **/
        for (j = 0; j < n; j++)
            aux[j] = diag[Pivot[j]] * xdi[Pivot[j]] / dxnorm;

        for (j = 0; j < n; j++) {
            aux[j] = aux[j] / Sdiag[j];
            for (i = j+1; i < n; i++)
                aux[i] -= r[j*ldr+i] * aux[j];
        }
        temp = lm_enorm(n, aux);
        parc = fp / delta / temp / temp;

        /** Depending on the sign of the function, update parl or paru. **/
        if (fp > 0)
            parl = MAX(parl, *par);
        else /* fp < 0 [the case fp==0 is precluded by the break condition] */
            paru = MIN(paru, *par);

        /** Compute an improved estimate for par. **/
        *par = MAX(parl, *par + parc);
    }

} /*** lm_lmpar. ***/
예제 #10
0
파일: lmmin.cpp 프로젝트: MrTheodor/gromacs
void lmmin(const int n, double* x, const int m, const void* data,
           void (*evaluate)(const double* par, const int m_dat,
                            const void* data, double* fvec, int* userbreak),
           const lm_control_struct* C, lm_status_struct* S)
{
    int j, i;
    double actred, dirder, fnorm, fnorm1, gnorm, pnorm, prered, ratio, step,
        sum, temp, temp1, temp2, temp3;

    /***  Initialize internal variables.  ***/

    int maxfev = C->patience * (n+1);

    int inner_success; /* flag for loop control */
    double lmpar = 0;  /* Levenberg-Marquardt parameter */
    double delta = 0;
    double xnorm = 0;
    double eps = sqrt(MAX(C->epsilon, LM_MACHEP)); /* for forward differences */

    int nout = C->n_maxpri == -1 ? n : MIN(C->n_maxpri, n);

    /* Reinterpret C->msgfile=NULL as stdout (which is unavailable for
       compile-time initialization of lm_control_double and similar). */
    FILE* msgfile = C->msgfile ? C->msgfile : stdout;

    /***  Default status info; must be set before first return statement.  ***/

    S->outcome = 0; /* status code */
    S->userbreak = 0;
    S->nfev = 0; /* function evaluation counter */

    /***  Check input parameters for errors.  ***/

    if (n <= 0) {
        fprintf(stderr, "lmmin: invalid number of parameters %i\n", n);
        S->outcome = 10;
        return;
    }
    if (m < n) {
        fprintf(stderr, "lmmin: number of data points (%i) "
                        "smaller than number of parameters (%i)\n",
                m, n);
        S->outcome = 10;
        return;
    }
    if (C->ftol < 0 || C->xtol < 0 || C->gtol < 0) {
        fprintf(stderr,
                "lmmin: negative tolerance (at least one of %g %g %g)\n",
                C->ftol, C->xtol, C->gtol);
        S->outcome = 10;
        return;
    }
    if (maxfev <= 0) {
        fprintf(stderr, "lmmin: nonpositive function evaluations limit %i\n",
                maxfev);
        S->outcome = 10;
        return;
    }
    if (C->stepbound <= 0) {
        fprintf(stderr, "lmmin: nonpositive stepbound %g\n", C->stepbound);
        S->outcome = 10;
        return;
    }
    if (C->scale_diag != 0 && C->scale_diag != 1) {
        fprintf(stderr, "lmmin: logical variable scale_diag=%i, "
                        "should be 0 or 1\n",
                C->scale_diag);
        S->outcome = 10;
        return;
    }

    /***  Allocate work space.  ***/

    /* Allocate total workspace with just one system call */
    char* ws;
    if ((ws = (char *)malloc((2*m + 5*n + m*n) * sizeof(double) +
                             n * sizeof(int))) == NULL) {
        S->outcome = 9;
        return;
    }

    /* Assign workspace segments. */
    char* pws = ws;
    double* fvec = (double*)pws;
    pws += m * sizeof(double) / sizeof(char);
    double* diag = (double*)pws;
    pws += n * sizeof(double) / sizeof(char);
    double* qtf = (double*)pws;
    pws += n * sizeof(double) / sizeof(char);
    double* fjac = (double*)pws;
    pws += n * m * sizeof(double) / sizeof(char);
    double* wa1 = (double*)pws;
    pws += n * sizeof(double) / sizeof(char);
    double* wa2 = (double*)pws;
    pws += n * sizeof(double) / sizeof(char);
    double* wa3 = (double*)pws;
    pws += n * sizeof(double) / sizeof(char);
    double* wf = (double*)pws;
    pws += m * sizeof(double) / sizeof(char);
    int* Pivot = (int*)pws;
    //pws += n * sizeof(int) / sizeof(char);

    /* Initialize diag. */
    if (!C->scale_diag)
        for (j = 0; j < n; j++)
            diag[j] = 1;

    /***  Evaluate function at starting point and calculate norm.  ***/

    if (C->verbosity) {
        fprintf(msgfile, "lmmin start ");
        lm_print_pars(nout, x, msgfile);
    }
    (*evaluate)(x, m, data, fvec, &(S->userbreak));
    if (C->verbosity > 4)
        for (i = 0; i < m; ++i)
            fprintf(msgfile, "    fvec[%4i] = %18.8g\n", i, fvec[i]);
    S->nfev = 1;
    if (S->userbreak)
        goto terminate;
    fnorm = lm_enorm(m, fvec);
    if (C->verbosity)
        fprintf(msgfile, "  fnorm = %18.8g\n", fnorm);

    if (!isfinite(fnorm)) {
        S->outcome = 12; /* nan */
        goto terminate;
    } else if (fnorm <= LM_DWARF) {
        S->outcome = 0; /* sum of squares almost zero, nothing to do */
        goto terminate;
    }

    /***  The outer loop: compute gradient, then descend.  ***/

    for (int outer = 0;; ++outer) {

        /** Calculate the Jacobian. **/
        for (j = 0; j < n; j++) {
            temp = x[j];
            step = MAX(eps * eps, eps * fabs(temp));
            x[j] += step; /* replace temporarily */
            (*evaluate)(x, m, data, wf, &(S->userbreak));
            ++(S->nfev);
            if (S->userbreak)
                goto terminate;
            for (i = 0; i < m; i++)
                fjac[j*m+i] = (wf[i] - fvec[i]) / step;
            x[j] = temp; /* restore */
        }
        if (C->verbosity >= 10) {
            /* print the entire matrix */
            printf("\nlmmin Jacobian\n");
            for (i = 0; i < m; i++) {
                printf("  ");
                for (j = 0; j < n; j++)
                    printf("%.5e ", fjac[j*m+i]);
                printf("\n");
            }
        }

        /** Compute the QR factorization of the Jacobian. **/

        /* fjac is an m by n array. The upper n by n submatrix of fjac is made
         *   to contain an upper triangular matrix R with diagonal elements of
         *   nonincreasing magnitude such that
         *
         *         P^T*(J^T*J)*P = R^T*R
         *
         *         (NOTE: ^T stands for matrix transposition),
         *
         *   where P is a permutation matrix and J is the final calculated
         *   Jacobian. Column j of P is column Pivot(j) of the identity matrix.
         *   The lower trapezoidal part of fjac contains information generated
         *   during the computation of R.
         *
         * Pivot is an integer array of length n. It defines a permutation
         *   matrix P such that jac*P = Q*R, where jac is the final calculated
         *   Jacobian, Q is orthogonal (not stored), and R is upper triangular
         *   with diagonal elements of nonincreasing magnitude. Column j of P
         *   is column Pivot(j) of the identity matrix.
         */

        lm_qrfac(m, n, fjac, Pivot, wa1, wa2, wa3);
        /* return values are Pivot, wa1=rdiag, wa2=acnorm */

        /** Form Q^T * fvec, and store first n components in qtf. **/
        for (i = 0; i < m; i++)
            wf[i] = fvec[i];

        for (j = 0; j < n; j++) {
            temp3 = fjac[j*m+j];
            if (temp3 != 0) {
                sum = 0;
                for (i = j; i < m; i++)
                    sum += fjac[j*m+i] * wf[i];
                temp = -sum / temp3;
                for (i = j; i < m; i++)
                    wf[i] += fjac[j*m+i] * temp;
            }
            fjac[j*m+j] = wa1[j];
            qtf[j] = wf[j];
        }

        /**  Compute norm of scaled gradient and detect degeneracy. **/
        gnorm = 0;
        for (j = 0; j < n; j++) {
            if (wa2[Pivot[j]] == 0)
                continue;
            sum = 0;
            for (i = 0; i <= j; i++)
                sum += fjac[j*m+i] * qtf[i];
            gnorm = MAX(gnorm, fabs(sum / wa2[Pivot[j]] / fnorm));
        }

        if (gnorm <= C->gtol) {
            S->outcome = 4;
            goto terminate;
        }

        /** Initialize or update diag and delta. **/
        if (!outer) { /* first iteration only */
            if (C->scale_diag) {
                /* diag := norms of the columns of the initial Jacobian */
                for (j = 0; j < n; j++)
                    diag[j] = wa2[j] ? wa2[j] : 1;
                /* xnorm := || D x || */
                for (j = 0; j < n; j++)
                    wa3[j] = diag[j] * x[j];
                xnorm = lm_enorm(n, wa3);
                if (C->verbosity >= 2) {
                    fprintf(msgfile, "lmmin diag  ");
                    lm_print_pars(nout, x, msgfile); // xnorm
                    fprintf(msgfile, "  xnorm = %18.8g\n", xnorm);
                }
                /* Only now print the header for the loop table. */
                if (C->verbosity >= 3) {
                    fprintf(msgfile, "  o  i     lmpar    prered"
                                     "          ratio    dirder      delta"
                                     "      pnorm                 fnorm");
                    for (i = 0; i < nout; ++i)
                        fprintf(msgfile, "               p%i", i);
                    fprintf(msgfile, "\n");
                }
            } else {
                xnorm = lm_enorm(n, x);
            }
            if (!isfinite(xnorm)) {
                S->outcome = 12; /* nan */
                goto terminate;
            }
            /* Initialize the step bound delta. */
            if (xnorm)
                delta = C->stepbound * xnorm;
            else
                delta = C->stepbound;
        } else {
            if (C->scale_diag) {
                for (j = 0; j < n; j++)
                    diag[j] = MAX(diag[j], wa2[j]);
            }
        }

        /** The inner loop. **/
        int inner = 0;
        do {

            /** Determine the Levenberg-Marquardt parameter. **/
            lm_lmpar(n, fjac, m, Pivot, diag, qtf, delta, &lmpar,
                     wa1, wa2, wf, wa3);
            /* used return values are fjac (partly), lmpar, wa1=x, wa3=diag*x */

            /* Predict scaled reduction. */
            pnorm = lm_enorm(n, wa3);
            if (!isfinite(pnorm)) {
                S->outcome = 12; /* nan */
                goto terminate;
            }
            temp2 = lmpar * SQR(pnorm / fnorm);
            for (j = 0; j < n; j++) {
                wa3[j] = 0;
                for (i = 0; i <= j; i++)
                    wa3[i] -= fjac[j*m+i] * wa1[Pivot[j]];
            }
            temp1 = SQR(lm_enorm(n, wa3) / fnorm);
            if (!isfinite(temp1)) {
                S->outcome = 12; /* nan */
                goto terminate;
            }
            prered = temp1 + 2*temp2;
            dirder = -temp1 + temp2; /* scaled directional derivative */

            /* At first call, adjust the initial step bound. */
            if (!outer && pnorm < delta)
                delta = pnorm;

            /** Evaluate the function at x + p. **/
            for (j = 0; j < n; j++)
                wa2[j] = x[j] - wa1[j];
            (*evaluate)(wa2, m, data, wf, &(S->userbreak));
            ++(S->nfev);
            if (S->userbreak)
                goto terminate;
            fnorm1 = lm_enorm(m, wf);
            if (!isfinite(fnorm1)) {
                S->outcome = 12; /* nan */
                goto terminate;
            }

            /** Evaluate the scaled reduction. **/

            /* Actual scaled reduction. */
            actred = 1 - SQR(fnorm1 / fnorm);

            /* Ratio of actual to predicted reduction. */
            ratio = prered ? actred / prered : 0;

            if (C->verbosity == 2) {
                fprintf(msgfile, "lmmin (%i:%i) ", outer, inner);
                lm_print_pars(nout, wa2, msgfile); // fnorm1,
            } else if (C->verbosity >= 3) {
                printf("%3i %2i %9.2g %9.2g %14.6g"
                       " %9.2g %10.3e %10.3e %21.15e",
                       outer, inner, lmpar, prered, ratio,
                       dirder, delta, pnorm, fnorm1);
                for (i = 0; i < nout; ++i)
                    fprintf(msgfile, " %16.9g", wa2[i]);
                fprintf(msgfile, "\n");
            }

            /* Update the step bound. */
            if (ratio <= 0.25) {
                if (actred >= 0)
                    temp = 0.5;
                else if (actred > -99) /* -99 = 1-1/0.1^2 */
                    temp = MAX(dirder / (2*dirder + actred), 0.1);
                else
                    temp = 0.1;
                delta = temp * MIN(delta, pnorm / 0.1);
                lmpar /= temp;
            } else if (ratio >= 0.75) {
                delta = 2 * pnorm;
                lmpar *= 0.5;
            } else if (!lmpar) {
                delta = 2 * pnorm;
            }

            /**  On success, update solution, and test for convergence. **/

            inner_success = ratio >= 1e-4;
            if (inner_success) {

                /* Update x, fvec, and their norms. */
                if (C->scale_diag) {
                    for (j = 0; j < n; j++) {
                        x[j] = wa2[j];
                        wa2[j] = diag[j] * x[j];
                    }
                } else {
                    for (j = 0; j < n; j++)
                        x[j] = wa2[j];
                }
                for (i = 0; i < m; i++)
                    fvec[i] = wf[i];
                xnorm = lm_enorm(n, wa2);
                if (!isfinite(xnorm)) {
                    S->outcome = 12; /* nan */
                    goto terminate;
                }
                fnorm = fnorm1;
            }

            /* Convergence tests. */
            S->outcome = 0;
            if (fnorm <= LM_DWARF)
                goto terminate; /* success: sum of squares almost zero */
            /* Test two criteria (both may be fulfilled). */
            if (fabs(actred) <= C->ftol && prered <= C->ftol && ratio <= 2)
                S->outcome = 1; /* success: x almost stable */
            if (delta <= C->xtol * xnorm)
                S->outcome += 2; /* success: sum of squares almost stable */
            if (S->outcome != 0) {
                goto terminate;
            }

            /** Tests for termination and stringent tolerances. **/
            if (S->nfev >= maxfev) {
                S->outcome = 5;
                goto terminate;
            }
            if (fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP &&
                ratio <= 2) {
                S->outcome = 6;
                goto terminate;
            }
            if (delta <= LM_MACHEP * xnorm) {
                S->outcome = 7;
                goto terminate;
            }
            if (gnorm <= LM_MACHEP) {
                S->outcome = 8;
                goto terminate;
            }

            /** End of the inner loop. Repeat if iteration unsuccessful. **/
            ++inner;
        } while (!inner_success);

    }; /***  End of the outer loop.  ***/

terminate:
    S->fnorm = lm_enorm(m, fvec);
    if (C->verbosity >= 2)
        printf("lmmin outcome (%i) xnorm %g ftol %g xtol %g\n", S->outcome,
               xnorm, C->ftol, C->xtol);
    if (C->verbosity & 1) {
        fprintf(msgfile, "lmmin final ");
        lm_print_pars(nout, x, msgfile); // S->fnorm,
        fprintf(msgfile, "  fnorm = %18.8g\n", S->fnorm);
    }
    if (S->userbreak) /* user-requested break */
        S->outcome = 11;

    /***  Deallocate the workspace.  ***/
    free(ws);

} /*** lmmin. ***/
예제 #11
0
void lm_lmdif( int m, int n, double *x, double *fvec, double ftol,
               double xtol, double gtol, int maxfev, double epsfcn,
               double *diag, int mode, double factor, int *info, int *nfev,
               double *fjac, int *ipvt, double *qtf, double *wa1,
               double *wa2, double *wa3, double *wa4,
               void (*evaluate) (const double *par, int m_dat, const void *data,
                                 double *fvec, int *info),
               void (*printout) (int n_par, const double *par, int m_dat,
                                 const void *data, const double *fvec,
                                 int printflags, int iflag, int iter, int nfev),
               int printflags, const void *data )
{
/*
 *   The purpose of lmdif is to minimize the sum of the squares of
 *   m nonlinear functions in n variables by a modification of
 *   the levenberg-marquardt algorithm. The user must provide a
 *   subroutine evaluate which calculates the functions. The jacobian
 *   is then calculated by a forward-difference approximation.
 *
 *   The multi-parameter interface lm_lmdif is for users who want
 *   full control and flexibility. Most users will be better off using
 *   the simpler interface lmmin provided above.
 *
 *   Parameters:
 *
 *      m is a positive integer input variable set to the number
 *        of functions.
 *
 *      n is a positive integer input variable set to the number
 *        of variables; n must not exceed m.
 *
 *      x is an array of length n. On input x must contain an initial
 *        estimate of the solution vector. On OUTPUT x contains the
 *        final estimate of the solution vector.
 *
 *      fvec is an OUTPUT array of length m which contains
 *        the functions evaluated at the output x.
 *
 *      ftol is a nonnegative input variable. Termination occurs when
 *        both the actual and predicted relative reductions in the sum
 *        of squares are at most ftol. Therefore, ftol measures the
 *        relative error desired in the sum of squares.
 *
 *      xtol is a nonnegative input variable. Termination occurs when
 *        the relative error between two consecutive iterates is at
 *        most xtol. Therefore, xtol measures the relative error desired
 *        in the approximate solution.
 *
 *      gtol is a nonnegative input variable. Termination occurs when
 *        the cosine of the angle between fvec and any column of the
 *        jacobian is at most gtol in absolute value. Therefore, gtol
 *        measures the orthogonality desired between the function vector
 *        and the columns of the jacobian.
 *
 *      maxfev is a positive integer input variable. Termination
 *        occurs when the number of calls to lm_fcn is at least
 *        maxfev by the end of an iteration.
 *
 *      epsfcn is an input variable used in choosing a step length for
 *        the forward-difference approximation. The relative errors in
 *        the functions are assumed to be of the order of epsfcn.
 *
 *      diag is an array of length n. If mode = 1 (see below), diag is
 *        internally set. If mode = 2, diag must contain positive entries
 *        that serve as multiplicative scale factors for the variables.
 *
 *      mode is an integer input variable. If mode = 1, the
 *        variables will be scaled internally. If mode = 2,
 *        the scaling is specified by the input diag.
 *
 *      factor is a positive input variable used in determining the
 *        initial step bound. This bound is set to the product of
 *        factor and the euclidean norm of diag*x if nonzero, or else
 *        to factor itself. In most cases factor should lie in the
 *        interval (0.1,100.0). Generally, the value 100.0 is recommended.
 *
 *      info is an integer OUTPUT variable that indicates the termination
 *        status of lm_lmdif as follows:
 *
 *        info < 0  termination requested by user-supplied routine *evaluate;
 *
 *        info = 0  fnorm almost vanishing;
 *
 *        info = 1  both actual and predicted relative reductions
 *                  in the sum of squares are at most ftol;
 *
 *        info = 2  relative error between two consecutive iterates
 *                  is at most xtol;
 *
 *        info = 3  conditions for info = 1 and info = 2 both hold;
 *
 *        info = 4  the cosine of the angle between fvec and any
 *                  column of the jacobian is at most gtol in
 *                  absolute value;
 *
 *        info = 5  number of calls to lm_fcn has reached or
 *                  exceeded maxfev;
 *
 *        info = 6  ftol is too small: no further reduction in
 *                  the sum of squares is possible;
 *
 *        info = 7  xtol is too small: no further improvement in
 *                  the approximate solution x is possible;
 *
 *        info = 8  gtol is too small: fvec is orthogonal to the
 *                  columns of the jacobian to machine precision;
 *
 *        info =10  improper input parameters;
 *
 *      nfev is an OUTPUT variable set to the number of calls to the
 *        user-supplied routine *evaluate.
 *
 *      fjac is an OUTPUT m by n array. The upper n by n submatrix
 *        of fjac contains an upper triangular matrix r with
 *        diagonal elements of nonincreasing magnitude such that
 *
 *              pT*(jacT*jac)*p = rT*r
 *
 *              (NOTE: T stands for matrix transposition),
 *
 *        where p is a permutation matrix and jac is the final
 *        calculated jacobian. Column j of p is column ipvt(j)
 *        (see below) of the identity matrix. The lower trapezoidal
 *        part of fjac contains information generated during
 *        the computation of r.
 *
 *      ipvt is an integer OUTPUT array of length n. It defines a
 *        permutation matrix p such that jac*p = q*r, where jac is
 *        the final calculated jacobian, q is orthogonal (not stored),
 *        and r is upper triangular with diagonal elements of
 *        nonincreasing magnitude. Column j of p is column ipvt(j)
 *        of the identity matrix.
 *
 *      qtf is an OUTPUT array of length n which contains
 *        the first n elements of the vector (q transpose)*fvec.
 *
 *      wa1, wa2, and wa3 are work arrays of length n.
 *
 *      wa4 is a work array of length m, used among others to hold
 *        residuals from evaluate.
 *
 *      evaluate points to the subroutine which calculates the
 *        m nonlinear functions. Implementations should be written as follows:
 *
 *        void evaluate( double* par, int m_dat, void *data,
 *                       double* fvec, int *info )
 *        {
 *           // for ( i=0; i<m_dat; ++i )
 *           //     calculate fvec[i] for given parameters par;
 *           // to stop the minimization, 
 *           //     set *info to a negative integer.
 *        }
 *
 *      printout points to the subroutine which informs about fit progress.
 *        Call with printout=0 if no printout is desired.
 *        Call with printout=lm_printout_std to use the default implementation.
 *
 *      printflags is passed to printout.
 *
 *      data is an input pointer to an arbitrary structure that is passed to
 *        evaluate. Typically, it contains experimental data to be fitted.
 *
 */
    int i, iter, j;
    double actred, delta, dirder, eps, fnorm, fnorm1, gnorm, par, pnorm,
        prered, ratio, step, sum, temp, temp1, temp2, temp3, xnorm;
    static double p1 = 0.1;
    static double p0001 = 1.0e-4;

    *nfev = 0;                  /* function evaluation counter */
    iter = 0;                   /* outer loop counter */
    par = 0;                    /* levenberg-marquardt parameter */
    delta = 0;   /* to prevent a warning (initialization within if-clause) */
    xnorm = 0;   /* ditto */
    temp = MAX(epsfcn, LM_MACHEP);
    eps = sqrt(temp); /* for calculating the Jacobian by forward differences */

/*** lmdif: check input parameters for errors. ***/

    if ((n <= 0) || (m < n) || (ftol < 0.)
        || (xtol < 0.) || (gtol < 0.) || (maxfev <= 0) || (factor <= 0.)) {
        *info = 10;             // invalid parameter
        return;
    }
    if (mode == 2) {            /* scaling by diag[] */
        for (j = 0; j < n; j++) {       /* check for nonpositive elements */
            if (diag[j] <= 0.0) {
                *info = 10;     // invalid parameter
                return;
            }
        }
    }
#ifdef LMFIT_DEBUG_MESSAGES
    printf("lmdif\n");
#endif

/*** lmdif: evaluate function at starting point and calculate norm. ***/

    *info = 0;
    (*evaluate) (x, m, data, fvec, info);
    ++(*nfev);
    if( printout )
        (*printout) (n, x, m, data, fvec, printflags, 0, 0, *nfev);
    if (*info < 0)
        return;
    fnorm = lm_enorm(m, fvec);
    if( fnorm <= LM_DWARF ){
        *info = 0;
        return;
    }

/*** lmdif: the outer loop. ***/

    do {
#ifdef LMFIT_DEBUG_MESSAGES
        printf("lmdif/ outer loop iter=%d nfev=%d fnorm=%.10e\n",
               iter, *nfev, fnorm);
#endif

/*** outer: calculate the Jacobian. ***/

        for (j = 0; j < n; j++) {
            temp = x[j];
            step = MAX(eps*eps, eps * fabs(temp));
            x[j] = temp + step; /* replace temporarily */
            *info = 0;
            (*evaluate) (x, m, data, wa4, info);
            ++(*nfev);
            if( printout )
                (*printout) (n, x, m, data, wa4, printflags, 1, iter, *nfev);
            if (*info < 0)
                return; /* user requested break */
            for (i = 0; i < m; i++)
                fjac[j*m+i] = (wa4[i] - fvec[i]) / step;
            x[j] = temp; /* restore */
        }
#ifdef LMFIT_DEBUG_MATRIX
        /* print the entire matrix */
        for (i = 0; i < m; i++) {
            for (j = 0; j < n; j++)
                printf("%.5e ", fjac[j*m+i]);
            printf("\n");
        }
#endif

/*** outer: compute the qr factorization of the Jacobian. ***/

        lm_qrfac(m, n, fjac, 1, ipvt, wa1, wa2, wa3);
        /* return values are ipvt, wa1=rdiag, wa2=acnorm */

        if (!iter) { 
            /* first iteration only */
            if (mode != 2) {
                /* diag := norms of the columns of the initial Jacobian */
                for (j = 0; j < n; j++) {
                    diag[j] = wa2[j];
                    if (wa2[j] == 0.)
                        diag[j] = 1.;
                }
            }
            /* use diag to scale x, then calculate the norm */
            for (j = 0; j < n; j++)
                wa3[j] = diag[j] * x[j];
            xnorm = lm_enorm(n, wa3);
            /* initialize the step bound delta. */
            delta = factor * xnorm;
            if (delta == 0.)
                delta = factor;
        } else {
            if (mode != 2) {
                for (j = 0; j < n; j++)
                    diag[j] = MAX( diag[j], wa2[j] );
            }
        }

/*** outer: form (q transpose)*fvec and store first n components in qtf. ***/

        for (i = 0; i < m; i++)
            wa4[i] = fvec[i];

        for (j = 0; j < n; j++) {
            temp3 = fjac[j*m+j];
            if (temp3 != 0.) {
                sum = 0;
                for (i = j; i < m; i++)
                    sum += fjac[j*m+i] * wa4[i];
                temp = -sum / temp3;
                for (i = j; i < m; i++)
                    wa4[i] += fjac[j*m+i] * temp;
            }
            fjac[j*m+j] = wa1[j];
            qtf[j] = wa4[j];
        }

/*** outer: compute norm of scaled gradient and test for convergence. ***/

        gnorm = 0;
        for (j = 0; j < n; j++) {
            if (wa2[ipvt[j]] == 0)
                continue;
            sum = 0.;
            for (i = 0; i <= j; i++)
                sum += fjac[j*m+i] * qtf[i];
            gnorm = MAX( gnorm, fabs( sum / wa2[ipvt[j]] / fnorm ) );
        }

        if (gnorm <= gtol) {
            *info = 4;
            return;
        }

/*** the inner loop. ***/
        do {
#ifdef LMFIT_DEBUG_MESSAGES
            printf("lmdif/ inner loop iter=%d nfev=%d\n", iter, *nfev);
#endif

/*** inner: determine the levenberg-marquardt parameter. ***/

            lm_lmpar( n, fjac, m, ipvt, diag, qtf, delta, &par,
                      wa1, wa2, wa4, wa3 );
            /* used return values are fjac (partly), par, wa1=x, wa3=diag*x */

            for (j = 0; j < n; j++)
                wa2[j] = x[j] - wa1[j]; /* new parameter vector ? */

            pnorm = lm_enorm(n, wa3);

            /* at first call, adjust the initial step bound. */

            if (*nfev <= 1+n)
                delta = MIN(delta, pnorm);

/*** inner: evaluate the function at x + p and calculate its norm. ***/

            *info = 0;
            (*evaluate) (wa2, m, data, wa4, info);
            ++(*nfev);
            if( printout )
                (*printout) (n, wa2, m, data, wa4, printflags, 2, iter, *nfev);
            if (*info < 0)
                return; /* user requested break. */

            fnorm1 = lm_enorm(m, wa4);
#ifdef LMFIT_DEBUG_MESSAGES
            printf("lmdif/ pnorm %.10e  fnorm1 %.10e  fnorm %.10e"
                   " delta=%.10e par=%.10e\n",
                   pnorm, fnorm1, fnorm, delta, par);
#endif

/*** inner: compute the scaled actual reduction. ***/

            if (p1 * fnorm1 < fnorm)
                actred = 1 - SQR(fnorm1 / fnorm);
            else
                actred = -1;

/*** inner: compute the scaled predicted reduction and 
     the scaled directional derivative. ***/

            for (j = 0; j < n; j++) {
                wa3[j] = 0;
                for (i = 0; i <= j; i++)
                    wa3[i] -= fjac[j*m+i] * wa1[ipvt[j]];
            }
            temp1 = lm_enorm(n, wa3) / fnorm;
            temp2 = sqrt(par) * pnorm / fnorm;
            prered = SQR(temp1) + 2 * SQR(temp2);
            dirder = -(SQR(temp1) + SQR(temp2));

/*** inner: compute the ratio of the actual to the predicted reduction. ***/

            ratio = prered != 0 ? actred / prered : 0;
#ifdef LMFIT_DEBUG_MESSAGES
            printf("lmdif/ actred=%.10e prered=%.10e ratio=%.10e"
                   " sq(1)=%.10e sq(2)=%.10e dd=%.10e\n",
                   actred, prered, prered != 0 ? ratio : 0.,
                   SQR(temp1), SQR(temp2), dirder);
#endif

/*** inner: update the step bound. ***/

            if (ratio <= 0.25) {
                if (actred >= 0.)
                    temp = 0.5;
                else
                    temp = 0.5 * dirder / (dirder + 0.5 * actred);
                if (p1 * fnorm1 >= fnorm || temp < p1)
                    temp = p1;
                delta = temp * MIN(delta, pnorm / p1);
                par /= temp;
            } else if (par == 0. || ratio >= 0.75) {
                delta = pnorm / 0.5;
                par *= 0.5;
            }

/*** inner: test for successful iteration. ***/

            if (ratio >= p0001) {
                /* yes, success: update x, fvec, and their norms. */
                for (j = 0; j < n; j++) {
                    x[j] = wa2[j];
                    wa2[j] = diag[j] * x[j];
                }
                for (i = 0; i < m; i++)
                    fvec[i] = wa4[i];
                xnorm = lm_enorm(n, wa2);
                fnorm = fnorm1;
                iter++;
            }
#ifdef LMFIT_DEBUG_MESSAGES
            else {
                printf("ATTN: iteration considered unsuccessful\n");
            }
#endif

/*** inner: test for convergence. ***/

            if( fnorm<=LM_DWARF ){
                *info = 0;
                return;
            }

            *info = 0;
            if (fabs(actred) <= ftol && prered <= ftol && 0.5 * ratio <= 1)
                *info = 1;
            if (delta <= xtol * xnorm)
                *info += 2;
            if (*info != 0)
                return;

/*** inner: tests for termination and stringent tolerances. ***/

            if (*nfev >= maxfev){
                *info = 5;
                return;
            }
            if (fabs(actred) <= LM_MACHEP &&
                prered <= LM_MACHEP && 0.5 * ratio <= 1){
                *info = 6;
                return;
            }
            if (delta <= LM_MACHEP * xnorm){
                *info = 7;
                return;
            }
            if (gnorm <= LM_MACHEP){
                *info = 8;
                return;
            }

/*** inner: end of the loop. repeat if iteration unsuccessful. ***/

        } while (ratio < p0001);

/*** outer: end of the loop. ***/

    } while (1);

} /*** lm_lmdif. ***/
예제 #12
0
void lmmin( int n_par, double *par, int m_dat, const void *data, 
            void (*evaluate) (const double *par, int m_dat, const void *data,
                              double *fvec, int *info),
            const lm_control_struct *control, lm_status_struct *status,
            void (*printout) (int n_par, const double *par, int m_dat,
                              const void *data, const double *fvec,
                              int printflags, int iflag, int iter, int nfev) )
{

/*** allocate work space. ***/

    double *fvec, *diag, *fjac, *qtf, *wa1, *wa2, *wa3, *wa4;
    int *ipvt;

    int n = n_par;
    int m = m_dat;

    if ( (fvec = (double *) malloc(m * sizeof(double))) == NULL ||
	 (diag = (double *) malloc(n * sizeof(double))) == NULL ||
	 (qtf  = (double *) malloc(n * sizeof(double))) == NULL ||
	 (fjac = (double *) malloc(n*m*sizeof(double))) == NULL ||
	 (wa1  = (double *) malloc(n * sizeof(double))) == NULL ||
	 (wa2  = (double *) malloc(n * sizeof(double))) == NULL ||
	 (wa3  = (double *) malloc(n * sizeof(double))) == NULL ||
	 (wa4  = (double *) malloc(m * sizeof(double))) == NULL ||
	 (ipvt = (int *)    malloc(n * sizeof(int)   )) == NULL    ) {
	status->info = 9;
	return;
    }

    int j;
    if( ! control->scale_diag )
        for( j=0; j<n_par; ++j )
            diag[j] = 1;

/*** perform fit. ***/

    status->info = 0;

    /* this goes through the modified legacy interface: */
    lm_lmdif( m, n, par, fvec, control->ftol, control->xtol, control->gtol,
              control->maxcall * (n + 1), control->epsilon, diag,
              ( control->scale_diag ? 1 : 2 ),
              control->stepbound, &(status->info),
              &(status->nfev), fjac, ipvt, qtf, wa1, wa2, wa3, wa4,
              evaluate, printout, control->printflags, data );

    if ( printout )
        (*printout)( n, par, m, data, fvec,
                     control->printflags, -1, 0, status->nfev );
    status->fnorm = lm_enorm(m, fvec);
    if ( status->info < 0 )
	status->info = 11;

/*** clean up. ***/

    free(fvec);
    free(diag);
    free(qtf);
    free(fjac);
    free(wa1);
    free(wa2);
    free(wa3);
    free(wa4);
    free(ipvt);
} /*** lm_minimize. ***/
예제 #13
0
void lmmin(
    const int n, double *const x, const int m, const double* y,
    const void *const data,
    void (*const evaluate)(
        const double *const par, const int m_dat, const void *const data,
        double *const fvec, int *const userbreak),
    const lm_control_struct *const C, lm_status_struct *const S)
{
    int j, i;
    double actred, dirder, fnorm, fnorm1, gnorm, pnorm,
        prered, ratio, step, sum, temp, temp1, temp2, temp3;
    static double p1 = 0.1, p0001 = 1.0e-4;

    int maxfev = C->patience * (n+1);

    int    inner_success; /* flag for loop control */
    double lmpar = 0;     /* Levenberg-Marquardt parameter */
    double delta = 0;
    double xnorm = 0;
    double eps = sqrt(MAX(C->epsilon, LM_MACHEP)); /* for forward differences */

    int nout = C->n_maxpri==-1 ? n : MIN(C->n_maxpri, n);

    /* The workaround msgfile=NULL is needed for default initialization */
    FILE* msgfile = C->msgfile ? C->msgfile : stdout;

    /* Default status info; must be set ahead of first return statements */
    S->outcome = 0;      /* status code */
    S->userbreak = 0;
    S->nfev = 0;      /* function evaluation counter */

/***  Check input parameters for errors.  ***/

    if ( n < 0 ) {
        fprintf(stderr, "lmmin: invalid number of parameters %i\n", n);
        S->outcome = 10; /* invalid parameter */
        return;
    }
    if (m < n) {
        fprintf(stderr, "lmmin: number of data points (%i) "
                "smaller than number of parameters (%i)\n", m, n);
        S->outcome = 10;
        return;
    }
    if (C->ftol < 0 || C->xtol < 0 || C->gtol < 0) {
        fprintf(stderr,
                "lmmin: negative tolerance (at least one of %g %g %g)\n",
                C->ftol, C->xtol, C->gtol);
        S->outcome = 10;
        return;
    }
    if (maxfev <= 0) {
        fprintf(stderr, "lmmin: nonpositive function evaluations limit %i\n",
                maxfev);
        S->outcome = 10;
        return;
    }
    if (C->stepbound <= 0) {
        fprintf(stderr, "lmmin: nonpositive stepbound %g\n", C->stepbound);
        S->outcome = 10;
        return;
    }
    if (C->scale_diag != 0 && C->scale_diag != 1) {
        fprintf(stderr, "lmmin: logical variable scale_diag=%i, "
                "should be 0 or 1\n", C->scale_diag);
        S->outcome = 10;
        return;
    }

/***  Allocate work space.  ***/

    /* Allocate total workspace with just one system call */
    char *ws;
    if ( ( ws = static_cast<char *>(malloc(
               (2*m+5*n+m*n)*sizeof(double) + n*sizeof(int)) ) ) == NULL ) {
        S->outcome = 9;
        return;
    }

    /* Assign workspace segments. */
    char *pws = ws;
    double *fvec = (double*) pws; pws += m * sizeof(double)/sizeof(char);
    double *diag = (double*) pws; pws += n * sizeof(double)/sizeof(char);
    double *qtf  = (double*) pws; pws += n * sizeof(double)/sizeof(char);
    double *fjac = (double*) pws; pws += n*m*sizeof(double)/sizeof(char);
    double *wa1  = (double*) pws; pws += n * sizeof(double)/sizeof(char);
    double *wa2  = (double*) pws; pws += n * sizeof(double)/sizeof(char);
    double *wa3  = (double*) pws; pws += n * sizeof(double)/sizeof(char);
    double *wf   = (double*) pws; pws += m * sizeof(double)/sizeof(char);
    int    *ipvt = (int*)    pws; /*pws += n * sizeof(int)   /sizeof(char);*/

    /* Initialize diag */ // TODO: check whether this is still needed
    if (!C->scale_diag) {
        for (j = 0; j < n; j++)
            diag[j] = 1.;
    }

/***  Evaluate function at starting point and calculate norm.  ***/

    if( C->verbosity&1 )
        fprintf(msgfile, "lmmin start (ftol=%g gtol=%g xtol=%g)\n",
                C->ftol, C->gtol, C->xtol);
    if( C->verbosity&2 )
        lm_print_pars(nout, x, msgfile);
    (*evaluate)(x, m, data, fvec, &(S->userbreak));
    if( C->verbosity&8 )
    {
        if (y) {
            for( i=0; i<m; ++i )
                fprintf(msgfile, "    i, f, y-f: %4i %18.8g %18.8g\n",
                        i, fvec[i], y[i]-fvec[i]);
        } else {
            for( i=0; i<m; ++i )
                fprintf(msgfile, "    i, f: %4i %18.8g\n", i, fvec[i]);
        }
    }
    S->nfev = 1;
    if ( S->userbreak )
        goto terminate;
    if ( n == 0 ) {
        S->outcome = 13; /* won't fit */
        goto terminate;
    }
    fnorm = lm_fnorm(m, fvec, y);
    if( C->verbosity&2 )
        fprintf(msgfile, "  fnorm = %24.16g\n", fnorm);
    if( !isfinite(fnorm) ){
        if( C->verbosity )
            fprintf(msgfile, "nan case 1\n");
        S->outcome = 12; /* nan */
        goto terminate;
    } else if( fnorm <= LM_DWARF ){
        S->outcome = 0; /* sum of squares almost zero, nothing to do */
        goto terminate;
    }

/***  The outer loop: compute gradient, then descend.  ***/

    for( int outer=0; ; ++outer ) {

/***  [outer]  Calculate the Jacobian.  ***/

        for (j = 0; j < n; j++) {
            temp = x[j];
            step = MAX(eps*eps, eps * fabs(temp));
            x[j] += step; /* replace temporarily */
            (*evaluate)(x, m, data, wf, &(S->userbreak));
            ++(S->nfev);
            if ( S->userbreak )
                goto terminate;
            for (i = 0; i < m; i++)
                fjac[j*m+i] = (wf[i] - fvec[i]) / step;
            x[j] = temp; /* restore */
        }
        if ( C->verbosity&16 ) {
            /* print the entire matrix */
            printf("Jacobian\n");
            for (i = 0; i < m; i++) {
                printf("  ");
                for (j = 0; j < n; j++)
                    printf("%.5e ", fjac[j*m+i]);
                printf("\n");
            }
        }

/***  [outer]  Compute the QR factorization of the Jacobian.  ***/

/*      fjac is an m by n array. The upper n by n submatrix of fjac
 *        is made to contain an upper triangular matrix R with diagonal
 *        elements of nonincreasing magnitude such that
 *
 *              P^T*(J^T*J)*P = R^T*R
 *
 *              (NOTE: ^T stands for matrix transposition),
 *
 *        where P is a permutation matrix and J is the final calculated
 *        Jacobian. Column j of P is column ipvt(j) of the identity matrix.
 *        The lower trapezoidal part of fjac contains information generated
 *        during the computation of R.
 *
 *      ipvt is an integer array of length n. It defines a permutation
 *        matrix P such that jac*P = Q*R, where jac is the final calculated
 *        Jacobian, Q is orthogonal (not stored), and R is upper triangular
 *        with diagonal elements of nonincreasing magnitude. Column j of P
 *        is column ipvt(j) of the identity matrix.
 */

        lm_qrfac(m, n, fjac, ipvt, wa1, wa2, wa3);
        /* return values are ipvt, wa1=rdiag, wa2=acnorm */

/***  [outer]  Form Q^T * fvec, and store first n components in qtf.  ***/

        if (y)
            for (i = 0; i < m; i++)
                wf[i] = fvec[i] - y[i];
        else
            for (i = 0; i < m; i++)
                wf[i] = fvec[i];

        for (j = 0; j < n; j++) {
            temp3 = fjac[j*m+j];
            if (temp3 != 0) {
                sum = 0;
                for (i = j; i < m; i++)
                    sum += fjac[j*m+i] * wf[i];
                temp = -sum / temp3;
                for (i = j; i < m; i++)
                    wf[i] += fjac[j*m+i] * temp;
            }
            fjac[j*m+j] = wa1[j];
            qtf[j] = wf[j];
        }

/***  [outer]  Compute norm of scaled gradient and detect degeneracy.  ***/

        gnorm = 0;
        for (j = 0; j < n; j++) {
            if (wa2[ipvt[j]] == 0)
                continue;
            sum = 0;
            for (i = 0; i <= j; i++)
                sum += fjac[j*m+i] * qtf[i];
            gnorm = MAX(gnorm, fabs( sum / wa2[ipvt[j]] / fnorm ));
        }

        if (gnorm <= C->gtol) {
            S->outcome = 4;
            goto terminate;
        }

/***  [outer]  Initialize / update diag and delta. ***/

        if ( !outer ) {
            /* first iteration only */
            if (C->scale_diag) {
                /* diag := norms of the columns of the initial Jacobian */
                for (j = 0; j < n; j++)
                    diag[j] = wa2[j] ? wa2[j] : 1;
                /* xnorm := || D x || */
                for (j = 0; j < n; j++)
                    wa3[j] = diag[j] * x[j];
                xnorm = lm_enorm(n, wa3);
            } else {
                xnorm = lm_enorm(n, x);
            }
            if( !isfinite(xnorm) ){
                if( C->verbosity )
                    fprintf(msgfile, "nan case 2\n");
                S->outcome = 12; /* nan */
                goto terminate;
            }
            /* initialize the step bound delta. */
            if ( xnorm )
                delta = C->stepbound * xnorm;
            else
                delta = C->stepbound;
            /* only now print the header for the loop table */
            if( C->verbosity&2 ) {
                fprintf(msgfile, " #o #i     lmpar    prered  actred"
                        "        ratio    dirder      delta"
                        "      pnorm                 fnorm");
                for (i = 0; i < nout; ++i)
                    fprintf(msgfile, "               p%i", i);
                fprintf(msgfile, "\n");
            }
        } else {
            if (C->scale_diag) {
                for (j = 0; j < n; j++)
                    diag[j] = MAX( diag[j], wa2[j] );
            }
        }

/***  The inner loop. ***/
        int inner = 0;
        do {

/***  [inner]  Determine the Levenberg-Marquardt parameter.  ***/

            lm_lmpar(n, fjac, m, ipvt, diag, qtf, delta, &lmpar,
                     wa1, wa2, wf, wa3);
            /* used return values are fjac (partly), lmpar, wa1=x, wa3=diag*x */

            /* predict scaled reduction */
            pnorm = lm_enorm(n, wa3);
            if( !isfinite(pnorm) ){
                if( C->verbosity )
                    fprintf(msgfile, "nan case 3\n");
                S->outcome = 12; /* nan */
                goto terminate;
            }
            temp2 = lmpar * SQR( pnorm / fnorm );
            for (j = 0; j < n; j++) {
                wa3[j] = 0;
                for (i = 0; i <= j; i++)
                    wa3[i] -= fjac[j*m+i] * wa1[ipvt[j]];
            }
            temp1 = SQR( lm_enorm(n, wa3) / fnorm );
            if( !isfinite(temp1) ){
                if( C->verbosity )
                    fprintf(msgfile, "nan case 4\n");
                S->outcome = 12; /* nan */
                goto terminate;
            }
            prered = temp1 + 2 * temp2;
            dirder = -temp1 + temp2; /* scaled directional derivative */

            /* at first call, adjust the initial step bound. */
            if ( !outer && !inner && pnorm < delta )
                delta = pnorm;

/***  [inner]  Evaluate the function at x + p.  ***/

            for (j = 0; j < n; j++)
                wa2[j] = x[j] - wa1[j];

            (*evaluate)( wa2, m, data, wf, &(S->userbreak) );
            ++(S->nfev);
            if ( S->userbreak )
                goto terminate;
            fnorm1 = lm_fnorm(m, wf, y);
            // exceptionally, for this norm we do not test for infinity
            // because we can deal with it without terminating.

/***  [inner]  Evaluate the scaled reduction.  ***/

            /* actual scaled reduction (supports even the case fnorm1=infty) */
	    if (p1 * fnorm1 < fnorm)
		actred = 1 - SQR(fnorm1 / fnorm);
	    else
		actred = -1;

            /* ratio of actual to predicted reduction */
            ratio = prered ? actred/prered : 0;

            if( C->verbosity&32 ) {
                if (y) {
                    for( i=0; i<m; ++i )
                        fprintf(msgfile, "    i, f, y-f: %4i %18.8g %18.8g\n",
                                i, fvec[i], y[i]-fvec[i]);
                } else {
                    for( i=0; i<m; ++i )
                        fprintf(msgfile, "    i, f, y-f: %4i %18.8g\n",
                                i, fvec[i]);
                }
            }
            if( C->verbosity&2 ) {
                printf("%3i %2i %9.2g %9.2g %9.2g %14.6g"
                       " %9.2g %10.3e %10.3e %21.15e",
                       outer, inner, lmpar, prered, actred, ratio,
                       dirder, delta, pnorm, fnorm1);
                for (i = 0; i < nout; ++i)
                    fprintf(msgfile, " %16.9g", wa2[i]);
                fprintf(msgfile, "\n");
            }

            /* update the step bound */
	    if (ratio <= 0.25) {
		if (actred >= 0)
		    temp = 0.5;
		else
		    temp = 0.5 * dirder / (dirder + 0.5 * actred);
		if (p1 * fnorm1 >= fnorm || temp < p1)
		    temp = p1;
		delta = temp * MIN(delta, pnorm / p1);
		lmpar /= temp;
	    } else if (lmpar == 0 || ratio >= 0.75) {
		delta = 2 * pnorm;
		lmpar *= 0.5;
	    }

/***  [inner]  On success, update solution, and test for convergence.  ***/

            inner_success = ratio >= p0001;
            if ( inner_success ) {

                /* update x, fvec, and their norms */
                if (C->scale_diag) {
                    for (j = 0; j < n; j++) {
                        x[j] = wa2[j];
                        wa2[j] = diag[j] * x[j];
                    }
                } else {
                    for (j = 0; j < n; j++)
                        x[j] = wa2[j];
                }
                for (i = 0; i < m; i++)
                    fvec[i] = wf[i];
                xnorm = lm_enorm(n, wa2);
                if( !isfinite(xnorm) ){
                    if( C->verbosity )
                        fprintf(msgfile, "nan case 6\n");
                    S->outcome = 12; /* nan */
                    goto terminate;
                }
                fnorm = fnorm1;
            }

            /* convergence tests */
            S->outcome = 0;
            if( fnorm<=LM_DWARF )
                goto terminate;  /* success: sum of squares almost zero */
            /* test two criteria (both may be fulfilled) */
            if (fabs(actred) <= C->ftol && prered <= C->ftol && ratio <= 2)
                S->outcome = 1;  /* success: x almost stable */
            if (delta <= C->xtol * xnorm)
                S->outcome += 2; /* success: sum of squares almost stable */
            if (S->outcome != 0) {
                goto terminate;
            }

/***  [inner]  Tests for termination and stringent tolerances.  ***/

            if ( S->nfev >= maxfev ){
                S->outcome = 5;
                goto terminate;
            }
            if ( fabs(actred) <= LM_MACHEP &&
                 prered <= LM_MACHEP && ratio <= 2 ){
                S->outcome = 6;
                goto terminate;
            }
            if ( delta <= LM_MACHEP*xnorm ){
                S->outcome = 7;
                goto terminate;
            }
            if ( gnorm <= LM_MACHEP ){
                S->outcome = 8;
                goto terminate;
            }

/***  [inner]  End of the loop. Repeat if iteration unsuccessful.  ***/

            ++inner;
        } while ( !inner_success );

/***  [outer]  End of the loop. ***/

    };

terminate:
    S->fnorm = lm_fnorm(m, fvec, y);
    if( C->verbosity&1 )
        fprintf(msgfile, "lmmin terminates with outcome %i\n", S->outcome);
    if( C->verbosity&2 )
        lm_print_pars(nout, x, msgfile);
    if( C->verbosity&8 ) {
        if (y) {
            for( i=0; i<m; ++i )
                fprintf(msgfile, "    i, f, y-f: %4i %18.8g %18.8g\n",
                        i, fvec[i], y[i]-fvec[i] );
        } else {
            for( i=0; i<m; ++i )
                fprintf(msgfile, "    i, f, y-f: %4i %18.8g\n", i, fvec[i]);
        }
    }
    if( C->verbosity&2 )
        fprintf(msgfile, "  fnorm=%24.16g xnorm=%24.16g\n", S->fnorm, xnorm);
    if ( S->userbreak ) /* user-requested break */
        S->outcome = 11;

/***  Deallocate the workspace.  ***/
    free(ws);

} /*** lmmin. ***/
예제 #14
0
double lm_fnorm(const int n, const double *const x, const double *const y)
{
/*     This function calculates the Euclidean norm of an n-vector x-y.
 *
 *     The Euclidean norm is computed by accumulating the sum of
 *     squares in three different sums. The sums of squares for the
 *     small and large components are scaled so that no overflows
 *     occur. Non-destructive underflows are permitted. Underflows
 *     and overflows do not occur in the computation of the unscaled
 *     sum of squares for the intermediate components.
 *     The definitions of small, intermediate and large components
 *     depend on two constants, LM_SQRT_DWARF and LM_SQRT_GIANT. The main
 *     restrictions on these constants are that LM_SQRT_DWARF**2 not
 *     underflow and LM_SQRT_GIANT**2 not overflow.
 *
 *     Parameters:
 *
 *      n is a positive integer INPUT variable.
 *
 *      x, y are INPUT arrays of length n.
 */
    if (!y)
        return lm_enorm(n, x);
    int i;
    double agiant, s1, s2, s3, xabs, x1max, x3max, temp;

    s1 = 0;
    s2 = 0;
    s3 = 0;
    x1max = 0;
    x3max = 0;
    agiant = LM_SQRT_GIANT / n;

    /** sum squares. **/

    for (i = 0; i < n; i++) {
        xabs = fabs(x[i]-y[i]);
        if (xabs > LM_SQRT_DWARF) {
            if ( xabs < agiant ) {
                s2 += xabs * xabs;
            } else if ( xabs > x1max ) {
                temp = x1max / xabs;
                s1 = 1 + s1 * SQR(temp);
                x1max = xabs;
            } else {
                temp = xabs / x1max;
                s1 += SQR(temp);
            }
        } else if ( xabs > x3max ) {
            temp = x3max / xabs;
            s3 = 1 + s3 * SQR(temp);
            x3max = xabs;
        } else if (xabs != 0) {
            temp = xabs / x3max;
            s3 += SQR(temp);
        }
    }

    /** calculation of norm. **/

    if (s1 != 0)
        return x1max * sqrt(s1 + (s2 / x1max) / x1max);
    else if (s2 != 0)
        if (s2 >= x3max)
            return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3)));
        else
            return sqrt(x3max * ((s2 / x3max) + (x3max * s3)));
    else
        return x3max * sqrt(s3);

} /*** lm_fnorm. ***/