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
1.2.7