Example #1
0
    public static void  LevenbergMarquardtFit (LMFunction fcn, double[] xvec, double[] fvec, 
      double ftol, double xtol, double gtol,
      int maxfev, double epsfcn, double[] diag, int mode, 
      double factor, int nprint, ref int info, ref int nfev, double[] fjac, 
      int ldfjac, int[] ipvt,
      double[] qtf, double[] wa1, double[] wa2, double[] wa3, double[] wa4)
      //
      // The purpose of LevenbergMarquardtFit 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 which calculates the functions. The Jacobian is 
      // then calculated by a forward-difference approximation. 
      //
      // This is the most general interface to the Levenberg-Marquardt algorithm
      // which gives you full control over the minimization process and auxilliary
      // storage allocation. Use one of the simpler interfaces above, if you don't 
      // all arguments.
      //
      // Arguments:
      //
      //       fcn is the name of the user-supplied subroutine which 
      //         calculates the functions. fcn should be written as follows: 
      //
      //         void fcn (int m, int n, double* xvec, double* fvec, int& iflag)
      //         {
      //            ...
      //            calculate the functions at xvec[0..n-1] and 
      //            return this vector in fvec[0..m-1]. 
      //            ...
      //         }
      //         
      //         The value of iflag should not be changed by fcn unless 
      //         the user wants to terminate execution of LevenbergMarquardtFit. 
      //         In this case set iflag to a negative integer. 
      //         
      //       xvec 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 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 (0.1,100.0). 100.0 is a generally recommended value. 
      //
      //       nprint is an integer input variable that enables controlled 
      //         printing of iterates if it is positive. In this case, 
      //         fcn is called with iflag = 0 at the beginning of the first 
      //         iteration and every nprint iterations thereafter and 
      //         immediately prior to return, with x and fvec available 
      //         for printing. if nprint is not positive, no special calls 
      //         of fcn with iflag = 0 are made. 
      //
      //       info is an integer output variable. If the user has 
      //         terminated execution, info is set to the (negative) 
      //         value of iflag. see description of fcn. Otherwise, 
      //         info is set as follows:
      //
      //         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 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 integer output variable set to the number of 
      //         calls to fcn. 
      //
      //       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. 
      //
      //       ldfjac is a positive integer input variable not less than m 
      //         which specifies the leading dimension of the array fjac. 
      //
      //       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. 
      //
    {

      const double p1 = 0.1;
      const double p5 = 0.5;
      const double p25 = 0.25;
      const double p75 = 0.75;
      const double p0001 = 1e-4;
    
      int fjac_dim1, fjac_offset;

      int iter;
      double temp=0.0, temp1, temp2;
      int i, j, l, iflag;
      double delta=0; // LELLID!! TODO  there was no initialization of delta in the original code
      double ratio;
      double fnorm, gnorm;
      double pnorm, xnorm=0.0, fnorm1, actred, dirder, prered;
      double par, sum;

        
      // Parameter adjustments

      int m,n;
      m = fvec.Length;  // number of functions
      n = xvec.Length;  // number of variables

      double[] x = xvec;
      double[] f = fvec;
      //    x = &xvec[ xvec.Lo()-1 ];   // 1-offset solution variables vector
      //    f = &fvec[ fvec.Lo()-1 ];   // 1-offset functions vector

      //--wa4;
      //--wa3;
      //--wa2;
      //--wa1;
      //--qtf;
      //--ipvt;
      fjac_dim1 = ldfjac;
      fjac_offset = fjac_dim1 + 1;
      //fjac -= fjac_offset;
      //--diag;

      info =  iflag =  nfev = 0;

      // check the input parameters for errors
      if (n <= 0 || m < n || ldfjac < m || ftol < 0.0 || xtol < 0.0 ||
        gtol < 0.0 || maxfev <= 0 || factor <= 0.0) 
        goto L300;
   
      if (mode != 2) goto L20;
    
      for (j = 0; j < n; j++) // LELLID!! 
        if (diag[j] <= 0.0) goto L300;
    
      L20:

        // evaluate the function at the starting point and calculate its norm
        iflag = 1;
      fcn(m, n, x, f, ref iflag);

      nfev = 1;
      if (iflag < 0) goto L300;

      fnorm = enorm(m, f);

      // initialize levenberg-marquardt parameter and iteration counter
      par = 0.0;
      iter = 1;

      // beginning of the outer loop.

      L30:

        // calculate the Jacobian matrix.
        iflag = 2;
      fdjac2(fcn, m, n, x, f, fjac, ldfjac, ref iflag,
        epsfcn, wa4);

      nfev += n;
      if (iflag < 0) goto L300;

      // if requested, call fcn to enable printing of iterates
      if (nprint <= 0) goto L40;

      iflag = 0;
      if ((iter - 1) % nprint == 0) 
        fcn(m, n, x, f, ref iflag);
    
      if (iflag < 0) goto L300;
    
      L40:

        // compute the qr factorization of the Jacobian.
        qrfac(m, n, fjac, ldfjac, true, ipvt, n, wa1,
          wa2, wa3);

      // on the first iteration and if mode is 1, scale according 
      // to the norms of the columns of the initial Jacobian

      if (iter != 1) goto L80;
      if (mode == 2) goto L60;

      for (j = 0; j < n; ++j) 
      { // LELLID!!
        diag[j] = wa2[j];
        if (wa2[j] == 0.0) diag[j] = 1.0;
      }

      L60:

        // on the first iteration, calculate the norm of the scaled x
        // and initialize the step bound delta

        for (j = 0; j < n; ++j) // LELLID
          wa3[j] = diag[j] * x[j];
    
      xnorm = enorm(n, wa3);
      delta = factor * xnorm;
      if (delta == 0.0) delta = factor;

      L80:

        // form (q transpose)*f and store the first n components in qtf
        for (i = 0; i < m; ++i) wa4[i] = f[i]; // LELLID!!
   
      for (j = 0; j < n; ++j) 
      { // LELLID!!
        if (fjac[j + j * fjac_dim1] != 0.0) 
        {
          sum = 0.0;
          for (i = j; i < m; ++i) // LELLID!! 
            sum += fjac[i + j * fjac_dim1] * wa4[i];
          temp = -sum / fjac[j + j * fjac_dim1];
          for (i = j; i < m; ++i) // LELLID!! 
            wa4[i] += fjac[i + j * fjac_dim1] * temp;
        }
        fjac[j + j * fjac_dim1] = wa1[j];
        qtf[j] = wa4[j];
      }

      // compute the norm of the scaled gradient
      gnorm = 0.0;
      if (fnorm != 0.0)
        for (j = 0; j < n; ++j) 
        { // LELLID!!
          l = ipvt[j];
          if (wa2[l] != 0.0) 
          { 
            sum = 0.0;
            for (i = 0; i <= j; ++i) // LELLID!!
              sum += fjac[i + j * fjac_dim1] * (qtf[i] / fnorm);
            gnorm =  Math.Max( gnorm, Math.Abs(sum/wa2[l]) );
          }
        }
    
      // test for convergence of the gradient norm
      if (gnorm <= gtol) info = 4;

      if (info != 0) goto L300;

      // rescale if necessary
      if (mode != 2)
        for (j = 0; j < n; ++j) // LELLID!!
          diag[j] = Math.Max( diag[j], wa2[j] );
    
      // beginning of the inner loop
    
      L200:

        // determine the levenberg-marquardt parameter
        lmpar(n, fjac, ldfjac, ipvt, diag, qtf, delta,
          ref par, wa1, wa2, wa3, wa4);
    
      // store the direction p and x + p. calculate the norm of p

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

      // on the first iteration, adjust the initial step bound
      if (iter == 1) delta = Math.Min(delta, pnorm);

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

      iflag = 1;
      fcn(m, n, wa2, wa4, ref iflag);
      ++nfev;
      if (iflag < 0) goto L300;
      fnorm1 = enorm(m, wa4);

      // compute the scaled actual reduction

      actred = -1.0;
      if (p1 * fnorm1 < fnorm) 
        actred = 1.0 - sqr(fnorm1 / fnorm);

      // compute the scaled predicted reduction and
      // the scaled directional derivative

      for (j = 0; j < n; ++j) 
      { // Lellid!!
        wa3[j] = 0.0;
        l = ipvt[j];
        temp = wa1[l];
        for (i = 0; i <= j; ++i) 
        { // LELLID!!
          wa3[i] += fjac[i + j * fjac_dim1] * temp;
        }
      }

      temp1 = enorm(n, wa3) / fnorm;
      temp2 = Math.Sqrt(par) * pnorm / fnorm;
      prered = sqr(temp1) + sqr(temp2) / p5;
      dirder = -(sqr(temp1) + sqr(temp2));

      // compute the ratio of the actual to the predicted reduction
      ratio = 0.0;
      if (prered != 0.0) ratio = actred / prered;

      // update the step bound
      if (ratio > p25) goto L240;

      if (actred >= 0.0) temp = p5;
      if (actred < 0.0)   temp = p5 * dirder / (dirder + p5 * actred);
      if (p1 * fnorm1 >= fnorm || temp < p1) temp = p1;

      delta = temp * Math.Min(delta, pnorm / p1);
      par /= temp;
      goto L260;

      L240:
        if (par != 0.0 && ratio < p75) goto L260;
      delta = pnorm / p5;
      par = p5 * par;

      L260:

        // test for successful iteration
        if (ratio < p0001) goto L290;

      // successful iteration. update x, f, and their norms
      for (j = 0; j < n; ++j) 
      { // LELLID
        x[j] = wa2[j];
        wa2[j] = diag[j] * x[j];
      }

      for (i = 0; i < m; ++i) 
      { // LELLID!!
        f[i] = wa4[i];
      }
      xnorm = enorm(n, wa2);
      fnorm = fnorm1;
      ++iter;

      L290:

        // tests for convergence
        if (Math.Abs(actred) <= ftol && prered <= ftol 
          && p5 * ratio <= 1.0) info = 1;
   
      if (delta <= xtol * xnorm) info = 2;
   
      if (Math.Abs(actred) <= ftol && prered <= ftol 
        && p5 * ratio <= 1.0 && info == 2) info = 3;
   
      if (info != 0) goto L300;
   
      // tests for termination and stringent tolerances

      if (nfev >= maxfev) info = 5;
   
      if (Math.Abs(actred) <= DBL_EPSILON && prered <= DBL_EPSILON 
        && p5 * ratio <= 1.0) info = 6;
   
      if (delta <= DBL_EPSILON * xnorm) info = 7;
   
      if (gnorm <= DBL_EPSILON) info = 8;
   
      if (info != 0) goto L300;
   
      // end of the inner loop. repeat if iteration unsuccessful
      if (ratio < p0001) goto L200;

      // end of the outer loop
      goto L30;
    
      L300:

        // termination, either normal or user imposed
        if (iflag < 0) info = iflag;
      iflag = 0;
      if (nprint > 0) fcn(m, n, x, f, ref iflag);
    }
