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

Documentation generated on Sat, 19 May 2012 14:37:42 +0200 by phpDocumentor 1.4.4