Main Page | Namespace List | Class List | File List | Class Members | File Members

EvoFunc.h

Go to the documentation of this file.
00001 //
00002 // $Id: EvoFunc.h,v 1.3 2004/11/29 14:37:10 min Exp min $
00003 //
00004 
00005 #ifndef __EVOFUNC_H
00006 #define __EVOFUNC_H
00007 
00008 #include <iostream>
00009 #include <fstream>
00010 #include <vector>
00011 #include <math.h>
00012 #include "map_functions/Map.h"
00013 #include "Population.h"
00014 
00015 using namespace std;
00016 
00017 // allows you to have a "EvoView" class which has access to EvoFunc's members (see below)
00018 class EvoView;  
00019 
00020 
00021 
00022 
00023 
00024 template<class Traits, class ParTraits>
00025 class EvoFunc
00026 {
00027 
00028 public:
00029 
00030   typedef typename Traits::SourceType SourceType;
00031   typedef typename Traits::TransformedSourceType TransformedSourceType;
00032   typedef typename Traits::TargetType TargetType;
00033 
00034   typedef typename Traits::MapType MapType;
00035   typedef typename Traits::ErrorType ErrorType;
00036 
00037   
00038   EvoFunc(SourceType& source, TargetType& target, const Traits& evo_traits);
00039   EvoFunc(SourceType& source, TransformedSourceType& transformed_source, TargetType& target, const Traits& evo_traits);
00040   ~EvoFunc() { delete pop_p; }
00041 
00042   void init();
00043 
00044   Population<ParTraits> *get_pop_p() { return pop_p; }
00045   
00046   void run(int max_nr_iterations = ParTraits::MAX_ITERATIONS);
00047   void run_2d_grid(int index[2], vector<vector<double> >& fitness_matrix);
00048   void run_1d_array(int index, vector<double>& fitness_array);
00049 
00050   double evaluate();
00051   double evaluate_individual(Indiv& ind);
00052   Indiv *get_best_indiv() { return (*pop_p)[pop_p->get_best_index()]; }
00053   int get_nr_iterations() { return current_iteration; }
00054 
00055   friend class EvoView;
00056 
00057   
00058 private:
00059 
00060   SourceType& source;
00061   TransformedSourceType& transformed_source;
00062   TargetType& target;
00063   const Traits& evo_traits;
00064 
00065   MapType& map;      // to prevent calling of copy constructor
00066   ErrorType& error;
00067   
00068   Population<ParTraits> *pop_p;
00069 
00070   
00071   int check_terminate(double best_fitness);
00072   double prev_fitness;
00073   // after this number of steps we compute the average delta, and compare to TERMINATION_FITNESS_EPSILON
00074   static const int DELTA_WINDOW_SIZE = 5;
00075   double fitness_deltas[DELTA_WINDOW_SIZE];
00076   int current_iteration;
00077 
00078   static const int GRID_NR_STEPS = 50;
00079   static const int ARRAY_NR_STEPS = 50;
00080 
00081   
00082 };  // EvoFunc class
00083 
00084 
00085 
00086 //
00087 // class definition
00088 //
00089 
00090 template<class Traits, class ParTraits>
00091 EvoFunc<Traits, ParTraits>::EvoFunc(SourceType& source_ref, TransformedSourceType& transformed_source_ref,
00092                                     TargetType& target_ref, const Traits& evo_traits_ref) :
00093   source(source_ref),
00094   transformed_source(transformed_source_ref),
00095   target(target_ref),
00096   evo_traits(evo_traits_ref),
00097   map(evo_traits.map_object()),
00098   error(evo_traits.error_object())
00099 {
00100   pop_p = 0;
00101   init();
00102   
00103 }  // constructor
00104 
00105 
00106 
00107 template<class Traits, class ParTraits>
00108 EvoFunc<Traits, ParTraits>::EvoFunc(SourceType& source_ref, TargetType& target_ref, const Traits& evo_traits_ref) :
00109   source(source_ref),
00110   transformed_source(target_ref),
00111   target(target_ref),
00112   evo_traits(evo_traits_ref),
00113   map(evo_traits.map_object()),
00114   error(evo_traits.error_object())
00115 {
00116   pop_p = 0;
00117   init();
00118 
00119 }  // constructor with type of transformed source equal to type of target (old default)
00120 
00121 
00122 
00123 template<class Traits, class ParTraits>         
00124 void
00125 EvoFunc<Traits, ParTraits>::init()
00126 {
00127   if (pop_p) delete pop_p;
00128   pop_p = new Population<ParTraits>();
00129 
00130   //
00131   // initialize variables used in check_terminate
00132   //
00133   prev_fitness = 1e6;
00134   current_iteration = 0;
00135   
00136   // map constructor now already should have initialized ranges
00137   vector<double>& par_ranges = map.get_parameter_ranges();
00138   pop_p->init(par_ranges);
00139 
00140 }  // EvoFunc::init
00141 
00142   
00143 
00144 template<class Traits, class ParTraits>         
00145 void
00146 EvoFunc<Traits, ParTraits>::run(int max_nr_iterations)
00147 {
00148   // init
00149   int t = 0;
00150   
00151   // call obj_func and see if we're done
00152   double best_fit = evaluate();
00153   if (check_terminate(best_fit)) return;
00154   
00155   int done = 0;
00156   
00157   while(!done) {
00158 
00159     //         t := t + 1;       // increase the time counter
00160     t++;
00161     current_iteration = t;
00162     
00163     //         P' := selectparents P (t);  // select sub-population for offspring production
00164     pop_p->select_parents();
00165 
00166     // Roland's algorithm randomly re-orders individuals, then each successive pair become parents
00167     //    pop_p->shuffle();
00168     
00169     //         recombine P' (t); // recombine the "genes" of selected parents
00170     pop_p->recombine();
00171 
00172     //         mutate P' (t);    // perturb the mated population stochastically
00173     pop_p->mutate();
00174     
00175     //         evaluate P' (t);  // evaluate its new fitness
00176     double best_fit = evaluate();
00177     
00178     //         P := survive P,P' (t);  // select the survivors from actual fitness
00179     pop_p->select_survivors();
00180     
00181     done = (t == max_nr_iterations) || check_terminate(best_fit);
00182 
00183     if (ParTraits::VERBOSITY)
00184       cout << "\rdone with iteration " << t << ", best error = " << best_fit << "        " << flush;
00185     
00186   }  // while
00187 
00188 
00189 }  // EvoFunc::run
00190 
00191 
00192 
00193 template<class Traits, class ParTraits>
00194 double
00195 EvoFunc<Traits, ParTraits>::evaluate()
00196 {
00197   //  cout << "EvoFunc::evaluate" << endl;
00198   
00199   double best_fit = 1e9;
00200   int nr = pop_p->get_size();
00201   TransformedSourceType result;
00202 
00203   for(int i=0; i < nr; i++) {
00204 
00205     Indiv *ind_p = (*pop_p)[i];
00206     map(source, result, ind_p->get_pars());
00207 
00208     double err = error(result, target);
00209     ind_p->set_fitness(err);
00210     
00211     if (err < best_fit) {
00212       best_fit = err;
00213       pop_p->set_best_index(i);
00214     }
00215 
00216   }  // for each individual
00217 
00218   return best_fit;
00219   
00220 }  // EvoFunc::evaluate
00221 
00222 
00223 
00224 template<class Traits, class ParTraits>
00225 int
00226 EvoFunc<Traits, ParTraits>::check_terminate(double best_fitness)
00227 {
00228   if (!finite(best_fitness)) {
00229     cout << "error: fitness value is not finite" << endl;
00230     return 1;
00231   }
00232   
00233   if (best_fitness < ParTraits::TERMINATION_FITNESS_CUTOFF) {
00234     if (ParTraits::VERBOSITY)
00235       cout << "terminating because fitness " << best_fitness << " < " << ParTraits::TERMINATION_FITNESS_CUTOFF << endl;
00236     return 1;
00237   }
00238 
00239   double delta = fabs(best_fitness - prev_fitness);
00240   prev_fitness = best_fitness;
00241 
00242   int delta_index = current_iteration % DELTA_WINDOW_SIZE;
00243   fitness_deltas[delta_index] = delta;
00244 
00245   if (current_iteration >= DELTA_WINDOW_SIZE) {
00246     double fitness_delta_sum = 0;
00247     for(int i=0; i < DELTA_WINDOW_SIZE; i++) fitness_delta_sum += fitness_deltas[i];
00248     
00249     double avg_delta = fitness_delta_sum / DELTA_WINDOW_SIZE;
00250     if (avg_delta < ParTraits::TERMINATION_FITNESS_EPSILON) {
00251       if (ParTraits::VERBOSITY) {
00252         cout << "terminating because average difference between consecutive fitness values over " << DELTA_WINDOW_SIZE
00253              << " steps < " << ParTraits::TERMINATION_FITNESS_EPSILON << endl;
00254       }
00255       return 1;
00256     }
00257   }  // if we've done at least DELTA_WINDOW_SIZE steps then our window is filled
00258   
00259   return 0;
00260   
00261 }  // EvoAlg::check_terminate
00262 
00263 
00264 
00265 template<class Traits, class ParTraits>
00266 void
00267 EvoFunc<Traits, ParTraits>::run_1d_array(int index, vector<double>& fitness_array)
00268 {
00269   char output_filespec[80];
00270   sprintf(output_filespec, "array_%d.dat", index);
00271   ofstream *out = new ofstream(output_filespec);
00272   if (ParTraits::VERBOSITY)
00273     cout << "EvoFunc::run_1d_array, writing to [" << output_filespec << "]" << endl;
00274 
00275   // clear array
00276   fitness_array.clear();
00277 
00278   vector<double>& par_ranges = map.get_parameter_ranges();
00279   vector<double>& parameters = map.get_parameters();
00280   
00281   double p_start = par_ranges[index * 2];
00282   double p_end = par_ranges[index * 2 + 1];
00283   double p_delta = (p_end - p_start) / ARRAY_NR_STEPS;
00284 
00285   if (ParTraits::VERBOSITY)
00286     cout << "single loop running from " << p_start << " to " << p_end << ", step " << p_delta << endl;
00287 
00288   // use single individual to evaluate fitness function
00289   int nr_pars = parameters.size();
00290   Indiv ind(nr_pars);
00291   // copy parameters
00292   vector<double>& pars = ind.get_pars();
00293   for(int i=0; i < nr_pars; i++) pars[i] = parameters[i];
00294 
00295   // start single loop
00296   TransformedSourceType result;
00297   for(double p = p_start; p <= p_end; p += p_delta) {
00298     pars[index] = p;
00299     
00300     map(source, result, ind.get_pars());
00301     double err = error(result, target);
00302     ind.set_fitness(err);
00303 
00304     *out << p << " " << err << endl;
00305     fitness_array.push_back(err);
00306     
00307   }  // for
00308   
00309   out->close();
00310   delete out;
00311 
00312 }  // EvoFunc::run_1d_array
00313 
00314 
00315 
00316 template<class Traits, class ParTraits>
00317 void
00318 EvoFunc<Traits, ParTraits>::run_2d_grid(int index[2], vector<vector<double> >& fitness_matrix)
00319 {
00320   char output_filespec[80];
00321   sprintf(output_filespec, "grid_%d%d.dat", index[0], index[1]);
00322   ofstream *out = new ofstream(output_filespec);
00323   if (ParTraits::VERBOSITY)
00324     cout << "EvoFunc::run_2d_grid, writing to [" << output_filespec << "]" << endl;
00325   
00326   // clear matrix
00327   for(unsigned int i=0; i < fitness_matrix.size(); i++) fitness_matrix[i].clear();
00328   fitness_matrix.clear();
00329   // fill matrix
00330   for(int i=0; i <= GRID_NR_STEPS; i++) {
00331     vector<double> temp;
00332     fitness_matrix.push_back(temp);
00333     for(int j=0; j <= GRID_NR_STEPS; j++) {
00334       fitness_matrix[i].push_back(0);
00335     }  // for
00336   }  // for, fill matrix
00337 
00338   vector<double>& par_ranges = map.get_parameter_ranges();
00339   vector<double>& parameters = map.get_parameters();
00340   
00341   // need parameter ranges and step size here
00342   double p_start[2], p_end[2], p_delta[2];
00343   for(int i=0; i < 2; i++) {
00344     p_start[i] = par_ranges[index[i] * 2];
00345     p_end[i] = par_ranges[index[i] * 2 + 1];
00346     p_delta[i] = (p_end[i] - p_start[i]) / GRID_NR_STEPS;
00347     if (ParTraits::VERBOSITY)
00348       cout << "loop " << i << " running from " << p_start[i] << " to " << p_end[i] << ", step " << p_delta[i] << endl;
00349   }  // for
00350 
00351   // use single individual to evaluate fitness function
00352   int nr_pars = parameters.size();
00353   Indiv ind(nr_pars);
00354   // copy parameters
00355   vector<double>& pars = ind.get_pars();
00356   for(int i=0; i < nr_pars; i++) pars[i] = parameters[i];
00357   
00358   // start double loop
00359   int i1 = 0;
00360   TransformedSourceType result;
00361   
00362   for(double p1 = p_start[0]; p1 <= p_end[0]; p1 += p_delta[0]) {
00363     pars[index[0]] = p1;
00364 
00365     int i2 = 0;
00366     for(double p2 = p_start[1]; p2 <= p_end[1]; p2 += p_delta[1]) {
00367       pars[index[1]] = p2;
00368 
00369       map(source, result, ind.get_pars());
00370       double err = error(result, target);
00371       ind.set_fitness(err);
00372 
00373       //      cout << ind << " : " << err << endl;
00374       *out << p1 << " " << p2 << " " << err << endl;
00375       fitness_matrix[i1][i2] = err;
00376       i2++;
00377 
00378     }  // for
00379     *out << endl;
00380     i1++;
00381    
00382   }  // for
00383 
00384   out->close();
00385   delete out;
00386   
00387 }  // EvoFunc::run_2d_grid
00388 
00389 
00390 
00391 template<class Traits, class ParTraits>
00392 double
00393 EvoFunc<Traits, ParTraits>::evaluate_individual(Indiv& ind)
00394 {
00395   TransformedSourceType result;
00396   map(source, result, ind.get_pars());
00397   double err = error(result, target);
00398   ind.set_fitness(err);
00399   return err;
00400   
00401 }  // EvoFunc::evaluate_individual
00402 
00403 
00404 
00405 #endif
00406 

Generated on Tue Jun 14 11:37:51 2005 for evofunc by doxygen 1.3.6