default
[ class tree: default ] [ index: default ] [ all elements ]

Source for file LevenbergMarquardt.php

Documentation is available at LevenbergMarquardt.php

  1. <?php
  2.  
  3. // Levenberg-Marquardt in PHP 
  4.  
  5. // http://www.idiom.com/~zilla/Computer/Javanumeric/LM.java
  6.  
  7.  
  8.   /**
  9.   * Calculate the current sum-squared-error
  10.   *
  11.   * Chi-squared is the distribution of squared Gaussian errors,
  12.   * thus the name.
  13.   *
  14.   * @param double[][] $x 
  15.   * @param double[] $a 
  16.   * @param double[] $y, 
  17.   * @param double[] $s, 
  18.   * @param object $f 
  19.   */
  20.   function chiSquared($x$a$y$s$f{
  21.  
  22.     $npts count($y);
  23.  
  24.     $sum 0.0;
  25.  
  26.     for($i 0$i $npts$i++ {
  27.       $d $y[$i$f->val($x[$i]$a);
  28.       $d $d $s[$i];
  29.       $sum $sum ($d*$d);
  30.     }
  31.  
  32.     return $sum;
  33.  
  34.   }
  35.  
  36.  
  37.   /**
  38.   * Minimize E = sum {(y[k] - f(x[k],a)) / s[k]}^2
  39.   * The individual errors are optionally scaled by s[k].
  40.   * Note that LMfunc implements the value and gradient of f(x,a),
  41.   * NOT the value and gradient of E with respect to a!
  42.   * 
  43.   * @param array of domain points, each may be multidimensional
  44.   * @param corresponding array of values
  45.   * @param the parameters/state of the model
  46.   * @param vary false to indicate the corresponding a[k] is to be held fixed
  47.   * @param s2 sigma^2 for point i
  48.   * @param lambda blend between steepest descent (lambda high) and
  49.   *     jump to bottom of quadratic (lambda zero).
  50.   *      Start with 0.001.
  51.   * @param termepsilon termination accuracy (0.01)
  52.   * @param maxiter    stop and return after this many iterations if not done
  53.   * @param verbose    set to zero (no prints), 1, 2
  54.   *
  55.   * @return the new lambda for future iterations.
  56.   *   Can use this and maxiter to interleave the LM descent with some other
  57.   *   task, setting maxiter to something small.
  58.   */
  59.   function solve($x$a$y$s$vary$f$lambda$termepsilon$maxiter$verbose{
  60.  
  61.     $npts count($y);
  62.     $nparm count($a);
  63.  
  64.     if ($verbose 0{
  65.       print("solve x[".count($x)."][".count($x[0])."]");
  66.       print(" a[".count($a)."]");
  67.       println(" y[".count(length)."]");
  68.     }
  69.  
  70.     $e0 $this->chiSquared($x$a$y$s$f);
  71.  
  72.     //double lambda = 0.001;
  73.     $done false;
  74.  
  75.     // g = gradient, H = hessian, d = step to minimum
  76.     // H d = -g, solve for d
  77.     $H array();
  78.     $g array();
  79.     
  80.     //double[] d = new double[nparm];
  81.  
  82.     $oos2 array();
  83.     
  84.     for($i 0$i $npts$i++)  $oos2[$i1./($s[$i]*$s[$i]);
  85.  
  86.     $iter 0;
  87.     $term 0;    // termination count test
  88.  
  89.     do {
  90.       ++$iter;
  91.  
  92.       // hessian approximation
  93.       for$r 0$r $nparm$r++ {
  94.           for$c 0$c $nparm$c++ {
  95.             for$i 0$i $npts$i++ {
  96.               if ($i == 0$H[$r][$c0.;
  97.               $xi $x[$i];
  98.               $H[$r][$c+= ($oos2[$i$f->grad($xi$a$r$f->grad($xi$a$c));
  99.             }  //npts
  100.           //c
  101.       //r
  102.  
  103.       // boost diagonal towards gradient descent
  104.       for$r 0$r $nparm$r++ )
  105.           $H[$r][$r*= (1. $lambda);
  106.  
  107.       // gradient
  108.       for$r 0$r $nparm$r++ {
  109.           for$i 0$i $npts$i++ {
  110.             if ($i == 0$g[$r0.;
  111.             $xi $x[$i];
  112.             $g[$r+= ($oos2[$i($y[$i]-$f->val($xi,$a)) $f->grad($xi$a$r));
  113.           }
  114.       //npts
  115.  
  116.       // scale (for consistency with NR, not necessary)
  117.       if ($false{
  118.           for$r 0$r $nparm$r++ {
  119.             $g[$r= -0.5 $g[$r];
  120.             for$c 0$c $nparm$c++ {
  121.               $H[$r][$c*= 0.5;
  122.             }
  123.           }
  124.       }
  125.  
  126.       // solve H d = -g, evaluate error at new location
  127.       //double[] d = DoubleMatrix.solve(H, g);
  128.       double[(new Matrix(H)).lu().solve(new Matrix(gnparm)).getRowPackedCopy();
  129.       //double[] na = DoubleVector.add(a, d);
  130.       double[na (new Matrix(anparm)).plus(new Matrix(dnparm)).getRowPackedCopy();
  131.       double e1 chiSquared(xnaysf);
  132.  
  133.       if (verbose 0{
  134.           System.out.println("\n\niteration "+iter+" lambda = "+lambda);
  135.           System.out.print("a = ");
  136.         (new Matrix(anparm)).print(102);
  137.           if (verbose 1{
  138.           System.out.print("H = ")
  139.           (new Matrix(H)).print(102);
  140.           System.out.print("g = ")
  141.           (new Matrix(gnparm)).print(102);
  142.           System.out.print("d = ")
  143.           (new Matrix(dnparm)).print(102);
  144.           }
  145.           System.out.print("e0 = " e0 ": ");
  146.           System.out.print("moved from ");
  147.         (new Matrix(anparm)).print(102);
  148.           System.out.print("e1 = " e1 ": ");
  149.           if (e1 e0{
  150.             System.out.print("to ");
  151.           (new Matrix(nanparm)).print(102);
  152.           else {
  153.             System.out.println("move rejected");
  154.           }
  155.       }
  156.  
  157.       // termination test (slightly different than NR)
  158.       if (Math.abs(e1-e0termepsilon{
  159.           term 0;
  160.       else {
  161.           term++;
  162.           if (term == 4{
  163.             System.out.println("terminating after " iter " iterations");
  164.             done true;
  165.           }
  166.       }
  167.       if (iter >= maxiterdone true;
  168.  
  169.       // in the C++ version, found that changing this to e1 >= e0
  170.       // was not a good idea.  See comment there.
  171.       //
  172.       if (e1 e0 || Double.isNaN(e1)) // new location worse than before
  173.           lambda *= 10.;
  174.       else {        // new location better, accept new parameters
  175.           lambda *= 0.1;
  176.           e0 e1;
  177.           // simply assigning a = na will not get results copied back to caller
  178.           forint i 0nparmi++ {
  179.             if (vary[i]a[ina[i];
  180.           }
  181.       }
  182.     while(!$done);
  183.  
  184.     return $lambda;
  185.  
  186.   //solve
  187.  
  188. }
  189.  
  190. ?>

Documentation generated on Mon, 05 Jan 2009 20:38:01 +0100 by phpDocumentor 1.4.1