XOR experiment

test.ne

trait_param_mut_prob 0.5 

trait_mutation_power 1.0

linktrait_mut_sig 1.0

nodetrait_mut_sig 0.5

weigh_mut_power 2.5

recur_prob 0.00

disjoint_coeff 1.0

excess_coeff 1.0

mutdiff_coeff 0.4

compat_thresh 3.0

age_significance 1.0

survival_thresh 0.20

mutate_only_prob 0.25

mutate_random_trait_prob 0.1

mutate_link_trait_prob 0.1

mutate_node_trait_prob 0.1

mutate_link_weights_prob 0.9

mutate_toggle_enable_prob 0.00

mutate_gene_reenable_prob 0.000

mutate_add_node_prob 0.03

mutate_add_link_prob 0.05

interspecies_mate_rate 0.001

mate_multipoint_prob 0.6

mate_multipoint_avg_prob 0.4

mate_singlepoint_prob 0.0

mate_only_prob 0.2

recur_only_prob 0.0

pop_size 150

dropoff_age 15

newlink_tries 20

print_every 30

babies_stolen 0

num_runs 100

xorstartgenes

genomestart 1

trait 1 0.1 0 0 0 0 0 0 0

trait 2 0.2 0 0 0 0 0 0 0

trait 3 0.3 0 0 0 0 0 0 0

node 1 0 1 3

node 2 0 1 1

node 3 0 1 1

node 4 0 0 2

gene 1 1 4 0.0 0 1 0 1

gene 2 2 4 0.0 0 2 0 1

gene 3 3 4 0.0 0 3 0 1

genomeend 1

////////////////////////////////////////////////////////////////////////////////////////

//The XOR evolution routines *****************************************

Population *xor_test(int gens);

bool xor_evaluate(Organism *org);

int xor_epoch(Population *pop,int generation,char *filename, int &winnernum, int &winnergenes,int &winnernodes);

////////////////////////////////////////////////////////////////////////////////////////

//Perform evolution on XOR, for gens generations

