Subversion Repositories f9daq

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. Only core function
  3. MIT License
  4.  
  5. Copyright (c) Jonas Almeida.
  6.  
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13.  
  14. The above copyright notice and this permission notice shall be included in all
  15. copies or substantial portions of the Software.
  16.  
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. SOFTWARE.*/
  24.  
  25. lin = function(x,P){
  26.         return x.map(function(xi){return (xi*P[1] + P[0])})
  27. }
  28.  
  29. quad = function(x,P){
  30.         return x.map(function(xi){return (Math.pow(xi, 2)*P[2] + xi*P[1] + P[0])})
  31. }
  32.  
  33. gaus2 = function(x, P){
  34.         return x.map(function(xi){return (P[2] * Math.exp(-0.5 * Math.pow((xi-P[0]) / P[1], 2)))})
  35. }
  36.  
  37.  
  38. chisq = function(y, yp){
  39.     var sum = 0;
  40.     for(var i = 0; i<y.length; i++){
  41.         if(y[i] != 0){
  42.             sum += Math.pow((y[i]-yp[i]),2)/y[i];
  43.         }
  44.     }
  45.     return sum
  46. }
  47.  
  48. fminsearch=function(fun,Parm0,x,y,Opt){// fun = function(x,Parm)
  49.  
  50.         // fun = function(x,P){return x.map(function(xi){return (P[0]+1/(1/(P[1]*(xi-P[2]))+1/P[3]))})}
  51.         // x=[32,37,42,47,52,57,62,67,72,77,82,87,92];y=[0,34,59,77,99,114,121,133,146,159,165,173,170];
  52.         //
  53.         // Opt is an object will all other parameters, from the objective function (cost function), to the
  54.         // number of iterations, initial step vector and the display switch, for example
  55.         // Parms=fminsearch(fun,[100,30,10,5000],x,y,{maxIter:10000,display:false})
  56.        
  57.         if(!Opt){Opt={}};
  58.         if(!Opt.maxIter){Opt.maxIter=1000};
  59.         if(!Opt.step){// initial step is 1/100 of initial value (remember not to use zero in Parm0)
  60.                 Opt.step=Parm0.map(function(p){return p/100});
  61.                 Opt.step=Opt.step.map(function(si){if(si==0){return 1}else{ return si}}); // convert null steps into 1's
  62.         };
  63.  
  64.         if(!Opt.objFun){Opt.objFun=function(y,yp){
  65.                 //console.log(y, yp);
  66.                 return chisq(y, yp)}//y.map(function(yi,i){return Math.pow((yi-yp[i]),2)}).reduce(function(a,b){return a+b})}
  67.         } //SSD
  68.         if(!Opt.mask){Opt.mask = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}; //use all parameters
  69.         if(!Opt.maskBond){Opt.maskBond = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[]]};//first element is mask, second is
  70.         if(!Opt.sframe){Opt.sframe = 'h0'};
  71.         var cloneVector=function(V){return V.map(function(v){return v})};
  72.  
  73.         var P1, ya,y0,yb,fP0,fP1;
  74.         var P0 = cloneVector(Parm0);//, P1 = cloneVector(Parm0);
  75.         var n = P0.length;
  76.         var step = Opt.step;
  77.         var funParm=function(P){return Opt.objFun(y,fun(x,P, Opt.sframe))}//function (of Parameters) to minimize
  78.         //console.log('before:', P0);
  79.         P0 = checkIfInRange(P0, Opt.maskBond);
  80.         //console.log('after:', P0)
  81.         // silly multi-univariate screening
  82.         for(var i=0;i<Opt.maxIter;i++){
  83.                 //console.log(i, P0);
  84.                 for(var j=0;j<n;j++){ // take a step for each parameter
  85.                         if(Opt.mask[j]==0){continue};//if parameter not used, skip it
  86.                        
  87.                         P1=cloneVector(P0);
  88.                         P1[j]+=step[j];
  89.                         //console.log(i, P1)
  90.                         //check if new parameter is bonded => check if out of bonds
  91.                         P1 = checkIfInRange(P1, Opt.maskBond)
  92.  
  93.                         if(funParm(P1)<funParm(P0)){ // if parm value going in the righ direction
  94.                                 step[j]=1.2*step[j]; // then go a little faster
  95.                                 P0=cloneVector(P1);
  96.                         }
  97.                         else{
  98.                                 step[j]=-(0.5*step[j]); // otherwiese reverse and go slower
  99.                         }      
  100.                 }
  101.                 if(Opt.display){if(i>(Opt.maxIter-10)){console.log(i+1,funParm(P0),P0)}}
  102.                 //console.log(funParm(P0), P0);
  103.         }
  104.         //console.log(funParm(P0), P0, chisq(y, fun(x,P0)));
  105.         return [P0, chisq(y, fun(x,P0, Opt.sframe))];
  106. };
  107.  
  108. function checkIfInRange(P0, maskBond){
  109.         //P0 - vector of parameters
  110.         //n - number of parameters
  111.         //maskBond - first element is actual mask, second element is matrix of
  112.         var n = P0.length;
  113.         for(var j=0; j<n;j++){
  114.                 if(maskBond[0][j]==1){
  115.                         if(P0[j] < maskBond[1][j][0]){P0[j]=maskBond[1][j][0]};
  116.                         if(P0[j] > maskBond[1][j][1]){
  117.                                 P0[j]=maskBond[1][j][1];
  118.                         }
  119.                 }
  120.         }
  121.         return P0
  122. }