Example #2
0
    /// <summary>
    /// The purpose of LevenbergMarquardtFit is to minimize the sum of the 
    /// squares of m nonlinear functions in n variables by a modification of the 
    /// Levenberg-Marquardt algorithm. This is done by using the more 
    /// general least-squares solver below. The user must provide a 
    /// subroutine which calculates the functions. The Jacobian is 
    /// then calculated by a forward-difference approximation. 
    /// </summary>
    /// <param name="fcn">The user supplied function which provides the values to minimize.</param>
    /// <param name="xvec">
    /// Array of length n containing the parameter vector. On input x must contain 
    /// an initial estimate of the solution vector. On output x 
    /// contains the final estimate of the solution vector. 
    /// </param>
    /// <param name="fvec">Output array of length m which contains the functions evaluated at the output x. </param>
    /// <param name="tol">
    /// Nonnegative input variable. Termination occurs 
    /// when the algorithm estimates either that the relative 
    /// error in the sum of squares is at most tol or that 
    /// the relative error between x and the solution is at 
    /// most tol. 
    /// </param>
    /// <param name="info">
    /// Info is an integer output variable. If the user has 
    /// terminated execution, info is set to the (negative) 
    /// value of iflag. See description of fcn. Otherwise, 
    /// info is set as follows: 
    ///
    ///         info = 0  improper input parameters. 
    ///
    ///         info = 1  algorithm estimates that the relative error 
    ///                   in the sum of squares is at most tol. 
    ///
    ///         info = 2  algorithm estimates that the relative error 
    ///                   between x and the solution is at most tol. 
    ///
    ///         info = 3  conditions for info = 1 and info = 2 both hold. 
    ///
    ///         info = 4  fvec is orthogonal to the columns of the 
    ///                   Jacobian to machine precision. 
    ///
    ///         info = 5  number of calls to fcn has reached or 
    ///                   exceeded 200*(n+1). 
    ///
    ///         info = 6  tol is too small. No further reduction in 
    ///                   the sum of squares is possible. 
    ///
    ///         info = 7  tol is too small. No further improvement in 
    ///                   the approximate solution x is possible. 
    /// </param>
    /// <param name="iwa">Integer working array of length n.</param>
    /// <param name="diag"></param>
    /// <param name="fjac"></param>
    /// <param name="ipvt"></param>
    /// <param name="qtf"></param>
    /// <param name="wa1"></param>
    /// <param name="wa2"></param>
    /// <param name="wa3"></param>
    /// <param name="wa4"></param>
    /// <remarks>
    /// This is the most easy-to-use interface with the smallest number of
    /// arguments. If you need more control over the minimization process and
    /// auxilliary storage allocation you should use one of the interfaces 
    /// described below.
    /// </remarks>
    public static void LevenbergMarquardtFit(
      LMFunction fcn,
      double[] xvec,
      double[] fvec, 
      double tol,
      ref int info,
      int[] iwa,
      double[] diag,
      double[] fjac, 
      int[] ipvt,
      double[] qtf, 
      double[] wa1, 
      double[] wa2,
      double[] wa3,
      double[] wa4)
      //
      //       iwa is an integer work array of length n. 
      //
      //       wa is a work array of length lwa. 
      //
      //       lwa is a positive integer input variable not less than 
      //         m*n+5*n+m. 
      //
      //
    {
      int mode, nfev, maxfev, nprint;
      double factor, ftol, gtol, xtol, epsfcn;
    
      // Parameter adjustments
      int m,n;
      m = fvec.Length;       // number of functions
      n = xvec.Length;       // number of variables

      // --wa;
      // --iwa;

      info = 0;
      nfev = 0;

      // check the input parameters for errors
      if (n <= 0 || m < n || tol < 0 ) return;

      factor = 100;
      maxfev = (n + 1) * 200;
      ftol = tol;
      xtol = tol;
      gtol = 0;
      epsfcn = 0;
      mode = 1;
      nprint = 0;

      LevenbergMarquardtFit(fcn, xvec, fvec, ftol, xtol, gtol, maxfev, epsfcn,
        diag, mode, factor, nprint, ref info, ref nfev, fjac, m,
        ipvt, qtf, wa1, wa2, wa3,
        wa4);
    
      if (info == 8) 
        info = 4;
    } 
