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

error_func.cc

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.cc
00032 //
00033 // Optimization error function class for SuperMix.
00034 //
00035 // See file error_func.h for more information.
00036 //
00037 // 4/21/99 by John Ward
00038 //
00039 // 9/21/00:  Major changes to error_func algoithms to match data structures
00040 // 9/15/00:  Some minor changes, except major ico scaled_match_error_term
00041 // 9/8/00:   Removed flatness_error_term.
00042 // 3/20/00:  Adjusted swept error term values by dividing by the number
00043 //           of points in the sweep in error_func::func_value()
00044 //
00045 // Based on err_func.cc written 7/22/98 J.Z.
00046 //
00047 // ************************************************************************
00048 
00049 #include "error_func.h"
00050 #include "error.h"
00051 
00052 void error_func::add_term(double weight, error_term & et, sweeper & swp)
00053 {
00054   // make an entry in the master terms vector:
00055   terms.push_back(error_func::weighted_term(weight, et));
00056   // put the index of this term in the associated sweeper's terms vector:
00057   (swp_map[&swp]).sweeper_terms.push_back(terms.size() - 1) ;
00058 }
00059 
00060 void error_func::add_term(double weight, error_term & et)
00061 {
00062   // make an entry in the master terms vector:
00063   terms.push_back(error_func::weighted_term(weight, et));
00064   // put the index of this term in the sweeperless_terms vector:
00065   sweeperless_terms.push_back(terms.size() - 1);
00066 }
00067 
00068 real_vector error_func::get_func_breakdown() const
00069 {
00070   real_vector result(terms.size());
00071   int i;
00072   term_index j;
00073   for(i = result.minindex(), j = 0; i <= result.maxindex(); i++, j++)
00074     result[i] = terms[j].result;
00075   return result;
00076 }
00077 
00078 double error_func::func_value()
00079 {
00080   double retval = 0. ;
00081 
00082   // Loop over the terms that don't have sweepers.
00083   state_tag tag = state_tag::get_tag();
00084   for(term_index_list_index i = 0; i < sweeperless_terms.size(); i++)
00085     retval += terms[sweeperless_terms[i]].reset().get(tag).result;
00086 
00087   // loop over all sweepers
00088   std::map<sweeper *, error_func::sweeper_info>::iterator is ;
00089   for(is=swp_map.begin(); is != swp_map.end(); is++) {
00090 
00091     // get a reference to this sweeper and its sweeper_info
00092     sweeper &       swp     = *(*is).first ;
00093     sweeper_info &  errors  =  (*is).second;
00094 
00095     // First reset the sweeper, so parameters are initialized
00096     swp.reset();
00097 
00098     // Now reset the error terms for this sweeper.
00099     errors.reset_terms(terms);
00100 
00101     // now loop over this sweeper's parameter range
00102     for(; !swp.finished(); swp++) {
00103       tag = state_tag::get_tag();
00104       errors.calc_terms(tag, terms) ;
00105     }
00106 
00107     // average the values of the terms
00108     retval += errors.get_error(swp.npoints(), terms);
00109   }
00110   return retval ;
00111 }
00112 
00113 
00114 void error_func::sweeper_info::reset_terms(error_func::term_list & terms)
00115 {
00116   // Loop through the error terms, calling their reset methods.
00117   for(error_func::term_index_list_index i = 0; i < sweeper_terms.size(); i++)
00118     terms[sweeper_terms[i]].reset();
00119 }
00120 
00121 void error_func::sweeper_info::calc_terms(state_tag t, error_func::term_list & terms)
00122 {
00123   // Loop through the error terms, calling their get methods.
00124   for(error_func::term_index_list_index i = 0; i < sweeper_terms.size(); i++)
00125     terms[sweeper_terms[i]].get(t);
00126 }
00127 
00128 double error_func::sweeper_info::get_error(int n, error_func::term_list & terms)
00129 {
00130   double retval = 0. ;
00131   // Loop through the terms, dividing their results by n and adding them up
00132   for(error_func::term_index_list_index i = 0; i < sweeper_terms.size(); i++) {
00133     terms[sweeper_terms[i]].result /= n;
00134     retval += terms[sweeper_terms[i]].result;
00135   }
00136   return(retval) ;
00137 }
00138 
00139 
00140 double error_term_mode::checkval(double x)
00141 {
00142   // If we are not optimizing for FLAT, we want to compute the error
00143   // based on the target value.
00144   if (flag != FLAT)
00145     x -= target_val;
00146 
00147   double new_error, return_value;  // used by some cases below
00148 
00149   switch(flag) {
00150 
00151     // the easy ones first...
00152 
00153   default:
00154     error::warning("Unknown mode setting in error_term_mode::checkval");
00155     return 0.;
00156 
00157   case MATCH:  return x*x;
00158   case ABOVE:  return (x < 0.) ? x*x : 0.;
00159   case BELOW:  return (x > 0.) ? x*x : 0.;
00160 
00161 
00162     // now the ones that need a memory of past values:
00163 
00164   case FLAT: {
00165     // Update the sum, sum of the squares, and counter.
00166     sum_xx += x*x;
00167     sum_x += x;
00168     n++;
00169 
00170     // Find the new value of the variance from the mean
00171     new_error = sum_xx - sum_x*sum_x/n;
00172   
00173     // We will only return the increase of the total error function,
00174     // since the caller is keeping a running sum.
00175     return_value = new_error - old_error;
00176   
00177     // Update old_error so that it will be correct for the next iteration.
00178     // Notice that we increment old_error rather than replace by new_error.
00179     // That way our old_error matches the caller's running sum, and maybe we
00180     // can minimize truncation errors that way. 
00181     old_error += return_value;
00182     return return_value;
00183   }
00184 
00185     // the following cases leave the switch without returning from the function:
00186   case M_ABOVE:
00187     new_error = (x < 0.) ? x*x : 0.;
00188     break;
00189   case M_BELOW:
00190     new_error = (x > 0.) ? x*x : 0.;
00191     break;
00192   case M_MATCH:
00193     new_error = x*x;
00194     break;
00195   } // switch
00196 
00197   // The modes M_ABOVE, M_BELOW, and M_MATCH get here,
00198   // with properly set value for new_error:
00199 
00200   n++;  // calls counter
00201     
00202   if (new_error > old_error) {
00203     // Oops, a new maximum error has been found.
00204 
00205     // The value returned by all calls should be the maximum error found;
00206     // since earlier calls returned values that were too small, we correct
00207     // by including the correction for all those previous calls as well. 
00208     return_value = n*new_error - (n-1)*old_error;
00209 
00210     // Update old_error so that it will be correct for the next iteration.
00211     old_error = new_error;
00212     return return_value;
00213   }
00214   else
00215     // Nothing has changed; the old maximum is still the maximum so far.
00216     return old_error;
00217 }
00218 
00219 
00220 double scaled_match_error_term::get(state_tag tag)
00221 {
00222   // Get the values.
00223   double a = get_a(tag);
00224   double b = get_b(tag);
00225 
00226   // Error = Sum[(a - k*b)*(a - k*b)],
00227   //   with k chosen to minimize the error. The value of the scale
00228   //   factor k is therefore:
00229   // k = Sum[a*b]/Sum[b*b].
00230   //   with this value for k, the formula for the error is:
00231   // Error = Sum[a*a] - Sum[a*b]*Sum[a*b]/Sum[b*b]
00232   //       = N*<a*a>*(1 - (<a*b>*<a*b>)/(<a*a>*<b*b>))
00233   //   Where <x> indicates the mean value of the expression x. Note
00234   //   that since error_func divides the error by N, the number of
00235   //   points in the sweep, the error term contibution will be
00236   //   independent of the number of points in the sweeper, although
00237   //   it WILL depend on the mean value of the square of a, the
00238   //   reference data. By dividing out this mean square value, we
00239   //   can get an error term which is independent of the actual
00240   //   overall scale of the reference data as well. Therefore,
00241   //   we actually use the formula:
00242   // Error = N*(1 - (Sum[a*b]*Sum[a*b])/(Sum[a*a]Sum[b*b]))
00243   //   once error_func divides this value by N, we see that we
00244   //   get an error contribution that must be between 0 and 1.
00245 
00246   // We save the error we calculate. When we get the next get()
00247   // call, we calculate a new error and return the difference
00248   // between it and the error we saved. That way if the caller
00249   // sums the return values, his running sum will reflect the
00250   // true error (except for inaccuracies due to roundoff errors).
00251 
00252   // Update the sums.
00253   sum_aa += a*a;
00254   sum_bb += b*b;
00255   sum_ab += a*b;
00256   n++;
00257 
00258   // Find the new value of the error function. We check for pathological
00259   // cases.
00260   double new_error;
00261   if (sum_aa == 0.0)
00262     new_error = 0.0;
00263   else if (sum_bb == 0.0)
00264     new_error = 1.0;
00265   else {
00266     new_error = 1.0 - sum_ab*sum_ab/(sum_aa*sum_bb);
00267     if (new_error < 0.0) new_error = 0.0;
00268   }
00269   new_error *= n;  // compensate for error_func averaging
00270 
00271 
00272   // We will only return the change in the total error function,
00273   // since the caller is keeping a running sum.
00274   double change = new_error - old_error;
00275 
00276   // Update old_error so that it will be correct for the next iteration.
00277   // Notice that we increment by change rather than replace by new_error.
00278   // That way our old_error matches the caller's running sum, and maybe we
00279   // can minimize truncation errors that way. 
00280   old_error += change;
00281 
00282   // Return the change in the error function.
00283   return change;
00284 }
00285 

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