2 #include "../problem/ackley.h"
3 #include "../problem/base_stochastic.h"
8 namespace pagmo {
namespace util {
namespace racing {
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())
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)
47 if(m_cache_data.size() != pop.size()){
48 m_cache_data.resize(pop.size());
49 m_cache_averaged_data.resize(pop.size());
51 cache_register_signatures(pop);
52 m_pop_registered =
true;
62 void race_pop::_validate_active_set(
const std::vector<population::size_type>& active_set,
unsigned int pop_size)
const
64 if(active_set.size() == 0)
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.");
71 if(hit[active_set[i]] ==
true){
72 pagmo_throw(index_error,
"Racing: Active set contains repeated indices.");
74 hit[active_set[i]] =
true;
79 void race_pop::_validate_problem_stochastic(
const problem::base& prob)
const
85 catch (
const std::bad_cast& e)
87 pagmo_throw(type_error,
"Attempt to call racing routines on a non-stochastic problem, use get_best_idx() instead");
92 void race_pop::_validate_racing_params(
const population& pop,
const population::size_type n_final,
double delta)
const
94 if(n_final > pop.size()){
95 pagmo_throw(value_error,
"Number of intended winner is too large");
97 if(delta < 0 || delta > 1){
98 pagmo_throw(value_error,
"Confidence level should be a small value greater than zero");
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
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");
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);
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");
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,
130 const bool race_best)
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));
138 std::vector<size_type> output;
141 std::sort(argsort.begin(), argsort.end(), std::less<std::pair<double, size_type> >());
145 std::sort(argsort.begin(), argsort.end(), std::greater<std::pair<double, size_type> >());
148 while(output.size() < n_final){
149 output.push_back(argsort[sorted_idx++].second);
163 unsigned int race_pop::prepare_population_friedman(
const std::vector<population::size_type>& in_race,
unsigned int count_iter)
165 unsigned int count_nfes = 0;
167 for(std::vector<population::size_type>::const_iterator it = in_race.begin(); it != in_race.end(); ++it) {
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);
178 const population::individual_type &ind = m_pop.get_individual(*it);
181 m_pop.set_fc(*it, f_vec, c_vec);
183 cache_insert_data(*it, f_vec, c_vec);
195 unsigned int race_pop::prepare_population_wilcoxon(
const std::vector<population::size_type>& in_race,
unsigned int count_iter)
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");
207 unsigned int start_count_iter;
208 if(m_pop_wilcoxon.size() == 0){
209 start_count_iter = 1;
212 start_count_iter = count_iter;
214 for(std::vector<population::size_type>::const_iterator it = in_race.begin(); it != in_race.end(); ++it) {
216 for(
unsigned int i = start_count_iter; i <= count_iter; i++){
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);
228 const population::individual_type &ind = m_pop.get_individual(*it);
231 m_pop_wilcoxon.push_back_noeval(dummy_x);
232 m_pop_wilcoxon.set_fc(m_pop_wilcoxon.size()-1, f_vec, c_vec);
234 cache_insert_data(*it, f_vec, c_vec);
250 unsigned int race_pop::compute_required_fevals(
const std::vector<population::size_type>& in_race,
unsigned int num_iter)
const
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)){
258 return required_fevals;
305 const unsigned int min_trials,
306 const unsigned int max_f_evals,
308 const std::vector<population::size_type>& active_set,
310 const bool race_best,
311 const bool screen_output
315 if(!m_pop_registered){
316 pagmo_throw(value_error,
"Attempt to run race but no population is registered");
320 _validate_problem_stochastic(m_pop.problem());
322 _validate_active_set(active_set, m_pop.size());
324 _validate_racing_params(m_pop, n_final, delta);
329 std::vector<racer_type> racers(m_pop.size(), racer_type());
332 if(active_set.size() == 0){
333 for(size_type i = 0; i < m_pop.size(); i++){
334 racers[i].active =
true;
338 for(size_type i = 0; i < active_set.size(); i++){
339 racers[active_set[i]].active =
true;
348 std::vector<size_type> in_race;
349 std::vector<size_type> decided;
350 std::vector<size_type> discarded;
352 for(size_type i = 0; i < racers.size(); i++){
353 if(racers[i].active){
354 in_race.push_back(i);
360 _validate_budget(min_trials, max_f_evals, in_race);
363 size_type N_begin = in_race.size();
364 size_type n_final_best;
368 n_final_best = n_final;
371 n_final_best = N_begin - n_final;
375 m_pop_wilcoxon.clear();
376 bool use_wilcoxon =
false;
378 unsigned int count_iter = 0;
379 unsigned int count_nfes = 0;
382 unsigned int seed_idx = 0;
386 while(decided.size() < n_final_best && decided.size() + in_race.size() > n_final_best){
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 <<
" ";
401 std::cout << std::endl;
402 print_cache_stats(in_race);
407 unsigned int required_fevals = compute_required_fevals(in_race, count_iter);
408 if(count_nfes + required_fevals > max_f_evals){
415 if(count_iter > max_f_evals){
420 unsigned int cur_seed = get_current_seed(seed_idx++);
435 stat_test_result ss_result;
436 if(use_wilcoxon && in_race.size() == 2){
438 count_nfes += prepare_population_wilcoxon(in_race, count_iter);
439 ss_result = wilcoxon_ranksum_test(racers, in_race, m_pop_wilcoxon, delta);
443 count_nfes += prepare_population_friedman(in_race, count_iter);
444 ss_result = friedman_test(racers, in_race, m_pop, delta);
448 if(count_iter < min_trials)
451 if(!ss_result.trivial){
454 const std::vector<std::vector<bool> >& is_better = ss_result.is_better;
456 std::vector<size_type> out_of_race;
458 std::vector<bool> to_decide(in_race.size(),
false), to_discard(in_race.size(),
false);
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])
470 else if(is_better[j][i]){
475 if(vote_decide >= N_begin - n_final_best - discarded.size()){
478 else if(vote_discard >= n_final_best - decided.size()){
479 to_discard[i] =
true;
483 std::vector<size_type> new_in_race;
484 for(
unsigned int i = 0; i < in_race.size(); i++){
486 decided.push_back(in_race[i]);
487 out_of_race.push_back(in_race[i]);
488 racers[in_race[i]].active =
false;
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;
496 new_in_race.push_back(in_race[i]);
500 in_race = new_in_race;
503 if(!use_wilcoxon || in_race.size() > 2){
504 f_race_adjust_ranks(racers, out_of_race);
511 std::vector<size_type> winners =
512 construct_output_list(racers, decided, in_race, discarded, n_final, race_best);
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;
519 return std::make_pair(winners, count_nfes);
534 _validate_active_set(ind_list, m_pop.size());
536 std::vector<population::size_type> active_set;
538 if(ind_list.size() == 0){
539 active_set.resize(
size());
545 active_set = ind_list;
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");
553 mean_fitness[i] = m_cache_averaged_data[active_set[i]].f;
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();
576 if(key_idx >= m_cache_data.size()){
577 pagmo_throw(index_error,
"cache_insert_data: Invalid key index");
579 m_cache_data[key_idx].push_back(eval_data(f,c));
581 if(m_cache_data[key_idx].
size() == 1){
582 m_cache_averaged_data[key_idx] = m_cache_data[key_idx].back();
585 unsigned int len = m_cache_data[key_idx].size();
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;
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;
603 void race_pop::cache_delete_entry(
unsigned int key_idx)
605 m_cache_data.erase(m_cache_data.begin() + key_idx);
613 bool race_pop::cache_data_exist(
unsigned int key_idx,
unsigned int data_location)
const
615 if(key_idx >= m_cache_data.size()){
616 pagmo_throw(index_error,
"cache_data_exist: Invalid key index");
618 if(data_location < m_cache_data[key_idx].
size()){
625 const race_pop::eval_data &race_pop::cache_get_entry(
unsigned int key_idx,
unsigned int data_location)
const
627 if(key_idx >= m_cache_data.size()){
628 pagmo_throw(index_error,
"cache_get_entry: Invalid key index");
630 if(data_location >= m_cache_data[key_idx].
size()){
631 pagmo_throw(index_error,
"cache_get_netry: Invalid data location");
633 return m_cache_data[key_idx][data_location];
640 void race_pop::cache_register_signatures(
const population& pop)
642 m_cache_signatures.clear();
644 m_cache_signatures.push_back(pop.get_individual(i).cur_x);
656 if(src.m_race_seed != m_race_seed){
657 pagmo_throw(value_error,
"Incompatible seed in inherit_memory");
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));
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];
679 void race_pop::print_cache_stats(
const std::vector<population::size_type> &in_race)
const
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;
704 void race_pop::generate_seeds(
unsigned int num_seeds)
706 for(
unsigned int i = 0; i < num_seeds; i++){
707 m_seeds.push_back(m_seeder());
714 unsigned int race_pop::get_current_seed(
unsigned int seed_idx)
716 if(seed_idx >= m_seeds.size()){
717 const unsigned int expanding_length = 500;
718 generate_seeds(expanding_length);
720 return m_seeds[seed_idx];
std::vector< double > decision_vector
Decision vector type.
void register_population(const population &)
Update the population on which the race will run.
Fixed number of function evaluations.
termination_condition
Method to stop the race.
race_pop(const population &, unsigned int seed=0)
Constructor.
std::vector< double > fitness_vector
Fitness vector type.
void reset_cache()
Clear all the cache.
std::vector< double > constraint_vector
Constraint vector type.
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.
Base Stochastic Optimization Problem.
container_type::size_type size_type
Population size type.
Racing mechanism for a population.
void set_seed(unsigned int)
Set a new racing seed.
population::size_type size() const
Get the number of individuals in the registered population.
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.
void inherit_memory(const race_pop &)
Inherits the memory of another race_pop object.