Example #3
0
    /// <summary>
    /// This will compute the covariances at a given parameter set xvec.
    /// </summary>
    /// <param name="func"></param>
    /// <param name="xvec"></param>
    /// <param name="covar"></param>
    public static int ComputeCovariances(LMFunction fcn, double[] x, int n, int m, double[]covar, out double sumchisq)
    {
      int  info=0;
      

      double[] f = new double[n];
      double[] fjac = new double[n*m];
      double [] jactjac = new double[m*m];

      fcn(n,m,x,f, ref info);
      sumchisq=0;
      for(int i=0;i<n;++i)
        sumchisq += f[i]*f[i];

      // calculate the Jacobian matrix.
      int iflag = 2;
      int ldfjac = n;
      double epsfcn=0;
      double[] wa4 = new double[n];
      fdjac2(fcn, n, m, x, f, fjac, ldfjac, ref iflag, epsfcn, wa4);

      // compute jacT*jac
      for(int i=0;i<m;++i)
      {
        for(int j=0;j<m;++j)
        {
          double sum = 0;
          for(int k=0;k<n;++k)
          {
            sum += fjac[k+n*i]*fjac[k+n*j];
          }
          jactjac[j+i*m] = sum;
        }
      }


      return LEVMAR_COVAR(jactjac, covar, sumchisq, m, n);

    }
