00001 // SuperMix version 1.0 C++ source file
00002 //
00003 // Copyright (c) 1999 California Institute of Technology.
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms for noncommercial
00007 // purposes are permitted provided that the above copyright notice and
00008 // this paragraph are duplicated in all such forms and that any
00009 // documentation and other materials related to such distribution and
00010 // use acknowledge that the software was developed by California
00011 // Institute of Technology. Redistribution and/or use in source or
00012 // binary forms is not permitted for any commercial purpose. Use of
00013 // this software does not include a permitted use of the Institute's
00014 // name or trademark for any purpose.
00015 //
00016 // DISCLAIMER:
00017 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT
00018 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR
00019 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET
00020 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
00021 // LICENSED PRODUCT, HOWEVER USED. IN NO EVENT SHALL CALTECH/JPL BE
00022 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO
00023 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC
00024 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF
00025 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN
00026 // FACT SHALL KNOW OF THE POSSIBILITY. THE USER BEARS ALL RISK
00027 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED
00028 // MATERIALS.
00029
00030 // ************************************************************************
00031 // optimizer.h
00032 //
00033 // Contains abstract classes to provide an interface to multivariate error
00034 // functions and minimize them with optimization algorithms.
00035 //
00036 // 7/27/98 by J.Z.
00037 //
00038 // 9/22/00: Added minimizer::stop().
00039 // 9/9/00: Provided usage info; changed flags to bool from int.
00040 // 9/8/00: Improved efficiency of abstract_error_func::calc_f().
00041 // 8/19/99: Another overhaul, especially to class abstract_error_func.
00042 // 4/21/99: Major overhaul to generalize and simplify the optimizer. JSW
00043 //
00044 // ************************************************************************
00045 // class minimizer:
00046 //
00047 // Class minimizer is an abstract class that defines an interface for
00048 // multiparameter optimization routines. Predefined optimizers derived from
00049 // minimizer include class "powell" in the file powell.h and class
00050 // "montecarlo" in montecarlo.h.
00051 //
00052 //
00053 // USAGE:
00054 //
00055 // Use one of the provided optimizers derived from class minimizer or
00056 // derive a new class of your own.
00057 //
00058 // Assume you are using the optimization class optimizer_class, which
00059 // is derived from class minimizer. Its constructor requires an error
00060 // function. You have already declared an error function ("my_error_func")
00061 // which is of a type derived from class abstract_error_func. Then:
00062 //
00063 // optimizer_class my_optimizer(my_error_func);
00064 //
00065 // Creates an optimizer for your error function which is ready to use.
00066 // You can then call any or all of the member functions of class minimizer:
00067 //
00068 // my_optimizer.verbose(); // toggle to provide status output
00069 //
00070 // my_optimizer.very_verbose(); // even more detailed status output
00071 //
00072 // my_optimizer.quiet(); // minimal or no status output (default)
00073 //
00074 // my_optimizer.set_target(10.0); // optimizer should stop if error drops
00075 // // to or below 10.0
00076 //
00077 // my_optimizer.no_target(); // use the optimizer's default method to
00078 // // decide when to stop.
00079 //
00080 // double e = my_optimizer.minimize(); // perform the minimization of the
00081 // // error function. Final error
00082 // // value is copied into e.
00083 //
00084 // After completion of the optimization, the error function object will hold
00085 // the values of the optimization parameters which achieved the error
00086 // function value returned by minimize(). See the description of class
00087 // abstract_error_func for details.
00088 //
00089 // There is an additional member function: stop(). It is described below.
00090 //
00091 //
00092 // WRITING YOUR OWN OPTIMIZER:
00093 //
00094 // If you write your own optimizer, then create a subclass of minimizer to
00095 // implement your specific minimization algorithm. Fill in the code for the
00096 // minimize() routine, which should minimize the error function. The error
00097 // function should be derived from class abstract_error_function (see details
00098 // below). The minimize() routine should interface with the error function
00099 // using only the member routines declared in class abstract_error_function.
00100 //
00101 // Class minimizer requires an abstract_error_function reference as an
00102 // argument to its constructor.
00103 //
00104 // Here's how to derive an optimizer from class minimizer:
00105 //
00106 // You must define a class (or use an already-defined class) derived from
00107 // class minimizer, with the following member definition details:
00108 //
00109 // class my_minimizer_class : public minimizer {
00110 // public:
00111 //
00112 // // Your constructor must provide an error function object (derived
00113 // // from class abstract_error_func) to minimizer, which will use it
00114 // // to initialize the reference variable minimizer::erf. Example:
00115 //
00116 // my_minimizer_class(abstract_error_func & aef) : minimizer(aef)
00117 // { ... // your constructor code goes here, if needed }
00118 //
00119 //
00120 // // You provide the minimization routine by implementing virtual
00121 // // function minimize(). It should return the final error function
00122 // // value.
00123 //
00124 // double minimize()
00125 // {
00126 // ... // Your code calls member functions of the abstract_error_func
00127 // // variable erf. When asking the error function for its
00128 //
00129 // // A single-variable minimization routine is provided by the
00130 // // templated function minimize(), defined in minimize1.h
00131 // // You may want to call it as a part of your algorithm.
00132 //
00133 // // Your algorithm should check variables is_verbose and
00134 // // is_very_verbose and output something useful if required.
00135 //
00136 // // Your algorithm should use the target error function value
00137 // // if target_on is set.
00138 // }
00139 //
00140 // };
00141 //
00142 //
00143 // Now you can declare and use a new optimizer object:
00144 //
00145 // my_minimizer_class my_minimizer(my_error_function);
00146 //
00147 // double minimum = my_minimizer.minimize();
00148 //
00149 //
00150 // Notes regarding minimize():
00151 //
00152 // Your minimizer should provide some useful status output as it executes if
00153 // the boolean is_verbose is true. It should provide even more details if the
00154 // boolean is_very_verbose is true. If target_on is true, then the minimizer
00155 // should exit successfully if the error function value decreases below
00156 // the value stored in member variable target. Otherwise it should use some
00157 // other method to test for convergence on a minimum. Your minimize()
00158 // routine should call the virtual function stop(int) periodically as it
00159 // executes. The argument in the call is meant to be an iteration count
00160 // and may be omitted (a default value of 0 is used in this case. stop()
00161 // returns a boolean value. If stop() returns false, then minimize()
00162 // should continue with its calculations; If stop() returns true, then
00163 // minimize() should terminate gracefully as though it had converged on a
00164 // minimum, using the best error function value and parameter set seen so
00165 // far.
00166 //
00167 // Notes regarding stop():
00168 //
00169 // The virtual function stop(), as defined, simply ignores the calling
00170 // argument and always returns false. It is provided as a means to add
00171 // additional functionality to an implementation of minimize() in a
00172 // derived class. By deriving and changing the definition of stop(), a
00173 // programmer could:
00174 //
00175 // (1) provide additional status information beyond that normally
00176 // output in the verbose and/or very_verbose modes.
00177 //
00178 // (2) allow the minimization to be terminated early without aborting
00179 // the program run.
00180 //
00181 // ************************************************************************
00182 // class abstract_error_func:
00183 //
00184 // Class abstract_error_func defines the interface that all multiparameter
00185 // error functions must implement in order to be used by classes derived
00186 // from class minimizer.
00187 //
00188 // The error function can be a function of multiple real (double) variables.
00189 // Therefore, we treat it as a function of a single real_vector object (see
00190 // SuperMix's header file vector.h, NOT the C++ standard header <vector.h>).
00191 // Consequently, communication between an optimization algorithm and the
00192 // error function is accomplished using real_vector objects containing the
00193 // relevant parameter values. In this way, the optimization algorithm is
00194 // insulated from the details of how the parameter values are actually used
00195 // to affect the program's behavior; these "messy" details are handled
00196 // entirely by the error function.
00197 //
00198 // SuperMix provides an abstract class derived from abstract_error_func which
00199 // handles all of the details of mapping the elements of these real_vectors
00200 // of values and actual program variables of type "parameter" (actually a
00201 // type_def for type "real_parameter" defined in parameter/real_parameter.h),
00202 // since most variables controlling the behavior of circuit elements in
00203 // SuperMix are of this type. This class is called "error_func_parameters"
00204 // and is defined in simple_error_func.h
00205 //
00206 // SuperMix also provides a fully implemented, concrete error function class
00207 // called "error_func", defined in error_func.h. It is derived from class
00208 // error_func_parameters, so it provides for the interface and control of
00209 // program parameter variables by the optimizer algorithm. It can calculate
00210 // complicated error function values containing multiple weighted terms swept
00211 // and summed over any number of ranges of multidimensional parameter space.
00212 //
00213 //
00214 // INTERFACE WITH THE MINIMIZER: GETTING AND SETTING PARAMETER VALUES
00215 //
00216 // The minimizer algorithm may need to know not only the current parameter
00217 // values, but also minimum, maximum, and initial values as well. Of course,
00218 // it also needs to be able to set the values of the parameters. The
00219 // following member functions of abstract_error_func provide for this
00220 // interface with the minimizer. All of the get_... functions should return
00221 // real_vectors with the same index mode and valid index range; their
00222 // individual sizes MAY EXCEED THE VALID INDEX RANGE. The minimizer algorithm
00223 // MUST ignore elements outside the valid index range. This means that if "V"
00224 // is a real_vector object returned by an abstract_error_func, then the valid
00225 // elements of V have index values from V.minindex() to V.maxindex(). If you
00226 // have an object "erf" derived from class abstract_error_func, then:
00227 //
00228 // erf.size(); // Return the number of parameters (an int
00229 // // value). This gives the number of valid
00230 // // elements in the real_vectors returned by
00231 // // erf.get_...
00232 //
00233 // erf.get_parms(); // Returns a real_vector containing the current
00234 // // values of the parameters actually being used
00235 // // in the program. The values will be limited by
00236 // // each parameter's specified min and max value.
00237 //
00238 // erf.get_min_parms(); // Returns a real_vector containing the minimum
00239 // // allowable values of the parameters.
00240 //
00241 // erf.get_max_parms(); // Returns a real_vector containing the maximum
00242 // // allowable values of the parameters.
00243 //
00244 // erf.get_initial_parms();// Returns a real_vector containing the values
00245 // // of the parameters initially assigned by the
00246 // // program. These values NEED NOT be limited by
00247 // // each parameter's specified min and max value.
00248 //
00249 // erf.set_parms(V); // Sets the parameters using the elements of the
00250 // // real_vector argument V. The first valid
00251 // // element of V holds the value for the first
00252 // // parameter, etc. V may attempt to set the
00253 // // parameters to values outside of their
00254 // // specified allowable ranges; the error
00255 // // function must take care of limiting these
00256 // // values appropriately.
00257 //
00258 // Note that none of these functions provides for setting the number of
00259 // parameters or for setting their minimum, maximum, or initial values. These
00260 // details must be taken care of by additional functions of classes derived
00261 // from class abstract_error_func. This implies that a minimizer algorithm
00262 // should not need to perform any of those functions.
00263 //
00264 //
00265 // RETURNING THE ERROR FUNCTION VALUE
00266 //
00267 // The primary means of calculating the error function value is to use
00268 // operator (). This is the method that should be used by a minimizer
00269 // algorithm. Again assuming your error function is called "erf":
00270 //
00271 // double e = erf(); // Using the current parameter values, calculate
00272 // // and return the error function value. In this
00273 // // case, copy the value into variable e.
00274 //
00275 // double e = erf(V); // Attempt to set the parameter values to those
00276 // // in the real_vector argument V and return the
00277 // // resulting error function value. The error
00278 // // function will limit the values to their valid
00279 // // ranges as in erf.set_parms(V). If V includes
00280 // // a values outside the specified ranges for
00281 // // the parameters, then the returned error
00282 // // function value will rise exponentially from
00283 // // its value at the nearest parameter space
00284 // // boundary point to V. This behavior is the
00285 // // default, but may be disabled by passing a
00286 // // boolean = true argument to the
00287 // // abstract_error_func constructor.
00288 //
00289 // Unlike the case of set_parms(V), the argument V in erf(V) MUST HAVE THE
00290 // SAME INDEXING MODE AND VALID INDEX RANGE AS THE RESULT RETURNED BY
00291 // get_parms().
00292 //
00293 // The calls above also increment an internal count register which can be
00294 // examined to determine how many calls have been made to calculate the
00295 // error function.
00296 //
00297 // Note that calling:
00298 // erf.set_parms(V);
00299 // double e = erf();
00300 // is generally faster than calling:
00301 // double e = erf(V);
00302 // since the error function value in the former case is always calculated at
00303 // a point within the valid range of the parameters, so an exponential growth
00304 // factor need not be calculated (a nontrivial calculation!). Convergence of
00305 // an optimization algorithm may be slowed down substantially, however, if
00306 // the algorithm continually tries to set V well outside the valid range of
00307 // the parameters. For this reason, optimization algorithms should always
00308 // use erf(V), unless the algorithm will not attempt to set V outside the
00309 // error function parameter limits.
00310 //
00311 //
00312 // OTHER MEMBER FUNCTIONS USEFUL FOR STATUS MONITORING
00313 //
00314 // Verbose output from the optimizer could include the current parameter
00315 // values along with a count of the number of calls made to the error
00316 // function. Here are functions which help with generating this output:
00317 //
00318 // erf.set_count(); // Reset the internal count register to 0. At
00319 // // creation of the error function object, the
00320 // // count register is already reset.
00321 //
00322 // erf.set_count(n); // Set the count register to (unsigned) n.
00323 //
00324 // erf.count(); // Returns the (unsigned) value of the count
00325 // // register. This count is incremented with
00326 // // each call to operator(), ie: erf() or erf(V).
00327 //
00328 // erf.get_parms_user(); // Return a real_vector of parameter values,
00329 // // but first convert each parameter into a
00330 // // number which has physical meaning to the
00331 // // user. In other words, if a parameter
00332 // // represents a physical resistance, then
00333 // // get_parms_user() may return its value in
00334 // // Ohms. Note that the error function erf
00335 // // must determine how to convert the values.
00336 //
00337 // erf.get_units(); // Returns a vector of the scaling factors
00338 // // erf uses when converting parameter values
00339 // // in get_parms_user(). These "units" work
00340 // // as described in the header file units.h
00341 // // for units conversion.
00342 //
00343 // Since get_parms() and set_parms() manipulate parameters in their internal
00344 // SuperMix representation and get_parms_user() provides an external,
00345 // physical value, we have the relation:
00346 // erf.get_parms_user()[i] * erf.get_units()[i] == erf.get_parms()[i]
00347 // for each element [i] of the real_vectors. An optimizer's verbose output
00348 // code may include a statement like:
00349 // cerr << erf.get_parms_user() << endl;
00350 // To display the values of the parameters in easy-to-interpret form.
00351 //
00352 //
00353 // WRITING YOUR OWN ERROR FUNCTION CLASS
00354 //
00355 // If you write your own error function class, you must derive it from
00356 // class abstract_error_func and provide implementations of the following
00357 // virtual functions:
00358 // virtual void set_parms(const real_vector & pv);
00359 // virtual real_vector get_parms();
00360 // virtual real_vector get_min_parms();
00361 // virtual real_vector get_max_parms();
00362 // virtual real_vector get_initial_parms();
00363 // virtual real_vector get_parms_user();
00364 // virtual real_vector get_units();
00365 // virtual int size();
00366 // virtual double func_value();
00367 //
00368 // A very viable approach to the possibly daunting task of implementing all
00369 // these functions is to derive your error function from class
00370 // "error_func_parameters" described in simple_error_func.h; in this case
00371 // you'll only have to implement func_value(). See simple_error_func.h for
00372 // details.
00373 //
00374 // The function func_value() calculates the value of the error function
00375 // at the point specified by the most recent call to set_parms(), or using
00376 // the initial parameter values as if the call:
00377 // set_parms(get_initial_parms())
00378 // had been made. In any case, get_parms() should ALWAYS return the point
00379 // at which a call to func_value() would calculate the error function.
00380 // It should never be the case that func_value() would attempt to calculate
00381 // the error function for a point with a parameter value outside of its
00382 // allowable range as defined by the return values of get_min_parms() and
00383 // get_max_parms(), since set_parms() is required to limit the values
00384 // stored to their valid ranges.
00385 //
00386 // It is probably appropriate (although not necessary) that the returned
00387 // real_vector results of the get_... functions use indexing mode Index_1.
00388 // In this case, the valid index range of the returned vectors would be
00389 // from 1 to size(). Note that set_parms() must accept a real_vector using
00390 // any indexing mode, not just the indexing mode used in the return values
00391 // of the get_... functions.
00392 //
00393 // The relationship between the return values of get_parms(), get_units(),
00394 // and get_parms_user() was described earlier. If this scaling scheme is
00395 // not appropriate for the parameters being optimized, then get_units()
00396 // should return a real_vector filled with 1's and get_parms_user()
00397 // should just return the same result as get_parms().
00398 //
00399 // Refer to the comments in the declaration of abstract_error_func below
00400 // for further details.
00401 //
00402 // ************************************************************************
00403
00404
00405 #ifndef OPTIMIZER_H
00406 #define OPTIMIZER_H
00407
00408 #include "matmath.h"
00409
00410 // ************************************************************************
00411 // abstract_error_func:
00412
00413 class abstract_error_func
00414 {
00415 public:
00416
00417 // If the constructor is called with a true argument, parameter limits are
00418 // ignored in operator() calculations
00419 explicit abstract_error_func(bool no_limits_flag = false)
00420 : limit_flag(!no_limits_flag) {} ;
00421
00422 // All of the get_... functions should return real_vectors with the same
00423 // index mode and valid index range; their individual sizes may exceed the
00424 // valid index range. The minimizer algorithm should ignore elements
00425 // outside the valid index range.
00426
00427 // Get and set the current parameter values. Note that calling
00428 // set_parms(get_parms()) should not change the parameter values used in
00429 // error function value calculations.
00430 virtual void set_parms(const real_vector & pv) = 0;
00431 virtual real_vector get_parms() = 0;
00432
00433 // We sometimes want to get the parameters in units convenient for the
00434 // user instead of machine units. This is usually for the purpose of
00435 // displaying them on screen.
00436 virtual real_vector get_parms_user() = 0;
00437
00438 // Get the minimum, maximum, and initial parameter values in machine
00439 // units. Note that the methods for setting these values are not defined
00440 // by this interface.
00441 virtual real_vector get_min_parms() = 0;
00442 virtual real_vector get_max_parms() = 0;
00443 virtual real_vector get_initial_parms() = 0;
00444
00445 // The parameters can be scaled by a scaling factor, usually corresponding
00446 // to some desired units (such as gigahertz.) If this feature is not
00447 // needed, get_units() should return a vector of all 1's.
00448 virtual real_vector get_units() = 0;
00449
00450 // Return the number of parameters to optimize. How this number is
00451 // determined is up to the actual error function derived from this
00452 // abstract interface class.
00453 virtual int size() = 0;
00454
00455 // primitive error function value calculation; called by operator().
00456 virtual double func_value() = 0 ;
00457
00458
00459 // Optionally set the parameters and calculate the function values. If the
00460 // vector pv determines a point outside of the valid parameter space as
00461 // defined by get_min_parms() and get_max_parms(), and parameter limits
00462 // are active (the default), then operator()(pv) will blow up the value
00463 // of the error function exponentially; this encourages a minimizer to
00464 // rapidly return the parameter values within the specified limits.
00465 // Note that for the limiting to work properly, pv must have the same size
00466 // and indexing mode as the real_vector returned by get_parms().
00467
00468 double operator()(const real_vector & pv); // use parameter values in pv.
00469 double operator()(); // use the previously set
00470 // parameter values.
00471
00472
00473 // maintain a count of the number of times that operator() has been called
00474 unsigned count() { return count_; }
00475 void set_count(unsigned c = 0) { count_ = c; }
00476
00477 // A virtual destructor ensures proper subclass destruction.
00478 virtual ~abstract_error_func() { }
00479
00480
00481 private:
00482 unsigned count_; // count calls to func_value();
00483 bool limit_flag; // should we consider parameter limits?
00484 double calc_f(); // manages count_; calls func_value()
00485 double calc_f(const real_vector & P); // consider limits with point P
00486 real_vector Ptemp; // temporary used by calc_f(P)
00487 } ;
00488
00489 inline double abstract_error_func::operator()()
00490 { return calc_f(); }
00491 inline double abstract_error_func::operator()(const real_vector & pv)
00492 { return calc_f(pv); }
00493
00494 inline double abstract_error_func::calc_f()
00495 { ++count_ ; return func_value(); }
00496
00497 inline double abstract_error_func::calc_f(const real_vector & P)
00498 {
00499 // When the parameters are set to P, the error function limits them
00500 // to within the parameter space boundaries:
00501 set_parms(P);
00502 double erf = calc_f();
00503
00504 if (limit_flag) {
00505 Ptemp = get_parms(); // Get the parameters, limited by boundaries
00506 Ptemp -= P; // we assume the sizes and indexing modes are compatible
00507 // Now if Ptemp != 0, P is outside the parameter space
00508 double d = norm(Ptemp);
00509 if (d != 0.0) {
00510 // We inflate the error function value exponentially:
00511 Ptemp = get_max_parms(); Ptemp -= get_min_parms();
00512 // Now Ptemp has the size of the parameter space
00513 double s = norm(Ptemp); // scale factor
00514 erf += (1+fabs(erf))*(exp(d/s)-1); // exponentially increase erf
00515 }
00516 }
00517 return erf;
00518 }
00519
00520 // ************************************************************************
00521 // minimizer:
00522
00523 class minimizer
00524 {
00525
00526 public:
00527 // The constructor needs to be passed a reference to an error function.
00528 minimizer(abstract_error_func & aef)
00529 : erf(aef), is_verbose(false), is_very_verbose(false),
00530 target_on(false), target(0.0)
00531 { }
00532
00533 // A virtual destructor ensures proper subclass destruction.
00534 virtual ~minimizer() { }
00535
00536 // Control the verbosity of the minimization routine.
00537 void verbose() { is_verbose = true ; return ;}
00538 void very_verbose() { is_verbose = is_very_verbose = true ; return ;}
00539 void quiet() { is_verbose = is_very_verbose = false ; return ;}
00540
00541 // Set a target error function value. Minimizer should stop when this
00542 // value is achieved. If set_target is not called, the minimizer will use
00543 // some other method to test for convergence.
00544 void set_target(double t) { target = t; target_on = true;} ;
00545 void no_target() {target_on = false;}
00546
00547 // minimize() is where the subclass implements the actual optimization
00548 // algorithm. The user will call this to do a minimization.
00549 virtual double minimize() = 0 ; // call this to do minimization
00550
00551 // stop() is a function which should be called periodically by
00552 // minimize() as it executes (once per iteration, perhaps). It is called
00553 // with a count of the current iteration number, and returns a boolean.
00554 // If stop returns false, then minimize() should continue with its
00555 // calculation. If it returns true, then minimize() should exit
00556 // gracefully as though it had successfully converged, using the best
00557 // parameter set and error function value seen so far. The default
00558 // version provided here always returns false, but is virtual, so it
00559 // may be made more useful in derived minimizer classes.
00560 virtual bool stop(int = 0) { return false; }
00561
00562
00563 protected:
00564 // All minimizers hold a reference to an error function.
00565 abstract_error_func & erf;
00566
00567 // Verbosity flags, give verbose output if is_verbose.
00568 bool is_verbose;
00569 bool is_very_verbose; // additional debugging info is output if set
00570
00571 // The minimizer should compare the error function value to target to test
00572 // for convergence if the following variable is true.
00573 bool target_on;
00574
00575 // Target error function value.
00576 double target;
00577 } ;
00578
00579 #endif /* OPTIMIZER_H */
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7