Population *xor_test(int gens) {

    Population *pop;

    Genome *start_genome;

    char curword[20];

    int id;

    ostringstream *fnamebuf;

    int gen;

 

    int evals[NEAT::num_runs];  //Hold records for each run

    int genes[NEAT::num_runs];

    int nodes[NEAT::num_runs];

    int winnernum;

    int winnergenes;

    int winnernodes;

    //For averaging

    int totalevals=0;

    int totalgenes=0;

    int totalnodes=0;

    int expcount;

    ifstream iFile("xorstartgenes",ios::in);

    cout<<"START XOR TEST"<<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();

    for(expcount=0;expcount<NEAT::num_runs;expcount++) {

      //Spawn the Population

      cout<<"Spawning Population off Genome2"<<endl;

      pop=new Population(start_genome,NEAT::pop_size);

      

      cout<<"Verifying Spawned Pop"<<endl;

      pop->verify();

      

      for (gen=1;gen<=gens;gen++) {

cout<<"Epoch "<<gen<<endl;

//This is how to make a custom filename

fnamebuf=new ostringstream();

(*fnamebuf)<<"gen_"<<gen<<ends;  //needs end marker

#ifndef NO_SCREEN_OUT

cout<<"name of fname: "<<fnamebuf->str()<<endl;

#endif

char temp[50];

sprintf (temp, "gen_%d", gen);

//Check for success

if (xor_epoch(pop,gen,temp,winnernum,winnergenes,winnernodes)) {

  {

 //Collect Stats on end of experiment

 evals[expcount]=NEAT::pop_size*(gen-1)+winnernum;

 genes[expcount]=winnergenes;

 nodes[expcount]=winnernodes;

 gen=gens;

}


//Clear output filename

fnamebuf->clear();

delete fnamebuf;


      }

      if (expcount<NEAT::num_runs-1) delete pop;

      

    }

    //Average and print stats

    cout<<"Nodes: "<<endl;

    for(expcount=0;expcount<NEAT::num_runs;expcount++) {

      cout<<nodes[expcount]<<endl;

      totalnodes+=nodes[expcount];

    }

    

    cout<<"Genes: "<<endl;

    for(expcount=0;expcount<NEAT::num_runs;expcount++) {

      cout<<genes[expcount]<<endl;

      totalgenes+=genes[expcount];

    }

    

    cout<<"Evals "<<endl;

    for(expcount=0;expcount<NEAT::num_runs;expcount++) {

      cout<<evals[expcount]<<endl;

      totalevals+=evals[expcount];

    }

    cout<<"Average Nodes: "<<((double) totalnodes/NEAT::num_runs)<<endl;

    cout<<"Average Genes: "<<((double) totalgenes/NEAT::num_runs)<<endl;

    cout<<"Average Evals: "<<((double) totalevals/NEAT::num_runs)<<endl;

    return pop;

}

bool xor_evaluate(Organism *org) {

  Network *net;

  double out[4]; //The four outputs

  double this_out; //The current output

  int count;

  double errorsum;

  bool success;  //Check for successful activation

  int numnodes;  /* Used to figure out how many nodes

   should be visited during activation */

  int net_depth; //The max depth of the network to be activated

  int relax; //Activates until relaxation

  //The four possible input combinations to xor

  //The first number is for biasing

  double in[4][3]={{1.0,0.0,0.0},

  {1.0,0.0,1.0},

  {1.0,1.0,0.0},

  {1.0,1.0,1.0}};

  

  net=org->net;

  numnodes=((org->gnome)->nodes).size();

  net_depth=net->max_depth();

  //TEST CODE: REMOVE

  //cout<<"ACTIVATING: "<<org->gnome<<endl;

  //cout<<"DEPTH: "<<net_depth<<endl;

  //Load and activate the network on each input

  for(count=0;count<=3;count++) {

    net->load_sensors(in[count]);

    //Relax net and get output

    success=net->activate();

    //use depth to ensure relaxation

    for (relax=0;relax<=net_depth;relax++) {

      success=net->activate();

      this_out=(*(net->outputs.begin()))->activation;

    }

    out[count]=(*(net->outputs.begin()))->activation;

    net->flush();

  }

  

  if (success) {

    errorsum=(fabs(out[0])+fabs(1.0-out[1])+fabs(1.0-out[2])+fabs(out[3]));

    org->fitness=pow((4.0-errorsum),2);

    org->error=errorsum;

  }

  else {

    //The network is flawed (shouldnt happen)

    errorsum=999.0;

    org->fitness=0.001;

  }

  #ifndef NO_SCREEN_OUT

  cout<<"Org "<<(org->gnome)->genome_id<<"                                     error: "<<errorsum<<"  ["<<out[0]<<" "<<out[1]<<" "<<out[2]<<" "<<out[3]<<"]"<<endl;

  cout<<"Org "<<(org->gnome)->genome_id<<"                                     fitness: "<<org->fitness<<endl;

  #endif

  //  if (errorsum<0.05) { 

  //if (errorsum<0.2) {

  if ((out[0]<0.5)&&(out[1]>=0.5)&&(out[2]>=0.5)&&(out[3]<0.5)) {

    org->winner=true;

    return true;

  }

  else {

    org->winner=false;

    return false;

  }

}

int xor_epoch(Population *pop,int generation,char *filename,int &winnernum,int &winnergenes,int &winnernodes) {

  vector<Organism*>::iterator curorg;

  vector<Species*>::iterator curspecies;

  //char cfilename[100];

  //strncpy( cfilename, filename.c_str(), 100 );

  //ofstream cfilename(filename.c_str());

  bool win=false;

  //Evaluate each organism on a test

  for(curorg=(pop->organisms).begin();curorg!=(pop->organisms).end();++curorg) {

    if (xor_evaluate(*curorg)) {

      win=true;

      winnernum=(*curorg)->gnome->genome_id;

      winnergenes=(*curorg)->gnome->extrons();

      winnernodes=((*curorg)->gnome->nodes).size();

      if (winnernodes==5) {

//You could dump out optimal genomes here if desired

//(*curorg)->gnome->print_to_filename("xor_optimal");

//cout<<"DUMPED OPTIMAL"<<endl;

      }

    }

  }

  

  //Average and max their fitnesses for dumping to file and snapshot

  for(curspecies=(pop->species).begin();curspecies!=(pop->species).end();++curspecies) {

    //This experiment control routine issues commands to collect ave

    //and max fitness, as opposed to having the snapshot do it, 

    //because this allows flexibility in terms of what time

    //to observe fitnesses at

    (*curspecies)->compute_average_fitness();

    (*curspecies)->compute_max_fitness();

  }

  //Take a snapshot of the population, so that it can be

  //visualized later on

  //if ((generation%1)==0)

  //  pop->snapshot();

  //Only print to file every print_every generations

  if  (win||

       ((generation%(NEAT::print_every))==0))

    pop->print_to_file_by_species(filename);

  if (win) {

    for(curorg=(pop->organisms).begin();curorg!=(pop->organisms).end();++curorg) {

      if ((*curorg)->winner) {

cout<<"WINNER IS #"<<((*curorg)->gnome)->genome_id<<endl;

//Prints the winner to file

//IMPORTANT: This causes generational file output!

print_Genome_tofile((*curorg)->gnome,"xor_winner");

      }

    }

    

  }

  pop->epoch(generation);

  if (win) return 1;

  else return 0;

}