Example #4
0
    /// <summary>
    /// The purpose of LevenbergMarquardtFit is to minimize the sum of the 
    /// squares of m nonlinear functions in n variables by a modification of the 
    /// Levenberg-Marquardt algorithm. This is done by using the more 
    /// general least-squares solver below. The user must provide a 
    /// subroutine which calculates the functions. The Jacobian is 
    /// then calculated by a forward-difference approximation. 
    /// </summary>
    /// <param name="fcn">The user supplied function which provides the values to minimize.</param>
    /// <param name="xvec">
    /// Array of length n containing the parameter vector. On input x must contain 
    /// an initial estimate of the solution vector. On output x 
    /// contains the final estimate of the solution vector. 
    /// </param>
    /// <param name="fvec">Output array of length m which contains the functions evaluated at the output x. </param>
    /// <param name="tol">
    /// Nonnegative input variable. Termination occurs 
    /// when the algorithm estimates either that the relative 
    /// error in the sum of squares is at most tol or that 
    /// the relative error between x and the solution is at 
    /// most tol. 
    /// </param>
    /// <param name="info">
    /// Info is an integer output variable. If the user has 
    /// terminated execution, info is set to the (negative) 
    /// value of iflag. See description of fcn. Otherwise, 
    /// info is set as follows: 
    ///
    ///         info = 0  improper input parameters. 
    ///
    ///         info = 1  algorithm estimates that the relative error 
    ///                   in the sum of squares is at most tol. 
    ///
    ///         info = 2  algorithm estimates that the relative error 
    ///                   between x and the solution is at most tol. 
    ///
    ///         info = 3  conditions for info = 1 and info = 2 both hold. 
    ///
    ///         info = 4  fvec is orthogonal to the columns of the 
    ///                   Jacobian to machine precision. 
    ///
    ///         info = 5  number of calls to fcn has reached or 
    ///                   exceeded 200*(n+1). 
    ///
    ///         info = 6  tol is too small. No further reduction in 
    ///                   the sum of squares is possible. 
    ///
    ///         info = 7  tol is too small. No further improvement in 
    ///                   the approximate solution x is possible. 
    /// </param>
    /// <remarks>
    /// This is the most easy-to-use interface with the smallest number of
    /// arguments. If you need more control over the minimization process and
    /// auxilliary storage allocation you should use one of the interfaces 
    /// described below.
    /// </remarks>
    public static void LevenbergMarquardtFit(
      LMFunction fcn, 
      double[] xvec, 
      double[] fvec, 
      double tol, 
      ref int info)

    {
      int m,n;
      int[] iwa;
    
      m = fvec.Length;       // number of functions
      n = xvec.Length;       // number of variables

      // allocate working arrays
      // lwa = m*n+5*n+m;
      iwa = new int[n];
      // wa  = new double[lwa];
      double[] diag = new double[n];
      double[] fjac = new double[n*m];
      int[] ipvt = new int[n];
      double[] qtf = new double[n];
      double[] wa1 = new double[n];
      double[] wa2 = new double[n];
      double[] wa3 = new double[n];
      double[] wa4 = new double[m];




      LevenbergMarquardtFit (fcn,xvec,fvec,tol,ref info,iwa, diag, fjac, ipvt, qtf, wa1,
        wa2, wa3,wa4); 

    }
