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
1.2.7