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

error_func.h

Go to the documentation of this file.
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 // error_func.h
00032 //
00033 // Optimization error function classes for SuperMix. 
00034 //
00035 // Contains:
00036 //   class error_func
00037 //   class error_term
00038 //   class error_term_mode
00039 //   class scaled_match_error_term
00040 //
00041 // Class error_func is a fully-implemented error function class which can
00042 // be used with optimizers derived from class minimizer (optimizer.h). It can
00043 // be used to build complicated error functions involving multiple terms and
00044 // sweeps over parameter ranges and provides for the optimization of any
00045 // number of program variables.
00046 //
00047 // The error term classes are abstract classes which provide the interface
00048 // between a single term in an error function calculation and the full
00049 // calculation performed by class error_func. Concrete implementations of
00050 // these classes for use with error_func can be found in the header file
00051 // error_terms.h. It is also very simple to write your own custom error term
00052 // class derived from one of these classes.
00053 //
00054 // 4/21/99 by John Ward
00055 //
00056 // Based on err_func.h written 7/22/98 J.Z.
00057 //
00058 // 9/21/00: Major error_func structural changes; added get_func_breakdown().
00059 // 9/15/00: Some minor changes, except major ico scaled_match_error_term
00060 // 9/11/00: Changed class simple_error_func to error_func_parameters
00061 // 9/8/00:  Added more modes to error_term_mode; deleted flatness_error_term.
00062 //
00063 // ************************************************************************
00064 // Class error_func
00065 // 
00066 // The concrete class "error_func" is an error function class that should be
00067 // suitable for most SuperMix simulations. Its error function value is built
00068 // up by summing the results from any number of more primitive calculations
00069 // (provided by objects derived from class "error_term"). Each of these
00070 // primitive terms may be individually weighted.
00071 //
00072 // By using sweeper objects (see sweeper.h), error_func can include error
00073 // terms whose values are calculated and summed over a swept range of parameter
00074 // values (such as a sweep over a frequency range); error_func manages the
00075 // sweepers and error terms so that the calculations are performed efficiently
00076 // in the case that multiple terms must be swept using the same sweeper. This
00077 // could be the case, for example, when summing a gain and a noise term over
00078 // a design frequency band. 
00079 //
00080 // error_func is derived from error_func_parameters (see simple_error_func.h)
00081 // which provides the interface between an optimizer and the program parameters
00082 // to be optimized.
00083 //
00084 //
00085 // USAGE:
00086 //
00087 // Construction of a complicated error function calculation for a circuit
00088 // optimization problem using error_func can be divided into 7 steps:
00089 //
00090 //  1. Identify the circuit parameters which may need to be optimized and
00091 //     define variables of type parameter to represent them.
00092 //
00093 //  2. Identify the other parameters which control the circuit operating
00094 //     state (frequency, temperature, etc) and ensure that variables of
00095 //     type parameter represent them as well.
00096 //
00097 //  3. Build the circuit model, using the parameters defined in steps
00098 //     1 and 2 to control its behavior.
00099 //
00100 //  4. Identify the individual circuit characteristics (S11, noise, etc.)
00101 //     that are critical to the performance of the circuit. Choose or
00102 //     write error terms that measure the performance of each characteristic
00103 //     and create the error term objects.
00104 //
00105 //  5. Define sweeper objects which cover the appropriate ranges of the
00106 //     operating state control parameters (from step 2) for the circuit
00107 //     performance goals. Use sweeper::sweep() for parameters to be swept
00108 //     (eg, a frequency sweep) and sweeper::initialize() for parameters
00109 //     to be held constant (eg, SIS bias voltage). Use of initialize() is
00110 //     especially important if one sweeper may be adjusting a control
00111 //     parameter which must then be reset to a specific value for another
00112 //     sweeper.
00113 //
00114 //  6. Create an error_func object. Use its vary() member function to
00115 //     define the allowable limits and initial values for the parameters
00116 //     to be optimized (from step 1). Use its add_term() member function
00117 //     to weight the individual error terms (step 4) and associate them
00118 //     with the appropriate sweepers for the control parameters (step 5).
00119 //
00120 //  7. Pass the error_func object as a parameter to the constructor for
00121 //     the optimizer. The optimizer will communicate with the error
00122 //     function using the abstract_error_func interface defined in
00123 //     optimizer.h
00124 //
00125 // Refer to the header files simple_error_func.h and sweeper.h for more
00126 // information about controlling parameters (steps 1 and 2) using the
00127 // vary() member function (step 6) and sweepers (step 5). Error terms
00128 // (step 4) are described in more detail below; header file error_terms.h
00129 // defines several ready-to-use error term classes suitable for circuit
00130 // performance optimizations.
00131 //
00132 // Once the error function has been created and built, its value is
00133 // calculated using abstract_error_function::operator(). Here's an
00134 // example:
00135 //
00136 //   error_func ef;
00137 //     ...                 // calls to ef.vary() and ef.add_term()
00138 //
00139 //   double error = ef();  // ef() calculates the error function and
00140 //                         // returns its value.
00141 //
00142 // The member function get_func_breakdown() returns a real_vector object
00143 // whose elements contain a term-by-term breakdown of the most recent
00144 // error function calculation, allowing you to check the weighted 
00145 // error contribution of each term.
00146 //
00147 //
00148 // THE vary() MEMBER FUNCTION:
00149 //
00150 // Refer to the description of class error_func_parameters in header file
00151 // simple_error_func.h for a detailed description of the vary() function.
00152 // Here's its declaration and an example of its use, both from that file:
00153 //
00154 //   abstract_real_parameter * vary(double min, double init, double max,
00155 //                                  double units = 1.0);
00156 //
00157 //   parameter R;          // a parameter we need the optimizer to control
00158 //   error_func ef;        // our error function
00159 //   R = ef.vary(10, 25, 100, Ohm);  // Range: 10*Ohm <= R <= 100*Ohm
00160 //                                   // Initial value: R = 25*Ohm
00161 //
00162 //
00163 // THE add_term() MEMBER FUNCTION:
00164 //
00165 // Class error_func builds up a full error function calculation by summing
00166 // individually-weighted terms. These terms may be calculated and averaged
00167 // over one or more sweeps of various operating state parameters. The
00168 // scheme for identifying, weighting and sweeping error terms is described
00169 // to an error_func object by calls to its add_term() member function.
00170 //
00171 // Individual error terms are created using classes derived from class
00172 // error_term (also described in this header file). Operating state
00173 // parameter sweeps are implemented using objects of class sweeper (see
00174 // sweeper.h). add_term() allows error_func to take control of these
00175 // objects.
00176 //
00177 // Here's how to use add_term():
00178 // Assume you've declared 2 error terms (derived from error_term) and
00179 // a sweeper, along with an error_func:
00180 //
00181 //   my_term_1   term1;
00182 //   my_term_2   term2;
00183 //   sweeper     sweep;   // will be used with term2
00184 //   error_func  ef;
00185 //
00186 // Then:
00187 //
00188 //   ef.add_term(2.0, term1);         // a "sweeperless" term
00189 //
00190 // adds term1's error to the error function calculation with weight 2.
00191 // Whenever ef.func_value() is called by the optimizer, term1 is reset and
00192 // asked for its error value before any sweeps are started. Its error
00193 // value is multiplied by its weight (2.0 in this case) and added into
00194 // the error value to be returned by error_func ef.
00195 //
00196 //   ef.add_term(1.0, term2, sweep);  // a term with an associated sweeper
00197 //
00198 // adds term2 to the error function calculation with weight 1. Whenever
00199 // ef.func_value() is called, First sweep and then term2 will be reset, then
00200 // the sweeper will be swept, with term2 being calculated for each point of
00201 // the sweep. The error values returned by term2 will be averaged over the
00202 // total number of points in the sweep. This average value will be
00203 // multiplied by the specified weight (1.0 in this case) and added into the
00204 // error function value to be returned by error_func.
00205 //
00206 // More than one error term may be added with the same sweeper. When
00207 // func_value() executes, it sweeps sweepers with more than one error term
00208 // only once; for each point of the sweep the individual terms are calculated,
00209 // weighted, and added into their individual running sums. The final results
00210 // are divided by the number of points in the sweeper to get an average for
00211 // each term. func_value() uses the state_tag argument to errror_term::get()
00212 // to try to maximize the efficiency of the calculations (see the description
00213 // of class error_term).
00214 //
00215 // The algorithm for error_func::func_value() is described in more detail
00216 // in the declaration of class error_func.
00217 //
00218 //
00219 // THE get_func_breakdown() MEMBER FUNCTION:
00220 //
00221 // Once the error function has been calculated, calling get_func_breakdown()
00222 // returns a real_vector object (see SuperMix's vector.h) containing a
00223 // term-by-term breakdown of the error function value. Each element of the
00224 // real_vector contains the weighted error contribution of a single error
00225 // term created by a call to add_term(). The real_vector uses the Index_1
00226 // indexing mode (first valid element has index 1); the first element holds
00227 // the weighted result of the term added by the first call to add_term().
00228 // The breakdown can be displayed using "<<" for real_vectors, so:
00229 //
00230 //   cout << ef.get_func_breakdown() << endl;
00231 //
00232 // outputs the term-by-term breakdown on a single line, the values separated
00233 // by " ". 
00234 //
00235 // ************************************************************************
00236 // class error_term
00237 //
00238 // Class error_term is an abstract class that provides the interface between
00239 // simple error function terms and class error_func. Actual, useful, concrete
00240 // subclasses of error_term can be found in the file error_terms.h.
00241 //
00242 //
00243 // USAGE: WRITING YOUR OWN ERROR TERMS USING ERROR_TERM
00244 //
00245 // Defining your own error terms is very simple: just derive a class from
00246 // error_term in which you define the virtual function get(). Better yet,
00247 // check out abstract class error_term_mode (described below). This latter
00248 // class may actually be the class of choice for deriving your own error
00249 // terms. If you don't need the added sophistication of error_term_mode,
00250 // here's an example of an error term derived from class error_term:
00251 //
00252 // Suppose you have a function f(p1,p2) that you need to minimize. Then all
00253 // you would need in order to define an error term for this function is:
00254 //
00255 //    // Define the new error term class:
00256 //
00257 //    class my_term_class : public error_term {
00258 //    public:
00259 //
00260 //      // get() must return an error value given the current program
00261 //      // state (eg, the current values of p1 and p2 for this example)
00262 //
00263 //      double get(state_tag) { return f(p1,p2); }
00264 //
00265 //    };   // don't forget the ";" after the "}"
00266 //
00267 //
00268 //    // create an actual error term object (my_term) using the class:
00269 //
00270 //    my_term_class   my_term;  
00271 //
00272 // where f(), p1, and p2 are global identifiers declared somewhere previously
00273 // in the source. Note that in this example we ignore the state_tag argument
00274 // in the call to get(). The use of state_tags is described later.
00275 //    
00276 // IMPORTANT:  Try to avoid side effects in derived classes of error_term.
00277 // An error term's get() function should attempt to leave the system in
00278 // the same state as before get() was called to prevent one error_term from
00279 // affecting another in a single error function calculation involving
00280 // multiple error terms.
00281 //
00282 //
00283 // USE OF THE error_term::reset() FUNCTION
00284 //
00285 // Some error term calculations involve saving results from previous get()
00286 // calls. This is useful if the function is performing some running sum
00287 // over a parameter sweep, for example, which it uses in its calculation.
00288 // The virtual function reset() is used to tell the error term that it
00289 // should clear any such previous results and prepare to start over. It is
00290 // called by class error_func, for example, before it begins a parameter
00291 // sweep. The default error_term::reset() does nothing, so if you don't
00292 // need the reset capability for your error term, then ignore it.
00293 //
00294 //
00295 // USE OF THE STATE_TAG ARGUMENT
00296 //
00297 // A state_tag is used to avoid repeating a lengthy function calculation
00298 // when more than one error term relies on the results of that calculation
00299 // for its error term value. Refer to the brief intro to state tags in the
00300 // header file state_tag.h before proceeding.
00301 //
00302 // Let's consider a specific example involving a circuit calculation,
00303 // although the state_tag mechanism could be useful in other contexts as
00304 // well. Assume your error function calculation needs to know the gain and
00305 // the noise of the circuit at a single operating condition (specific set
00306 // of program variable values). The circuit returns both gain and noise
00307 // when it calculates its response; this may be a complicated, lengthy
00308 // calculation that you wouldn't want to have the program repeat
00309 // unnecessarily. However, you use two error_term objects, one for gain
00310 // and one for noise. By using state_tag arguments, you can have each
00311 // term call the circuit's response function and still avoid the
00312 // recalculation.
00313 //
00314 // The idea is this: you define the response function (which calculates
00315 // both noise and gain, both returned in some data structure) so that it
00316 // accepts a state_tag argument. When the function is called, it compares
00317 // the state_tag argument to a saved copy of the argument provided on the
00318 // previous function call; if the two state_tags match, then the function
00319 // assumes that none of the parameters on which it depends has changed.
00320 // In this case it can just return a copy of the previously returned
00321 // output rather than perform a recalculation. This is the way that an
00322 // nport object's get_data(state_tag) member function works (see nport.h).
00323 //
00324 // As for an error_term implementation, all you would do is pass on the
00325 // state_tag argument in the error_term::get(state_tag) function to the
00326 // response function you are calling (it, of course, has to be defined so
00327 // that it accepts the state_tag argument as well). The error_term objects
00328 // just assume that the caller of get() knows what it is doing if it
00329 // sends along the same state_tag value to more than one get() call.
00330 //
00331 // ************************************************************************
00332 // class error_term_mode
00333 //
00334 // In many cases the function to be optimized must not be simply minimized,
00335 // but must be made to match, stay below, or exceed a given target value.
00336 // This class provides the calculating muscle to perform these or similar
00337 // optimizations using an error term.
00338 //
00339 // Class error_term_mode is a much-refined derivative of class error_term.
00340 // Most of the concrete error terms in error_terms.h are derived from this
00341 // class. It provides various "modes" for calculating an error term based
00342 // on a comparison of a function value and a target. These modes are
00343 // designed to be used in error function calculations using error_func with
00344 // sweepers.
00345 //
00346 //
00347 // CALCULATION OF THE ERROR VALUE:
00348 //
00349 // The basic error value (e) is given by the square of the difference between
00350 // a function value (f) and a target value (t). How this value is used in the
00351 // calculation of the returned error value is determined by the mode that has
00352 // been set:
00353 //
00354 //   Mode                    Returned Error Value
00355 //   ----                    --------------------
00356 //   MATCH, M_MATCH, FLAT    return e
00357 //   ABOVE, M_ABOVE          if (f < t) return e; else return 0
00358 //   BELOW, M_BELOW          if (f > t) return e; else return 0
00359 //
00360 // The target value is set by the user before the error term's get() function
00361 // is called, for all modes except FLAT. In the case of mode FLAT, the target
00362 // value is calculated internally by the error term. The error calculation is
00363 // performed by error_term_mode::checkval(double), which considers the mode,
00364 // the target, and any internally saved results of previous error
00365 // calculations. Its argument is the function value; it returns the
00366 // calculated error:
00367 //
00368 //   checkval(double f);   // using the saved target value and other data
00369 //                         // (depending on the error mode), return the
00370 //                         // error value generated by function value f.
00371 //
00372 //
00373 // DETAILED MODE DESCRIPTIONS:
00374 //
00375 //   MATCH, ABOVE, BELOW:
00376 //    A fixed target value is specified by the user. Anytime checkval() is
00377 //    called, the argument is compared with the target and an error value
00378 //    is generated as described in the table above. These modes have no
00379 //    "memory" of previous error values returned. When error_func sweeps
00380 //    an error term using one of these modes, it calculates the average
00381 //    value of the error over the points in the sweep.
00382 //
00383 //   M_MATCH, M_ABOVE, M_BELOW:
00384 //    A fixed target value is specified by the user. These modes are
00385 //    designed to be used in an error term with a sweeper. When error_func
00386 //    sweeps an error term using one of these modes, then instead of
00387 //    calculating the average value of the error over the sweep, it
00388 //    calculates the MAXIMUM ERROR VALUE seen during the sweep. The code
00389 //    in checkval() ensures that this result is returned by keeping a
00390 //    running tally of the number of points seen so far in the sweep and
00391 //    the maximum error value seen (both internal variables are cleared
00392 //    by the reset() member function). When a new maximum error is
00393 //    encountered, checkval() returns that value plus a correction which
00394 //    compensates for the lower error values it had returned on previous
00395 //    calls. Because of this correction, when error_func calculates the
00396 //    mean error value upon sweep completion, the result is the maximum
00397 //    error value encountered during the sweep. ( the M_ prefix is a
00398 //    mnemonic for "maximum error").
00399 //
00400 //   FLAT:
00401 //    Like the M_-prefixed modes, mode FLAT is designed to be used in an
00402 //    error term with a sweeper. Unlike the other modes, no fixed target
00403 //    value need be specified; FLAT uses the mean value of the function
00404 //    as the target value, so this error term mode measures the "flatness"
00405 //    of the function value over the range of a sweep. The code in
00406 //    checkval() essentially keeps a running calculation of the function
00407 //    mean value. When it returns an error value, it also includes a
00408 //    correction for all previously returned values to compensate for
00409 //    changes in the function's mean as the sweep proceeds. Consequently,
00410 //    when error_func calculates the mean error value upon sweep completion,
00411 //    the result is the mean squared deviation from the mean of the
00412 //    function value. Calling reset() sets up the error term to start the
00413 //    calculation over again from scratch.
00414 //
00415 // IMPORTANT:  One must be precise when defining "flat."  Returning a 
00416 // simple value, such as the magnitude of S21, will minimize the absolute
00417 // deviation from flatness. This may have the unwanted side effect of making
00418 // S21 go to zero. To avoid this problem, either include another error term
00419 // which gets large if S21 gets too small, or optimize the flatness of
00420 // log(S21).  This way, the fractional deviation from flatness will be
00421 // minimized instead of the absolute deviation.
00422 //
00423 //
00424 // USAGE:
00425 //
00426 // Use one of the provided error terms derived from class error_term_mode
00427 // (see error_terms.h) or derive a new class of your own. Set the error
00428 // term mode and target value using error_term_mode member functions or
00429 // whatever other methods are available for the specific error term you
00430 // are using. Add the error term to an error_func object using
00431 // error_func::add_term().
00432 //
00433 // Member Functions for Setting the Target and Mode:
00434 //
00435 //   target(t);       // set the target value to t (a double)
00436 //
00437 //   match()          // set the mode as indicated; target is unchanged
00438 //   above()
00439 //   below()
00440 //   flat()
00441 //   worst_match()    // set mode to M_MATCH
00442 //   worst_above()    // M_ABOVE
00443 //   worst_below()    // M_BELOW
00444 //
00445 //   match(t)         // set both the mode and target (t a double)
00446 //   above(t)
00447 //   below(t)
00448 //   worst_match(t)
00449 //   worst_above(t)
00450 //   worst_below(t)
00451 //
00452 // Each of the above functions returns a reference to error_term_mode which
00453 // refers to the error term object, so they can be concatenated using ".":
00454 //   ef.match().target(10);  is the same as:  ef.match(10);
00455 //
00456 //
00457 // WRITING YOUR OWN error_term_mode CLASS:
00458 //
00459 // Here's an example, similar to the one included for class error_term.
00460 // Again assume you have some function f(p1,p2) to be optimized, only this
00461 // time you want to compare its value to a target using the capabilities
00462 // of class error_term_mode. You could write: 
00463 //
00464 //    class my_term_class : public error_term_mode {
00465 //    public:
00466 //
00467 //      // get() uses error_term_mode::checkval() to do the comparison:
00468 //      double get(state_tag) { return checkval(f(p1,p2)); }
00469 //
00470 //    } my_term;  // the actual error term object is "my_term"
00471 //
00472 // where f(), p1, and p2 are global identifiers declared somewhere previously
00473 // in the source. Note that in this example we ignore the state_tag argument
00474 // in the call to get(). Now we can use our object my_term with an error_func:
00475 //
00476 //    error_func ef;
00477 //    sweeper sweep;
00478 //    ef.add_term(1.0, my_term, sweep);
00479 //    my_term.above(0.5);
00480 //
00481 // If you would like to be able to initialize the mode and target to some
00482 // particular combination at construction, then you could include a constructor
00483 // in your class definition:
00484 //
00485 //    my_term_class(error_term_mode::mode m, double t)
00486 //      : error_term_mode(m,t) { }
00487 //
00488 // The type error_term_mode::mode is an enumeration of the available modes:
00489 //
00490 //    enum error_term_mode:mode
00491 //         {MATCH, ABOVE, BELOW, FLAT, M_MATCH, M_ABOVE, M_BELOW};
00492 //
00493 // ************************************************************************
00494 // class scaled_match_error_term
00495 //
00496 // Class scaled_match_error_term is an abstract class that provides an
00497 // error function term to compare the shape of two curves which may not have
00498 // the same scale. For example, it is used by class fts_match (error_terms.h)
00499 // which compares a measured mixer FTS response in arbitrary units to that of
00500 // a simulated mixer. It is meant to be used by error_func with a sweeper.
00501 //
00502 // USAGE:
00503 //
00504 // Derive a class from this class in which you implement functions get_a()
00505 // and get_b(), where:
00506 //
00507 //   double get_a(state_tag); // returns values for the reference data
00508 //   double get_b(state_tag); // returns values for the data to be scaled
00509 //
00510 // IMPORTANT:  Note that get_b() values will be scaled to match get_a()
00511 // values. Beware that if the get_a() values are allowed to go to zero under
00512 // control of the optimizer, then the calculation will find a scale factor
00513 // for the get_b() values equal to zero as well, resulting in a very small
00514 // error value. To avoid this limitation, the function get_a() should not be
00515 // changeable by the optimizer, but should represent a fixed reference
00516 // function. For example, get_a() may return data read from a file.
00517 //
00518 // The error calculation for the scaled match is:
00519 //
00520 //            Sum[(get_a() - K*get_b())*(get_a() - K*get_b())]
00521 //   error = --------------------------------------------------
00522 //                         Sum[get_a()*get_a()]
00523 //
00524 // Where "Sum[]" represents a sum over all terms, and we scale the return
00525 // values from get_b() by the factor K to best match the return values from
00526 // get_a(). The error = 0 if the get_a() all vanish, since K = 0 gives a
00527 // perfect match regardless of the values of get_b(). Otherwise, the K which
00528 // results in the best match is given by:
00529 //
00530 //   K = Sum[get_a()*get_b()]/Sum[get_b()*get_b()]
00531 //
00532 // Using this formula for the scale factor, we must have:
00533 //
00534 //   0.0 <= error <= 1.0
00535 //
00536 // If the get_b() all vanish, then K is undefined and error = 1.0. Since
00537 // the error will be less than 1.0 even if the match is terrible, you will
00538 // want to adjust the weight used with error_func::add_term() appropriately.
00539 // A weight of ~100 might be a good starting value, depending on what other
00540 // error terms you are also including in the error function. 
00541 //
00542 // The scale factor that minimizes the error can be accessed using the
00543 // member function scale():
00544 //
00545 //   double scale() const;  // return the scale factor for get_b() data
00546 //
00547 // Since error_func will sum the error values returned by the error term
00548 // during a sweep, scaled_match_error_term::get() only returns an error
00549 // increment at each iteration. Since error_func divides by the number of
00550 // points in a sweep to calculate an average, scaled_match_error_term
00551 // inflates the error by a factor equal to the number of get() calls to
00552 // compensate. The term's internal registers are reset by the member
00553 // function reset(); if your derived class needs to overload reset() in
00554 // order to perform its own internal housekeeping, then your reset() must
00555 // remember to call the function scaled_match_error_term::zero() so that
00556 // the scaled_match_error_term registers are properly reset. 
00557 //
00558 // ************************************************************************
00559 
00560 #ifndef ERROR_FUNC_H
00561 #define ERROR_FUNC_H
00562 
00563 #include <vector>     // STL vector template class
00564 #include <map>        // STL associative array template class
00565 
00566 #include "simple_error_func.h"
00567 #include "state_tag.h"
00568 #include "sweeper.h"
00569 
00570 
00571 // ************************************************************************
00572 class error_term
00573 {
00574 public:
00575 
00576   // This is the interface. Calculate error function term.
00577   virtual double get(state_tag) = 0;
00578 
00579   // The method reset() is called before a sweep is started.  It is normally
00580   // not needed.  Some error terms, such as flatness_error_term, must keep
00581   // running sums during a sweep.  For them, reset clears these running
00582   // sums to 0.
00583   virtual void reset() { }
00584 
00585   // Virtual destructor is necessary to ensure proper subclass destruction.
00586   virtual ~error_term() { }
00587 };
00588 
00589 
00590 // ************************************************************************
00591 class error_func : public error_func_parameters
00592 {
00593 
00594 public:
00595 
00596   // The add_term() member function, the major addition to the error function
00597   // interface provided by class error_func:
00598 
00599   // Add a simple, "sweeperless" error term.
00600   void add_term(double weight, error_term & et);
00601 
00602   // Add an error term whose values will be averaged over the points of the 
00603   // associated sweeper. The function allows the sweeper and error term
00604   // arguments to be listed in either order.
00605   void add_term(double weight, error_term & et, sweeper & swp);
00606   void add_term(double weight, sweeper & swp, error_term & et)
00607     { add_term(weight,et,swp); }
00608 
00609   // This function breaks down an error_func return value (calculated by
00610   // error_func::func_value()) into a real_vector of component terms, each
00611   // of which holds the contribution to the error function value from a
00612   // term added with add_term(). The first (lowest index) entry contains
00613   // the contribution of the earliest add_term() call; the last to the
00614   // latest add_term() call.
00615   real_vector get_func_breakdown() const;
00616 
00617 
00618   // Refer to simple_error_func.h for the use of the vary() member function,
00619   // which error_func inherits.
00620 
00621 
00622   // the constructor:
00623   // Refer to the definition of abstract_error_func in optimizer.h for the
00624   // purpose of the argument no_limits_flag. Just using the default value
00625   // (ie, don't provide a constructor argument) is appropriate in nearly all
00626   // cases.
00627   error_func(bool no_limits_flag = false)
00628     : error_func_parameters(no_limits_flag) { }
00629 
00630 
00631   // func_value(): the only virtual function of abstract_error_func which
00632   // still needs to be defined.
00633 
00634   double func_value();
00635   // Returns the final error function, after summing over all error terms,
00636   // sweepers, etc. Calls error terms via their associated weighted_term
00637   // objects held in error_func::terms. func_value() algorithm: When called,
00638   // func_value() does the following:
00639   //  (1) initializes its return value accumulator to 0.0
00640   //  (2) gets a new state_tag for the "sweeperless" terms
00641   //  (3) Loop: for each "sweeperless" term added using add_term():
00642   //      (3.1) call the weighted_term's reset(),
00643   //            which clears its result and resets the error_term
00644   //      (3.2) call the weighted_term's get(state_tag), which:
00645   //            (3.2.1) calls the term's error_term::get(state_tag)
00646   //            (3.2.2) weights the error and adds it into the term's result
00647   //      (3.3) add the term's result into the return value
00648   //  (4) Loop: for each unique sweeper identified by an add_term():
00649   //      (4.1) reset the sweeper using its sweeper::reset()
00650   //      (4.2) call the associated sweeper_info::reset_terms(), which:
00651   //            (4.2.1) Loop: for each term added using this sweeper:
00652   //                    (4.2.1.1) call the weighted_term's reset()
00653   //      (4.3) Loop: until sweeper::is_finished() goes true:
00654   //            (4.3.1) get a new state_tag
00655   //            (4.3.2) call the associated sweeper_info::calc_terms(), which:
00656   //                    (4.3.2.1) Loop: for each term added using this sweeper: 
00657   //                              (4.3.2.1.1) weighted_term::get(state_tag)
00658   //            (4.3.3) increment sweeper
00659   //      (4.4) call the associated sweeper_info::get_error(), which:
00660   //            (4.4.1) Loop: for each term added using this sweeper: 
00661   //                    (4.4.1) divide result by the number of sweeper points
00662   //                    (4.4.2) add the result into the return value
00663   //  (5) return the accumulated return value
00664 
00665 
00666 private:
00667 
00668   // This class takes care of multiplying error terms by weighting factors
00669   // and maintaining accumulators for their error contributions
00670   class weighted_term
00671   {
00672   public:
00673     double weight;                 // weight of this term
00674     error_term * et;               // pointer to the function
00675     double result;                 // accumulate the result for this term  
00676 
00677     // The constructor initializes parameters.
00678     weighted_term(double w, error_term & etr) : weight(w), et(&etr), result(0.0) { }
00679 
00680     // Reset the term and clear the accumulator
00681     weighted_term & reset() { result = 0.0; et->reset(); return *this; }
00682 
00683     // Calculate and the weighted error and add into the accumulator.
00684     weighted_term & get(state_tag s) { result += weight*(et->get(s)); return *this; }
00685   } ;
00686 
00687   // to make the code a bit more readable, we add typedefs using weighted_term :
00688   typedef  std::vector<error_func::weighted_term>  term_list;
00689   typedef  term_list::size_type                    term_index;
00690   typedef  std::vector<term_index>                 term_index_list;
00691   typedef  term_index_list::size_type              term_index_list_index;
00692 
00693   // This class has the information on terms for a single sweeper. It keeps a
00694   // record of the weighted_terms which use the sweeper, and a few functions
00695   // which loop over all of these associated terms.
00696   class sweeper_info
00697   {
00698   public:
00699     // The terms vector keeps track of all the weighted_terms to be summed
00700     // by this sweeper. It holds indexes into the container with all terms.
00701     error_func::term_index_list sweeper_terms;
00702 
00703     // Method reset() loops through sweeper_terms, calling reset() for each.
00704     // It is called with a reference to error_func::terms
00705     void reset_terms(error_func::term_list &);
00706 
00707     // Method get_terms loops through sweeper_terms, calling get() for each.
00708     void calc_terms(state_tag, error_func::term_list &);
00709 
00710     // Method get_error averages the terms by dividing each term's result
00711     // by npoints; it adds them all and returns the sum
00712     double get_error(int npoints, error_func::term_list &);
00713   };
00714   
00715 
00716   // Here we store all the weighted_terms added using add_term:
00717   term_list terms;
00718 
00719   // Here we store all the sweepers and their associated information in an
00720   // STL associative array (map)
00721   std::map<sweeper *, sweeper_info> swp_map ;
00722 
00723   // Keep a vector of all the terms that don't have sweepers.
00724   term_index_list sweeperless_terms;
00725 
00726 } ;
00727 
00728 
00729 // ************************************************************************
00730 class error_term_mode : public error_term
00731 {
00732 public:
00733   enum mode {MATCH, ABOVE, BELOW, FLAT, M_MATCH, M_ABOVE, M_BELOW};
00734 
00735   // Constructor sets mode and target, initializes other values to 0.
00736   // If the mode is FLAT, then target_val will be ignored.
00737   error_term_mode(mode m = MATCH, double t = 0.0):
00738     flag(m), target_val(t)
00739   { reset(); }
00740 
00741   // Method to set the target.
00742   error_term_mode & target(double t) { target_val = t; return *this; }
00743 
00744   // The following methods may be called to set the mode.
00745   error_term_mode & match() {flag = MATCH; return *this;}
00746   error_term_mode & above() {flag = ABOVE; return *this;}
00747   error_term_mode & below() {flag = BELOW; return *this;}
00748   error_term_mode & flat()  {flag = FLAT;  return *this;}
00749   error_term_mode & worst_match() {flag = M_MATCH; return *this;}
00750   error_term_mode & worst_above() {flag = M_ABOVE; return *this;}
00751   error_term_mode & worst_below() {flag = M_BELOW; return *this;}
00752 
00753   // The following methods may be called to set both the mode and target.
00754   error_term_mode & match(double t) {flag = MATCH; target_val = t; return *this;}
00755   error_term_mode & above(double t) {flag = ABOVE; target_val = t; return *this;}
00756   error_term_mode & below(double t) {flag = BELOW; target_val = t; return *this;}
00757   error_term_mode & worst_match(double t) {flag = M_MATCH; target_val = t; return *this;}
00758   error_term_mode & worst_above(double t) {flag = M_ABOVE; target_val = t; return *this;}
00759   error_term_mode & worst_below(double t) {flag = M_BELOW; target_val = t; return *this;}
00760 
00761   // Compute the error for the given mode.
00762   double checkval(double x);
00763 
00764   // Reset is called before a sweep, and clears all memory of past calculations.
00765   void reset()
00766   {
00767     sum_xx = 0.0;
00768     sum_x = 0.0;
00769     n = 0;
00770     old_error = 0.0;
00771   }
00772 
00773   // Virtual destructor is necessary to ensure proper subclass destruction.
00774   virtual ~error_term_mode() { }
00775 
00776 private:
00777   // Which type of error to calculate.
00778   mode flag;
00779 
00780   // Target for MATCH, minimum for ABOVE, etc.
00781   // If the mode is FLAT, then target_val is ignored.
00782   double target_val;
00783 
00784   // The following variables are used for FLAT, M_MATCH, M_ABOVE, M_BELOW.
00785   double sum_xx;      // Keep a running sum of the squares of the values.
00786   double sum_x;       // Keep a running sum of the values.
00787   unsigned n;         // The number of points since the last reset() call.
00788   double old_error;   // The value of the error from the last iteration.
00789 
00790 };
00791 
00792 
00793 // ************************************************************************
00794 class scaled_match_error_term : public error_term
00795 {
00796 protected:
00797   // Zero is called by reset, and clears all running sums to 0.
00798   // This function is provided for subclasses that overload reset().
00799   void zero()
00800   {
00801     sum_aa = 0.0;
00802     sum_bb = 0.0;
00803     sum_ab = 0.0;
00804     old_error = 0.0;
00805     n = 0;
00806   }
00807 
00808 public:
00809   // Constructor sets initial values to 0.
00810   scaled_match_error_term() :
00811   sum_aa(0.0), sum_bb(0.0), sum_ab(0.0), old_error(0.0), n(0)
00812   { }
00813 
00814   // Reset is called before a sweep, and clears all running sums to 0.
00815   // Any derived classes that implement reset() must remember to call zero().
00816   virtual void reset() { zero(); }
00817 
00818   // Return the values that we want to match.
00819   // These are the functions that must be defined in concrete subclasses.
00820 
00821   virtual double get_a(state_tag) = 0;  // The reference data
00822   virtual double get_b(state_tag) = 0;  // The data to be scaled and compared
00823 
00824   // This function returns the scale factor for b to make it match a
00825   double scale() const
00826   { return (sum_bb == 0.0 && sum_ab == 0.0) ? 1.0 : sum_ab/sum_bb; }
00827 
00828   // The method get will calculate the error function by calling get_value.
00829   // It should not be modified or redefined in subclasses.
00830   double get(state_tag);
00831 
00832   // Virtual destructor is necessary to ensure proper subclass destruction.
00833   virtual ~scaled_match_error_term() { }
00834 
00835 private:
00836   double sum_aa;      // Keep a running sum of the squares of value a.
00837   double sum_bb;      // Keep a running sum of the squares of value b.
00838   double sum_ab;      // Keep a running sum of (value a) * (value b).
00839   double old_error;   // The value of the error from the last iteration.
00840   unsigned n;         // iteration counter
00841 };
00842 
00843 #endif /* ERROR_FUNC_H */

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