Example #5
0
    /// <summary>
    /// This subroutine computes a forward-difference approximation 
    /// to the m by n Jacobian matrix associated with a specified 
    /// problem of m functions in n variables. 
    /// </summary>
    /// <param name="fcn">User-supplied subroutine which  calculates the functions</param>
    /// <param name="m">m is a positive integer input variable set to the number of functions.</param>
    /// <param name="n">n is a positive integer input variable set to the number of variables. n must not exceed m.</param>
    /// <param name="x">x is an input array of length n containing the parameters.</param>
    /// <param name="fvec">fvec is an input array of length m which must contain the functions evaluated at x. </param>
    /// <param name="fjac">fjac is an output m by n array which contains the approximation to the Jacobian matrix evaluated at x.</param>
    /// <param name="ldfjac">ldfjac is a positive integer input variable not less than m which specifies the leading dimension of the array fjac. </param>
    /// <param name="iflag">iflag is an integer variable which can be used to terminate the execution of fdjac2. see description of fcn.</param>
    /// <param name="epsfcn">
    /// 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. 
    /// </param>
    /// <param name="wa">wa is a work array of length m.</param>
    public static void fdjac2(
      LMFunction fcn,
      int m, 
      int n, 
      double[] x, 
      double[] fvec, 
      double[] fjac, 
      int ldfjac,
      ref int iflag,
      double epsfcn,
      double[] wa)
     
    {
      int fjac_dim1;
      double temp, h;
      int i, j;
      double eps;

      // Parameter adjustments 
      // --wa; LELLID!!
      fjac_dim1 = ldfjac;
      // fjac_offset = fjac_dim1 + 1; // LELLID!!
      // fjac -= fjac_offset; // LELLID!!
      // --fvec; LELLID!!
      // --x; // LELLID!!

      eps = Math.Sqrt((Math.Max(epsfcn, DBL_EPSILON)));

      for (j = 0; j < n; ++j) 
      { // LELLID!!
        temp = x[j];
        h = eps * Math.Abs(temp);
        if (h == 0.0)  
          h = eps;
        x[j] = temp + h;
        fcn(m, n, x, wa, ref iflag);
        if (iflag < 0) 
          return;
        x[j] = temp;
        for (i = 0; i < m; ++i) // LELLID!!
          fjac[i + j * fjac_dim1] = (wa[i] - fvec[i]) / h;
      }
    }
