Real-time NEAT Validation
/* ------------------------------------------------------------------ */
/* Real-time NEAT Validation */
/* ------------------------------------------------------------------ */
//Perform evolution on double pole balacing using rtNEAT methods calls
//Always uses Markov case (i.e. velocities provided)
//This test is meant to validate the rtNEAT methods and show how they can be used instead
// of the usual generational NEAT
Population *pole2_test_realtime() {
Population *pop;
Genome *start_genome;
char curword[20];
int id;
ostringstream *fnamebuf;
int gen;
CartPole *thecart;
double highscore;
ifstream iFile("pole2startgenes1",ios::in);
cout<<"START DOUBLE POLE BALANCING REAL-TIME EVOLUTION VALIDATION"<<endl;
cout<<"Reading in the start genome"<<endl;
//Read in the start Genome
iFile>>curword;
iFile>>id;
cout<<"Reading in Genome id "<<id<<endl;
start_genome=new Genome(id,iFile);
iFile.close();
cout<<"Start Genome: "<<start_genome<<endl;
//Spawn the Population from starter gene
cout<<"Spawning Population off Genome"<<endl;
pop=new Population(start_genome,NEAT::pop_size);
//Alternative way to start off of randomly connected genomes
//pop=new Population(pop_size,7,1,10,false,0.3);
cout<<"Verifying Spawned Pop"<<endl;
pop->verify();
//Create the Cart
thecart=new CartPole(true,1);
//Start the evolution loop using rtNEAT method calls
highscore=pole2_realtime_loop(pop,thecart);
return pop;
}
int pole2_realtime_loop(Population *pop, CartPole *thecart) {
vector<Organism*>::iterator curorg;
vector<Species*>::iterator curspecies;
vector<Species*>::iterator curspec; //used in printing out debug info
vector<Species*> sorted_species; //Species sorted by max fit org in Species
int pause;
bool win=false;
double champ_fitness;
Organism *champ;
//double statevals[5]={-0.9,-0.5,0.0,0.5,0.9};
double statevals[5]={0.05, 0.25, 0.5, 0.75, 0.95};
int s0c,s1c,s2c,s3c;
int score;
//Real-time evolution variables
int offspring_count;
Organism *new_org;
thecart->nmarkov_long=false;
thecart->generalization_test=false;
//We try to keep the number of species constant at this number
int num_species_target=NEAT::pop_size/15;
//This is where we determine the frequency of compatibility threshold adjustment
int compat_adjust_frequency = NEAT::pop_size/10;
if (compat_adjust_frequency < 1)
compat_adjust_frequency = 1;
//Initially, we evaluate the whole population
//Evaluate each organism on a test
for(curorg=(pop->organisms).begin();curorg!=(pop->organisms).end();++curorg) {
//shouldn't happen
if (((*curorg)->gnome)==0) {
cout<<"ERROR EMPTY GEMOME!"<<endl;
cin>>pause;
}
if (pole2_evaluate((*curorg),1,thecart)) win=true;
}
//Get ready for real-time loop
//Rank all the organisms from best to worst in each species
pop->rank_within_species();
//Assign each species an average fitness
//This average must be kept up-to-date by rtNEAT in order to select species probabailistically for reproduction
pop->estimate_all_averages();
//Now create offspring one at a time, testing each offspring,
// and replacing the worst with the new offspring if its better
for (offspring_count=0;offspring_count<20000;offspring_count++) {
//Every pop_size reproductions, adjust the compat_thresh to better match the num_species_targer
//and reassign the population to new species
if (offspring_count % compat_adjust_frequency == 0) {
int num_species = pop->species.size();
double compat_mod=0.1; //Modify compat thresh to control speciation
// This tinkers with the compatibility threshold
if (num_species < num_species_target) {
NEAT::compat_threshold -= compat_mod;
}
else if (num_species > num_species_target)
NEAT::compat_threshold += compat_mod;
if (NEAT::compat_threshold < 0.3)
NEAT::compat_threshold = 0.3;
cout<<"compat_thresh = "<<NEAT::compat_threshold<<endl;
//Go through entire population, reassigning organisms to new species
for (curorg = (pop->organisms).begin(); curorg != pop->organisms.end(); ++curorg) {
pop->reassign_species(*curorg);
}
}
//For printing only
for(curspec=(pop->species).begin();curspec!=(pop->species).end();curspec++) {
cout<<"Species "<<(*curspec)->id<<" size"<<(*curspec)->organisms.size()<<" average= "<<(*curspec)->average_est<<endl;
}
cout<<"Pop size: "<<pop->organisms.size()<<endl;
//Here we call two rtNEAT calls:
//1) choose_parent_species() decides which species should produce the next offspring
//2) reproduce_one(...) creates a single offspring fromt the chosen species
new_org=(pop->choose_parent_species())->reproduce_one(offspring_count,pop,pop->species);
//Now we evaluate the new individual
//Note that in a true real-time simulation, evaluation would be happening to all individuals at all times.
//That is, this call would not appear here in a true online simulation.
cout<<"Evaluating new baby: "<<endl;
if (pole2_evaluate(new_org,1,thecart)) win=true;
if (win) {
cout<<"WINNER"<<endl;
pop->print_to_file_by_species("rt_winpop");
break;
}
//Now we reestimate the baby's species' fitness
new_org->species->estimate_average();
//Remove the worst organism
pop->remove_worst();
}
}