Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

powell.cc

Go to the documentation of this file.
00001 // powell.cc
00002 // SuperMix version 1.0  C++ source file
00003 //
00004 // Copyright (c) 1999 California Institute of Technology.
00005 // All rights reserved.
00006 //
00007 // Redistribution and use in source and binary forms for noncommercial
00008 // purposes are permitted provided that the above copyright notice and
00009 // this paragraph are duplicated in all such forms and that any
00010 // documentation and other materials related to such distribution and
00011 // use acknowledge that the software was developed by California
00012 // Institute of Technology. Redistribution and/or use in source or
00013 // binary forms is not permitted for any commercial purpose. Use of
00014 // this software does not include a permitted use of the Institute's
00015 // name or trademark for any purpose.
00016 //
00017 // DISCLAIMER:
00018 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT
00019 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR
00020 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET
00021 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
00022 // LICENSED PRODUCT, HOWEVER USED.  IN NO EVENT SHALL CALTECH/JPL BE
00023 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO
00024 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC
00025 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF
00026 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN
00027 // FACT SHALL KNOW OF THE POSSIBILITY.  THE USER BEARS ALL RISK
00028 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED
00029 // MATERIALS.
00030 // ********************************************************************
00031 //
00032 // Change history:
00033 // 12/12/00: added calls to stop() in minimize()
00034 // 3/21/00:  made "exeeded max iterations" warning only if verbose 
00035 // 8/6/99:   Modified to use minimize() in minimize1.h
00036 // 6/99:     converted to new optimizer interface  JSW
00037 // 11/10/98: minor change to support new vector indexing
00038 
00039 #include "powell.h"
00040 #include "matmath.h"
00041 #include "error.h"
00042 #include "minimize1.h"
00043 #include "num_utility.h"
00044 
00045 powell::powell(abstract_error_func & aef) :
00046   minimizer(aef),
00047   FTOL(1.0e-4),
00048   ITMAX(100),
00049   CLOSENESS(10),
00050   FOCUS(1.0),
00051   iter(0)
00052 { }
00053 
00054 
00055 double powell::minimize()
00056 {
00057   // set up control limits:
00058   FTOL = fabs(FTOL);
00059   if (FTOL < 1.0e-12) FTOL = 1.0e-12;
00060   if (FTOL > 0.1) FTOL = 0.1;
00061   LN_ITMAX = (ITMAX < 100) ? 100 : ITMAX;
00062   LN_TOL   = sqrt(sqrt(FTOL));
00063   if (FOCUS < 0.0) FOCUS = 0.0;
00064   double focus = FOCUS;
00065   
00066   // get initial values of parameters
00067   P = erf.get_parms();
00068   Pmax = erf.get_max_parms();
00069   Pmin = erf.get_min_parms();
00070   D = Pmax - Pmin; D /= CLOSENESS+1;
00071   lambda_ = sqrt(norm(D)); if (lambda_ < 1.0) lambda_ = 1.0;
00072 
00073   real_vector Ps(P), Pext(P) ;   // Ps saves old P; Pext: extrapolation of P
00074 
00075   
00076   // Create a set of direction vectors -- initially this is diagonal
00077   N.resize(P) ;                     // N: a "delta P" direction vector chosen from Nset
00078   real_matrix Nset(N.size, N.mode); // Nset holds the set of directions
00079   Nset.diagonal(1.) ;
00080 
00081   erf.set_count(0);
00082   double f = erf() ;  // uses the initial parameter values here
00083   if(target_on && f < target) return f; // we're already below the target value
00084 
00085   // OK, perform the minimization:
00086   for(iter=1; 1 ; ++iter) {
00087 
00088     int imin = P.minindex(), imax = P.maxindex();
00089     double fP;
00090     double del;   // will be largest delta f()
00091     int ibig;     // will be direction with largest delta f()
00092 
00093     if(is_verbose) {  // spit stuff out every iteration if verbose
00094       error::stream() << "Iteration " << iter << endl ;
00095       error::stream() << "Parameters: " << endl << erf.get_parms_user() << endl; 
00096       error::stream() << "Function value: " << f << endl ;
00097       if(is_very_verbose) {
00098         error::stream() << "Calls to error function: " << erf.count() << endl;
00099       }
00100       error::stream() << endl ;
00101     }
00102 
00103     // minimize in turn along each direction in Nset; determine ibig and del
00104     fP = f;
00105     del = 0.0;
00106     ibig = imin;
00107     lambda_ *= 1;
00108     for (int i = imin; i <= imax; ++i) {
00109       for (int j = imin; j <= imax; ++j) N[j] = Nset[i][j]; // get direction
00110       double lastf = f ;
00111       f = fmin(lambda());   // perform the line minimization
00112       //      P = erf.get_parms();  // limit P to the valid parameter range of erf
00113       if ( fabs(lastf - f) > del) {
00114         // biggest decrease so far
00115         del = fabs(lastf - f);
00116         ibig = i;
00117       }
00118     }
00119 
00120     // check for termination:
00121     if(stop(iter)) return f;
00122     if(target_on && f < target) return f;
00123     if(2.0*fabs(fP-f) <= FTOL*(fabs(fP)+fabs(f))) return f;
00124     if (iter >= ITMAX) {
00125       if(is_verbose) error::warning("powell exceeding maximum iterations.");
00126       return f;
00127     }
00128 
00129     // test extrapolated P and update Nset if warranted
00130     N = P - Ps;
00131     Pext = P + N;
00132     double fPext = erf(Pext);    // one more call to erf
00133     if (fPext < fP) {
00134 
00135       // test if a new coordinate direction is warranted; note that focus must be >= 1.0:
00136       if ((2.0*(fP-2.0*f+fPext)*norm(fP-f-del)-del*norm(fP-fPext) < 0.0) && focus >= 1.0) {
00137         f = fmin(lambda());
00138         for (int j = imin; j <= imax; ++j) {
00139           Nset[ibig][j] = Nset[imax][j];
00140           Nset[imax][j] = N[j];
00141         }
00142       }
00143 
00144       // else, if fPext is better don't discarg it!
00145       else if (fPext < f) {
00146         P = Pext; f = fPext;
00147       }
00148     }
00149 
00150     // for the next iteration:  
00151     Ps = P;
00152     focus += FOCUS;
00153 
00154   } // for(iter)
00155 
00156 } // powell::minimize()
00157 
00158 
00159 // calculate error function values along a vector with direction N from point P:
00160 double powell::f(double x) const
00161 {
00162   xf = N; xf *= x; xf += P;
00163   return erf(xf);
00164 }
00165 
00166 
00167 // find the minimum of f(x) and update P to be the location of the minimum
00168 double powell::fmin(double lambda)
00169 {
00170   double x1, x2, fmin;
00171   x1 = lambda;
00172   x2 = 0.0;
00173   double a = x2, c, fa, fx1, fc;
00174   unsigned count = erf.count();
00175   if(is_very_verbose) {
00176     error::stream() << "Starting X values: " << a << " " << x1 << endl;
00177     error::stream() << "Starting f(X) val: " << f(a) << " " << f(x1) << endl;
00178   }
00179   erf.set_count(0);
00180   bracket_minimum(member_function(& powell::f, *this),a,x1,c,fa,fx1,fc,LN_ITMAX);
00181   if(is_very_verbose) {
00182     error::stream() << "Calls to erf by bracket_minimum(): " << erf.count() << endl;
00183     error::stream() << "X values: " << a << " " << x1 << " " << c << endl;
00184     error::stream() << "f(X) val: " << fa << " " << fx1 << " " << fc << endl;
00185   }
00186   count += erf.count(); erf.set_count(0);
00187   fmin = refine_minimum(member_function(& powell::f, *this),a,x1,c,LN_TOL, LN_ITMAX);
00188   if(is_very_verbose) {
00189     error::stream() << "Calls to erf by refine_minimum(): " << erf.count() << endl;
00190     error::stream() << "Minimum X value: " << x1 << " , fmin: " << fmin << endl;
00191   }
00192   count += erf.count(); erf.set_count(count);
00193   N *= x1 ;
00194   P += N ;
00195   return(fmin) ;
00196 }
00197 
00198 
00199 // find an appropriate initial increment multiplier for the line minimizer
00200 // must initialize P, Pmax, Pmin, N before calling
00201 double powell::lambda()
00202 {
00203   int imin = P.minindex(), imax = P.maxindex();
00204   for (int i = imin; i <= imax; ++i) {
00205     if(N[i] == 0.0 || D[i] <= 0.0) continue;
00206     double L = D[i]/N[i];
00207     if (fabs(L) < fabs(lambda_)) lambda_ = L;
00208   }
00209   return lambda_ ;
00210 }

Please direct comments and corrections to supermix@submm.caltech.edu
Go to the supermix home page
Generated by doxygen1.2.7