Example #6
0
    /// <summary>
    /// This will compute the covariances at a given parameter set xvec.
    /// </summary>
    /// <param name="fcn">The function that was to minimize.</param>
    /// <param name="x">Parameter vector.</param>
    /// <param name="n">First dimension of the parameter vector.</param>
    /// <param name="m">Second dimension of the parameter vector.</param>
    /// <param name="covar">Array to hold the covariance matrix. Must be of dimension m*n.</param>
    /// <param name="sumchisq">Outputs the sum of chi squared.</param>
    public static int ComputeCovariances(LMFunction fcn, double[] x, int n, int m, double[]covar, out double sumchisq)
    {
      int  info=0;
      

      double[] f = new double[n];
      double[] fjac = new double[n*m];
      double [] jactjac = new double[m*m];

      fcn(n,m,x,f, ref info);
      sumchisq=0;
      for(int i=0;i<n;++i)
        sumchisq += f[i]*f[i];

      // calculate the Jacobian matrix.
      int iflag = 2;
      int ldfjac = n;
      double epsfcn=0;
      double[] wa4 = new double[n];
      fdjac2(fcn, n, m, x, f, fjac, ldfjac, ref iflag, epsfcn, wa4);

      // compute jacT*jac
      for(int i=0;i<m;++i)
      {
        for(int j=0;j<m;++j)
        {
          double sum = 0;
          for(int k=0;k<n;++k)
          {
            sum += fjac[k+n*i]*fjac[k+n*j];
          }
          jactjac[j + i * m] = sum;
        }
      }

      // changed  20060519: scale jactjac so that the diagonal is 1 (except for those elements which are zero)
      double[] scale = new double[m];
      for(int i=0;i<m;i++)
      {
        double jj = jactjac[i+i*m];
        scale[i] = jj == 0 ? 1 : 1 / Math.Sqrt(Math.Abs(jj));
      }

      for (int i = 0; i < m; ++i)
        for (int j = 0; j < m; ++j)
          jactjac[j + i * m] *= scale[i] * scale[j];

      int result =  LEVMAR_COVAR(jactjac, covar, sumchisq, m, n);

      // changed  20060519: now scale the covar back again so that Diag[x]*covar*Diag[x]
      for (int i = 0; i < m; ++i)
        for (int j = 0; j < m; ++j)
          covar[j + i * m] *= scale[i] * scale[j];

      return result;
    }