PaGMO  1.1.5
race_pop.cpp
1 #include "race_pop.h"
2 #include "../problem/ackley.h"
3 #include "../problem/base_stochastic.h"
4 
5 #include <map>
6 #include <utility>
7 
8 namespace pagmo { namespace util { namespace racing {
9 
11 
18 race_pop::race_pop(const population& pop, unsigned int seed): m_race_seed(seed), m_pop(pop), m_pop_wilcoxon(pop), m_seeds(), m_seeder(seed), m_use_caching(true), m_cache_data(pop.size()), m_cache_averaged_data(pop.size())
19 {
21 }
22 
24 
31 race_pop::race_pop(unsigned int seed): m_race_seed(seed), m_pop(population(problem::ackley())), m_pop_wilcoxon(population(problem::ackley())), m_pop_registered(false), m_seeds(), m_seeder(seed), m_use_caching(true), m_cache_data(0), m_cache_averaged_data(0)
32 {
33 }
34 
36 
42 {
43  m_pop = pop;
44  // This is merely to set up the problem in wilcoxon pop
45  m_pop_wilcoxon = pop;
46  reset_cache();
47  if(m_cache_data.size() != pop.size()){
48  m_cache_data.resize(pop.size());
49  m_cache_averaged_data.resize(pop.size());
50  }
51  cache_register_signatures(pop);
52  m_pop_registered = true;
53 }
54 
57 {
58  return m_pop.size();
59 }
60 
61 // Check if the provided active_set is valid.
62 void race_pop::_validate_active_set(const std::vector<population::size_type>& active_set, unsigned int pop_size) const
63 {
64  if(active_set.size() == 0)
65  return;
66  std::vector<bool> hit(pop_size, 0);
67  for(unsigned int i = 0; i < active_set.size(); i++){
68  if(active_set[i] >= pop_size){
69  pagmo_throw(index_error, "Racing: Active set contains invalid (out of bound) index.");
70  }
71  if(hit[active_set[i]] == true){
72  pagmo_throw(index_error, "Racing: Active set contains repeated indices.");
73  }
74  hit[active_set[i]] = true;
75  }
76 }
77 
78 // Check if the problem is stochastic
79 void race_pop::_validate_problem_stochastic(const problem::base& prob) const
80 {
81  try
82  {
83  dynamic_cast<const pagmo::problem::base_stochastic &>(prob).get_seed();
84  }
85  catch (const std::bad_cast& e)
86  {
87  pagmo_throw(type_error, "Attempt to call racing routines on a non-stochastic problem, use get_best_idx() instead");
88  }
89 }
90 
91 // Check if the other parameters for racing are sensible
92 void race_pop::_validate_racing_params(const population& pop, const population::size_type n_final, double delta) const
93 {
94  if(n_final > pop.size()){
95  pagmo_throw(value_error, "Number of intended winner is too large");
96  }
97  if(delta < 0 || delta > 1){
98  pagmo_throw(value_error, "Confidence level should be a small value greater than zero");
99  }
100 }
101 
102 // Check if the provided budget is sensible
103 void race_pop::_validate_budget(const unsigned int min_trials, const unsigned int max_f_evals, const std::vector<population::size_type>& in_race) const
104 {
105  // The fevals required to complete the first iteration
106  unsigned int min_required_1 = compute_required_fevals(in_race, 1);
107  if (max_f_evals < min_required_1) {
108  pagmo_throw(value_error, "Maximum number of function evaluations is smaller than the number of racers");
109  }
110  // The fevals required to complete first min_trials-th iterations
111  unsigned int min_required_2 = 0;
112  for(unsigned int i = 1; i <= min_trials; i++){
113  min_required_2 += compute_required_fevals(in_race, i);
114  }
115  if (max_f_evals < min_required_2) {
116  pagmo_throw(value_error, "You are asking for a mimimum amount of trials which cannot be made with the allowed function evaluation budget");
117  }
118 }
119 
120 // Construct the output (winner / loser) list based on the book kept data
121 // Two possible scenarios:
122 // (1) Goal is BEST: Output will be decided + best ones from in_race (if required).
123 // (2) Goal is WORST: Output will be discarded + worst ones from in_race (if required).
124 std::vector<population::size_type> race_pop::construct_output_list(
125  const std::vector<racer_type>& racers,
126  const std::vector<population::size_type>& decided,
127  const std::vector<population::size_type>& in_race,
128  const std::vector<population::size_type>& discarded,
129  const population::size_type n_final,
130  const bool race_best)
131 {
132  typedef population::size_type size_type;
133  // To be sorted either in ascending (BEST) or descending (WORST)
134  std::vector<std::pair<double, size_type> > argsort;
135  for(std::vector<size_type>::const_iterator it = in_race.begin(); it != in_race.end(); ++it){
136  argsort.push_back(std::make_pair(racers[*it].m_mean, *it));
137  }
138  std::vector<size_type> output;
139  if(race_best){
140  output = decided;
141  std::sort(argsort.begin(), argsort.end(), std::less<std::pair<double, size_type> >());
142  }
143  else{
144  output = discarded;
145  std::sort(argsort.begin(), argsort.end(), std::greater<std::pair<double, size_type> >());
146  }
147  int sorted_idx = 0;
148  while(output.size() < n_final){
149  output.push_back(argsort[sorted_idx++].second);
150  }
151 
152  return output;
153 }
154 
155 // Update m_pop with the evaluation data w.r.t current seed for Friedman test
156 //
157 // The resulting population is aligned with the racers, i.e. m_pop[0]
158 // corresponds to racers[0], storing the newest fitness and constraint vector
159 // evaluated under the new seed. Evaluation data can come from cache or fresh
160 // computation.
161 //
162 // @return The number of objective function calls made
163 unsigned int race_pop::prepare_population_friedman(const std::vector<population::size_type>& in_race, unsigned int count_iter)
164 {
165  unsigned int count_nfes = 0;
166  // Perform re-evaluation on necessary individuals under current seed
167  for(std::vector<population::size_type>::const_iterator it = in_race.begin(); it != in_race.end(); ++it) {
168  // Case 1: Current racer has previous data that can be reused, no
169  // need to be evaluated with this seed
170  if(m_use_caching && cache_data_exist(*it, count_iter-1)){
171  const eval_data& cached_data = cache_get_entry(*it, count_iter-1);
172  m_pop.set_fc(*it, cached_data.f, cached_data.c);
173  }
174  // Case 2: No previous data can be reused, perform actual
175  // re-evaluation and update the cache
176  else{
177  count_nfes++;
178  const population::individual_type &ind = m_pop.get_individual(*it);
179  fitness_vector f_vec = m_pop.problem().objfun(ind.cur_x);
180  constraint_vector c_vec = m_pop.problem().compute_constraints(ind.cur_x);
181  m_pop.set_fc(*it, f_vec, c_vec);
182  if(m_use_caching)
183  cache_insert_data(*it, f_vec, c_vec);
184  }
185  }
186  return count_nfes;
187 }
188 
190 
195 unsigned int race_pop::prepare_population_wilcoxon(const std::vector<population::size_type>& in_race, unsigned int count_iter)
196 {
197  unsigned int count_nfes = 0;
198  if(in_race.size() != 2){
199  pagmo_throw(value_error, "Wilcoxon rank sum test is only applicable when there are two active individuals");
200  }
201 
202  // Need to bootstrap by pulling all the previous evaluation data into
203  // wilcoxon_pop for the first time when race is left with the two
204  // individuals. Subsequent racing iterations can just re-use this
205  // wilcoxon_pop memory structure and pad in necessary fc data for each
206  // particular iteration.
207  unsigned int start_count_iter;
208  if(m_pop_wilcoxon.size() == 0){
209  start_count_iter = 1;
210  }
211  else{
212  start_count_iter = count_iter;
213  }
214  for(std::vector<population::size_type>::const_iterator it = in_race.begin(); it != in_race.end(); ++it) {
215  decision_vector dummy_x;
216  for(unsigned int i = start_count_iter; i <= count_iter; i++){
217  // Case 1: Current racer has previous data that can be reused, no
218  // need to be evaluated with this seed
219  if(m_use_caching && cache_data_exist(*it, i-1)){
220  m_pop_wilcoxon.push_back_noeval(dummy_x);
221  const eval_data& cached_data = cache_get_entry(*it, i-1);
222  m_pop_wilcoxon.set_fc(m_pop_wilcoxon.size()-1, cached_data.f, cached_data.c);
223  }
224  // Case 2: No previous data can be reused, perform actual
225  // re-evaluation and update the cache
226  else{
227  count_nfes++;
228  const population::individual_type &ind = m_pop.get_individual(*it);
229  fitness_vector f_vec = m_pop.problem().objfun(ind.cur_x);
230  constraint_vector c_vec = m_pop.problem().compute_constraints(ind.cur_x);
231  m_pop_wilcoxon.push_back_noeval(dummy_x);
232  m_pop_wilcoxon.set_fc(m_pop_wilcoxon.size()-1, f_vec, c_vec);
233  if(m_use_caching)
234  cache_insert_data(*it, f_vec, c_vec);
235  }
236  }
237  }
238  return count_nfes;
239 }
240 
242 /*
243  * This function takes into account the existence of cache. For example, if the
244  * cache has already been filled with many data, a call to run race with zero
245  * budget is actually possible.
246  *
247  * @param[in] racers List of racers
248  * @param[in] num_iter Index of current iteration (starts from 1)
249  */
250 unsigned int race_pop::compute_required_fevals(const std::vector<population::size_type>& in_race, unsigned int num_iter) const
251 {
252  unsigned int required_fevals = 0;
253  for(unsigned int i = 0; i < in_race.size(); i++){
254  if(!cache_data_exist(in_race[i], num_iter-1)){
255  required_fevals++;
256  }
257  }
258  return required_fevals;
259 }
260 
262 
303 std::pair<std::vector<population::size_type>, unsigned int> race_pop::run(
304  const population::size_type n_final,
305  const unsigned int min_trials,
306  const unsigned int max_f_evals,
307  const double delta,
308  const std::vector<population::size_type>& active_set,
309  termination_condition term_cond,
310  const bool race_best,
311  const bool screen_output
312  )
313 {
314  // First check whether the a population has been properly registered
315  if(!m_pop_registered){
316  pagmo_throw(value_error, "Attempt to run race but no population is registered");
317  }
318  // We start validating the inputs:
319  // a - Problem has to be stochastic
320  _validate_problem_stochastic(m_pop.problem());
321  // b - active_set has to contain valid indexes
322  _validate_active_set(active_set, m_pop.size());
323  // c - Other parameters have to be sane
324  _validate_racing_params(m_pop, n_final, delta);
325 
326  typedef population::size_type size_type;
327 
328  // Temporary: Consider a fresh start every time race() is called
329  std::vector<racer_type> racers(m_pop.size(), racer_type());
330 
331  // If active_set is empty, default to race all individuals
332  if(active_set.size() == 0){
333  for(size_type i = 0; i < m_pop.size(); i++){
334  racers[i].active = true;
335  }
336  }
337  else{
338  for(size_type i = 0; i < active_set.size(); i++){
339  racers[active_set[i]].active = true;
340  }
341  }
342 
343  // Indices of racers who are currently active in the pop's sense
344  // Examples:
345  // (1) in_race.size() == 5 ---> Only 5 individuals are still being raced.
346  // (2) pop.get_individual(in_race[0]) gives a reference to an actual
347  // individual which is active in the race.
348  std::vector<size_type> in_race;
349  std::vector<size_type> decided;
350  std::vector<size_type> discarded;
351 
352  for(size_type i = 0; i < racers.size(); i++){
353  if(racers[i].active){
354  in_race.push_back(i);
355  }
356  }
357 
358  if(term_cond == MAX_BUDGET){
359  // d - Check if the given budget is too small
360  _validate_budget(min_trials, max_f_evals, in_race);
361  }
362 
363  size_type N_begin = in_race.size();
364  size_type n_final_best;
365 
366  // Complimentary relationship between race-for-best and race-for-worst
367  if(race_best){
368  n_final_best = n_final;
369  }
370  else{
371  n_final_best = N_begin - n_final;
372  }
373 
374  // Reset data holder for wilcoxon test
375  m_pop_wilcoxon.clear();
376  bool use_wilcoxon = false;
377 
378  unsigned int count_iter = 0;
379  unsigned int count_nfes = 0;
380 
381  // The stochastic problem's seed will be changed using a pre-determined sequence
382  unsigned int seed_idx = 0;
383 
384  // Start of the main loop. It will stop as soon as we have decided enough winners or
385  // discarded enough losers
386  while(decided.size() < n_final_best && decided.size() + in_race.size() > n_final_best){
387 
388  count_iter++;
389 
390  if(screen_output){
391  std::cout << "\n-----Iteration: " << count_iter << ", evaluation count = " << count_nfes << std::endl;
392  std::cout << "Decided: " << decided << std::endl;
393  std::cout << "In-race: " << in_race << std::endl;
394  std::cout << "Discarded: " << discarded << std::endl;
395  std::cout << "Mean ranks: ";
396  for(unsigned int i = 0; i < in_race.size(); i++){
397  if(racers[in_race[i]].active){
398  std::cout << "(" << in_race[i] << "): " << racers[in_race[i]].m_mean << " ";
399  }
400  }
401  std::cout << std::endl;
402  print_cache_stats(in_race);
403  }
404 
405  if(term_cond == MAX_BUDGET){
406  // Check if there is enough budget for evaluating the individuals in the race
407  unsigned int required_fevals = compute_required_fevals(in_race, count_iter);
408  if(count_nfes + required_fevals > max_f_evals){
409  break;
410  }
411  }
412  else{
413  // Here max_f_evals has the meaning of "maximum number of data
414  // points" to be considered for each individual
415  if(count_iter > max_f_evals){
416  break;
417  }
418  }
419 
420  unsigned int cur_seed = get_current_seed(seed_idx++);
421  dynamic_cast<const pagmo::problem::base_stochastic &>(m_pop.problem()).set_seed(cur_seed);
422 
423  // NOTE: Here after resetting to a new seed, we do not perform
424  // re-evaluation of the whole population, as this defeats the purpose
425  // of doing race! Only the required individuals (i.e. those still
426  // active in racing) shall be re-evaluated. A direct consequence is
427  // that the champion of the population is not valid anymore nor the
428  // individuals best_x and best_f -- they do not correspond to the
429  // latest seed. This is OK, as this only affects the local copy the
430  // population, which will not be accessed elsewhere, and the champion
431  // information is not used during racing.
432 
433  // Update m_pop with re-evaluation results or possibly data from cache,
434  // and invoke statistical testing routines.
435  stat_test_result ss_result;
436  if(use_wilcoxon && in_race.size() == 2){
437  // Perform Wilcoxon rank-sum test
438  count_nfes += prepare_population_wilcoxon(in_race, count_iter);
439  ss_result = wilcoxon_ranksum_test(racers, in_race, m_pop_wilcoxon, delta);
440  }
441  else{
442  // Perform Friedman test
443  count_nfes += prepare_population_friedman(in_race, count_iter);
444  ss_result = friedman_test(racers, in_race, m_pop, delta);
445 
446  }
447 
448  if(count_iter < min_trials)
449  continue;
450 
451  if(!ss_result.trivial){
452  // Inside here some pairs must be statistically different, let's find them out
453 
454  const std::vector<std::vector<bool> >& is_better = ss_result.is_better;
455 
456  std::vector<size_type> out_of_race;
457 
458  std::vector<bool> to_decide(in_race.size(), false), to_discard(in_race.size(), false);
459 
460  for(unsigned int i = 0; i < in_race.size(); i++){
461  unsigned int vote_decide = 0;
462  unsigned int vote_discard = 0;
463  for(unsigned int j = 0; j < in_race.size(); j++){
464  if(i == j || to_decide[j] || to_discard[j])
465  continue;
466  // Check if a pair is statistically significantly different
467  if(is_better[i][j]){
468  vote_decide++;
469  }
470  else if(is_better[j][i]){
471  vote_discard++;
472  }
473  }
474 
475  if(vote_decide >= N_begin - n_final_best - discarded.size()){
476  to_decide[i] = true;
477  }
478  else if(vote_discard >= n_final_best - decided.size()){
479  to_discard[i] = true;
480  }
481  }
482 
483  std::vector<size_type> new_in_race;
484  for(unsigned int i = 0; i < in_race.size(); i++){
485  if(to_decide[i]){
486  decided.push_back(in_race[i]);
487  out_of_race.push_back(in_race[i]);
488  racers[in_race[i]].active = false;
489  }
490  else if(to_discard[i]){
491  discarded.push_back(in_race[i]);
492  out_of_race.push_back(in_race[i]);
493  racers[in_race[i]].active = false;
494  }
495  else{
496  new_in_race.push_back(in_race[i]);
497  }
498  }
499 
500  in_race = new_in_race;
501 
502  // Check if this is that important
503  if(!use_wilcoxon || in_race.size() > 2){
504  f_race_adjust_ranks(racers, out_of_race);
505  }
506  }
507 
508  };
509 
510  // Note that n_final (instead of n_final_best) is required here
511  std::vector<size_type> winners =
512  construct_output_list(racers, decided, in_race, discarded, n_final, race_best);
513 
514  if(screen_output){
515  std::cout << "\nRace ends after " << count_iter << " iterations, incurred nfes = " << count_nfes << std::endl;
516  std::cout << "Returning winners: " << std::vector<size_type>(winners.begin(), winners.end()) << std::endl;
517  }
518 
519  return std::make_pair(winners, count_nfes);
520 }
521 
523 
532 std::vector<fitness_vector> race_pop::get_mean_fitness(const std::vector<population::size_type> &ind_list) const
533 {
534  _validate_active_set(ind_list, m_pop.size());
535 
536  std::vector<population::size_type> active_set;
537  // If empty list is given then assume all individuals are of interest
538  if(ind_list.size() == 0){
539  active_set.resize(size());
540  for(population::size_type i = 0; i < size(); i++){
541  active_set[i] = i;
542  }
543  }
544  else{
545  active_set = ind_list;
546  }
547 
548  std::vector<fitness_vector> mean_fitness(active_set.size());
549  for(unsigned int i = 0; i < active_set.size(); i++){
550  if(m_cache_data[active_set[i]].size() == 0){
551  pagmo_throw(value_error, "Request the mean fitness of an individual which has not been raced before");
552  }
553  mean_fitness[i] = m_cache_averaged_data[active_set[i]].f;
554  }
555  return mean_fitness;
556 }
557 
560 {
561  for(unsigned int i = 0; i < m_cache_data.size(); i++){
562  m_cache_data[i].clear();
563  m_cache_averaged_data[i].f.clear();
564  m_cache_averaged_data[i].c.clear();
565  }
566 }
567 
569 
574 void race_pop::cache_insert_data(unsigned int key_idx, const fitness_vector &f, const constraint_vector &c)
575 {
576  if(key_idx >= m_cache_data.size()){
577  pagmo_throw(index_error, "cache_insert_data: Invalid key index");
578  }
579  m_cache_data[key_idx].push_back(eval_data(f,c));
580  // Update the averaged data to be returned upon each race call
581  if(m_cache_data[key_idx].size() == 1){
582  m_cache_averaged_data[key_idx] = m_cache_data[key_idx].back();
583  }
584  else{
585  unsigned int len = m_cache_data[key_idx].size();
586  // Average for each fitness dimension
587  for(unsigned int i = 0; i < m_cache_averaged_data[key_idx].f.size(); i++){
588  m_cache_averaged_data[key_idx].f[i] =
589  (m_cache_averaged_data[key_idx].f[i]*(len-1) +
590  m_cache_data[key_idx].back().f[i]) / (double)len;
591  }
592  // Average for each constraint dimension
593  for(unsigned int i = 0; i < m_cache_averaged_data[key_idx].c.size(); i++){
594  m_cache_averaged_data[key_idx].c[i] =
595  (m_cache_averaged_data[key_idx].c[i]*(len-1) +
596  m_cache_data[key_idx].back().c[i]) / (double)len;
597  }
598  }
599 }
600 
603 void race_pop::cache_delete_entry(unsigned int key_idx)
604 {
605  m_cache_data.erase(m_cache_data.begin() + key_idx);
606 }
607 
609 
613 bool race_pop::cache_data_exist(unsigned int key_idx, unsigned int data_location) const
614 {
615  if(key_idx >= m_cache_data.size()){
616  pagmo_throw(index_error, "cache_data_exist: Invalid key index");
617  }
618  if(data_location < m_cache_data[key_idx].size()){
619  return true;
620  }
621  return false;
622 }
623 
625 const race_pop::eval_data &race_pop::cache_get_entry(unsigned int key_idx, unsigned int data_location) const
626 {
627  if(key_idx >= m_cache_data.size()){
628  pagmo_throw(index_error, "cache_get_entry: Invalid key index");
629  }
630  if(data_location >= m_cache_data[key_idx].size()){
631  pagmo_throw(index_error, "cache_get_netry: Invalid data location");
632  }
633  return m_cache_data[key_idx][data_location];
634 }
635 
636 // Each cache entry is dedicated to an individual in the population, and it can
637 // be associated with a signature based on the decision vector of the
638 // individual. This can be useful to identify a match when trying to inherit
639 // memory from another race_pop structure to maximize information reuse.
640 void race_pop::cache_register_signatures(const population& pop)
641 {
642  m_cache_signatures.clear();
643  for(population::size_type i = 0; i < pop.size(); i++){
644  m_cache_signatures.push_back(pop.get_individual(i).cur_x);
645  }
646 }
647 
649 
654 {
655  // If seeds are different, no memory transfer is possible
656  if(src.m_race_seed != m_race_seed){
657  pagmo_throw(value_error, "Incompatible seed in inherit_memory");
658  }
659  std::map<decision_vector, unsigned int> src_cache_locations;
660  for(unsigned int i = 0; i < src.m_cache_data.size(); i++){
661  src_cache_locations.insert(std::make_pair(src.m_cache_signatures[i], i));
662  }
663  int cnt_transferred = 0;
664  for(unsigned int i = 0; i < m_cache_data.size(); i++){
665  std::map<decision_vector, unsigned int>::iterator it
666  = src_cache_locations.find(m_cache_signatures[i]);
667  if(it != src_cache_locations.end()){
668  if(src.m_cache_data[it->second].size() > m_cache_data[i].size()){
669  m_cache_data[i] = src.m_cache_data[it->second];
670  m_cache_averaged_data[i] = src.m_cache_averaged_data[it->second];
671  cnt_transferred++;
672  }
673  }
674  }
675 }
676 
677 
679 void race_pop::print_cache_stats(const std::vector<population::size_type> &in_race) const
680 {
681  for(std::vector<population::size_type>::const_iterator it = in_race.begin(); it != in_race.end(); it++){
682  std::cout << "Cache of ind#" << *it << ": length = " << m_cache_data[*it].size() << std::endl;
683  }
684 }
685 
686 
688 
695 void race_pop::set_seed(unsigned int seed)
696 {
697  m_race_seed = seed;
698  m_seeder.seed(seed);
699  m_seeds.clear();
700  reset_cache();
701 }
702 
703 // Produce new seeds and append to the list of seeds
704 void race_pop::generate_seeds(unsigned int num_seeds)
705 {
706  for(unsigned int i = 0; i < num_seeds; i++){
707  m_seeds.push_back(m_seeder());
708  }
709 }
710 
711 // Get the n-th seed to be used for evaluation of the n-th data point. With
712 // this we can ensure that all the aligned data points are generated using the
713 // same rng seed.
714 unsigned int race_pop::get_current_seed(unsigned int seed_idx)
715 {
716  if(seed_idx >= m_seeds.size()){
717  const unsigned int expanding_length = 500;
718  generate_seeds(expanding_length);
719  }
720  return m_seeds[seed_idx];
721 }
722 
723 }}}
Root PaGMO namespace.
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
void register_population(const population &)
Update the population on which the race will run.
Definition: race_pop.cpp:41
Population class.
Definition: population.h:70
Fixed number of function evaluations.
Definition: race_pop.h:69
termination_condition
Method to stop the race.
Definition: race_pop.h:68
race_pop(const population &, unsigned int seed=0)
Constructor.
Definition: race_pop.cpp:18
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
void reset_cache()
Clear all the cache.
Definition: race_pop.cpp:559
std::vector< double > constraint_vector
Constraint vector type.
Definition: types.h:44
std::pair< std::vector< population::size_type >, unsigned int > run(const population::size_type n_final, const unsigned int min_trials, const unsigned int max_count, double delta, const std::vector< population::size_type > &, termination_condition term_cond, const bool race_best, const bool screen_output)
Races some individuals in a population.
Definition: race_pop.cpp:303
Base Stochastic Optimization Problem.
container_type::size_type size_type
Population size type.
Definition: population.h:192
Racing mechanism for a population.
Definition: race_pop.h:60
void set_seed(unsigned int)
Set a new racing seed.
Definition: race_pop.cpp:695
population::size_type size() const
Get the number of individuals in the registered population.
Definition: race_pop.cpp:56
std::vector< fitness_vector > get_mean_fitness(const std::vector< population::size_type > &active_set=std::vector< population::size_type >()) const
Returns mean fitness of the individuals based on past evaluation data.
Definition: race_pop.cpp:532
void inherit_memory(const race_pop &)
Inherits the memory of another race_pop object.
Definition: race_pop.cpp:653