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); }
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. ***/
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. ***/
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. ***/