Genome

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

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

#ifndef _GENOME_H_

#define _GENOME_H_

#include <vector>

#include "gene.h"

#include "innovation.h"

namespace NEAT {

enum mutator {

GAUSSIAN = 0,

COLDGAUSSIAN = 1

};

//----------------------------------------------------------------------- 

//A Genome is the primary source of genotype information used to create   

//a phenotype.  It contains 3 major constituents:                         

//  1) A list of Traits                                                 

//  2) A list of NNodes pointing to a Trait from (1)                      

//  3) A list of Genes with Links that point to Traits from (1)           

//(1) Reserved parameter space for future use

//(2) NNode specifications                                                

//(3) Is the primary source of innovation in the evolutionary Genome.     

//    Each Gene in (3) has a marker telling when it arose historically.   

//    Thus, these Genes can be used to speciate the population, and the   

//    list of Genes provide an evolutionary history of innovation and     

//    link-building.

class Genome {

public:

int genome_id;

std::vector<Trait*> traits; //parameter conglomerations

std::vector<NNode*> nodes; //List of NNodes for the Network

std::vector<Gene*> genes; //List of innovation-tracking genes

Network *phenotype; //Allows Genome to be matched with its Network

int get_last_node_id(); //Return id of final NNode in Genome

double get_last_gene_innovnum(); //Return last innovation number in Genome

void print_genome(); //Displays Genome on screen

//Constructor which takes full genome specs and puts them into the new one

Genome(int id, std::vector<Trait*> t, std::vector<NNode*> n, std::vector<Gene*> g);

//Constructor which takes in links (not genes) and creates a Genome

Genome(int id, std::vector<Trait*> t, std::vector<NNode*> n, std::vector<Link*> links);

// Copy constructor

Genome(const Genome& genome);

//Special constructor which spawns off an input file

//This constructor assumes that some routine has already read in GENOMESTART

        Genome(int id, std::ifstream &iFile);

// This special constructor creates a Genome

// with i inputs, o outputs, n out of nmax hidden units, and random

// connectivity.  If r is true then recurrent connections will

// be included. 

// The last input is a bias

// Linkprob is the probability of a link  

Genome(int new_id,int i, int o, int n,int nmax, bool r, double linkprob);

//Special constructor that creates a Genome of 3 possible types:

//0 - Fully linked, no hidden nodes

//1 - Fully linked, one hidden node splitting each link

//2 - Fully connected with a hidden layer, recurrent 

//num_hidden is only used in type 2

Genome(int num_in,int num_out,int num_hidden,int type);

// Loads a new Genome from a file (doesn't require knowledge of Genome's id)

static Genome *new_Genome_load(char *filename);

//Destructor kills off all lists (including the trait vector)

~Genome();

//Generate a network phenotype from this Genome with specified id

Network *genesis(int);

// Dump this genome to specified file

void print_to_file(std::ostream &outFile);

void print_to_file(std::ofstream &outFile);

// Wrapper for print_to_file above

void print_to_filename(char *filename);

// Duplicate this Genome to create a new one with the specified id 

Genome *duplicate(int new_id);

// For debugging: A number of tests can be run on a genome to check its

// integrity

// Note: Some of these tests do not indicate a bug, but rather are meant

// to be used to detect specific system states

bool verify();

// ******* MUTATORS *******

// Perturb params in one trait

void mutate_random_trait();

// Change random link's trait. Repeat times times

void mutate_link_trait(int times);

// Change random node's trait times times 

void mutate_node_trait(int times);

// Add Gaussian noise to linkweights either GAUSSIAN or COLDGAUSSIAN (from zero)

void mutate_link_weights(double power,double rate,mutator mut_type);

// toggle genes on or off 

void mutate_toggle_enable(int times);

// Find first disabled gene and enable it 

void mutate_gene_reenable();

// These last kinds of mutations return false if they fail

//   They can fail under certain conditions,  being unable

//   to find a suitable place to make the mutation.

//   Generally, if they fail, they can be called again if desired. 

// Mutate genome by adding a node respresentation 

bool mutate_add_node(std::vector<Innovation*> &innovs,int &curnode_id,double &curinnov);

// Mutate the genome by adding a new link between 2 random NNodes 

bool mutate_add_link(std::vector<Innovation*> &innovs,double &curinnov,int tries); 

void mutate_add_sensor(std::vector<Innovation*> &innovs, double &curinnov);

// ****** MATING METHODS ***** 

// This method mates this Genome with another Genome g.  

//   For every point in each Genome, where each Genome shares

//   the innovation number, the Gene is chosen randomly from 

//   either parent.  If one parent has an innovation absent in 

//   the other, the baby will inherit the innovation 

//   Interspecies mating leads to all genes being inherited.

//   Otherwise, excess genes come from most fit parent.

Genome *mate_multipoint(Genome *g,int genomeid,double fitness1, double fitness2, bool interspec_flag);

//This method mates like multipoint but instead of selecting one

//   or the other when the innovation numbers match, it averages their

//   weights 

Genome *mate_multipoint_avg(Genome *g,int genomeid,double fitness1,double fitness2, bool interspec_flag);

// This method is similar to a standard single point CROSSOVER

//   operator.  Traits are averaged as in the previous 2 mating

//   methods.  A point is chosen in the smaller Genome for crossing

//   with the bigger one.  

Genome *mate_singlepoint(Genome *g,int genomeid);

// ******** COMPATIBILITY CHECKING METHODS ********

// This function gives a measure of compatibility between

//   two Genomes by computing a linear combination of 3

//   characterizing variables of their compatibilty.

//   The 3 variables represent PERCENT DISJOINT GENES, 

//   PERCENT EXCESS GENES, MUTATIONAL DIFFERENCE WITHIN

//   MATCHING GENES.  So the formula for compatibility 

//   is:  disjoint_coeff*pdg+excess_coeff*peg+mutdiff_coeff*mdmg.

//   The 3 coefficients are global system parameters 

double compatibility(Genome *g);

double trait_compare(Trait *t1,Trait *t2);

// Return number of non-disabled genes 

int extrons();

// Randomize the trait pointers of all the node and connection genes 

void randomize_traits();

protected:

//Inserts a NNode into a given ordered list of NNodes in order

void node_insert(std::vector<NNode*> &nlist, NNode *n);

//Adds a new gene that has been created through a mutation in the

//*correct order* into the list of genes in the genome

void add_gene(std::vector<Gene*> &glist,Gene *g);

};

//Calls special constructor that creates a Genome of 3 possible types:

//0 - Fully linked, no hidden nodes

//1 - Fully linked, one hidden node splitting each link

//2 - Fully connected with a hidden layer 

//num_hidden is only used in type 2

//Saves to file "auto_genome"

Genome *new_Genome_auto(int num_in,int num_out,int num_hidden,int type, const char *filename);

void print_Genome_tofile(Genome *g,const char *filename);

} // namespace NEAT

#endif

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

#include "genome.h"

#include <iostream>

#include <cmath>

#include <sstream>

using namespace NEAT;

Genome::Genome(int id, std::vector<Trait*> t, std::vector<NNode*> n, std::vector<Gene*> g) {

genome_id=id;

traits=t;

nodes=n; 

genes=g;

}

Genome::Genome(int id, std::vector<Trait*> t, std::vector<NNode*> n, std::vector<Link*> links) {

std::vector<Link*>::iterator curlink;

Gene *tempgene;

traits=t;

nodes=n;

genome_id=id;

//We go through the links and turn them into original genes

for(curlink=links.begin();curlink!=links.end();++curlink) {

//Create genes one at a time

tempgene=new Gene((*curlink)->linktrait, (*curlink)->weight,(*curlink)->in_node,(*curlink)->out_node,(*curlink)->is_recurrent,1.0,0.0);

genes.push_back(tempgene);

}

}

Genome::Genome(const Genome& genome)

{

genome_id = genome.genome_id;

std::vector<Trait*>::const_iterator curtrait;

std::vector<NNode*>::const_iterator curnode;

std::vector<Gene*>::const_iterator curgene;

for(curtrait=genome.traits.begin(); curtrait!=genome.traits.end(); ++curtrait) {

traits.push_back(new Trait(**curtrait));

}

Trait *assoc_trait;

//Duplicate NNodes

for(curnode=genome.nodes.begin();curnode!=genome.nodes.end();++curnode) {

//First, find the trait that this node points to

if (((*curnode)->nodetrait)==0) assoc_trait=0;

else {

curtrait=traits.begin();

while(((*curtrait)->trait_id)!=(((*curnode)->nodetrait)->trait_id))

++curtrait;

assoc_trait=(*curtrait);

}

NNode* newnode=new NNode(*curnode,assoc_trait);

(*curnode)->dup=newnode;  //Remember this node's old copy

//    (*curnode)->activation_count=55;

nodes.push_back(newnode);    

}

NNode *inode; //For forming a gene 

NNode *onode; //For forming a gene

Trait *traitptr;

//Duplicate Genes

for(curgene=genome.genes.begin(); curgene!=genome.genes.end(); ++curgene) {

//First find the nodes connected by the gene's link

inode=(((*curgene)->lnk)->in_node)->dup;

onode=(((*curgene)->lnk)->out_node)->dup;

//Get a pointer to the trait expressed by this gene

traitptr=((*curgene)->lnk)->linktrait;

if (traitptr==0) assoc_trait=0;

else {

curtrait=traits.begin();

while(((*curtrait)->trait_id)!=(traitptr->trait_id))

++curtrait;

assoc_trait=(*curtrait);

}

Gene* newgene=new Gene(*curgene,assoc_trait,inode,onode);

genes.push_back(newgene);

}

}

Genome::Genome(int id, std::ifstream &iFile) {

char curword[128];  //max word size of 128 characters

char curline[1024]; //max line size of 1024 characters

char delimiters[] = " \n";

int done=0;

//int pause;

genome_id=id;

iFile.getline(curline, sizeof(curline));

int wordcount = NEAT::getUnitCount(curline, delimiters);

int curwordnum = 0;

//Loop until file is finished, parsing each line

while (!done) {

        //std::cout << curline << std::endl;

if (curwordnum > wordcount || wordcount == 0) {

iFile.getline(curline, sizeof(curline));

wordcount = NEAT::getUnitCount(curline, delimiters);

curwordnum = 0;

}

        

        std::stringstream ss(curline);

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

        ss >> curword;

//printf(curword);

//printf(" test\n");

//Check for end of Genome

if (strcmp(curword,"genomeend")==0) {

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

            ss >> curword;

int idcheck = atoi(curword);

//iFile>>idcheck;

if (idcheck!=genome_id) printf("ERROR: id mismatch in genome");

done=1;

}

//Ignore genomestart if it hasn't been gobbled yet

else if (strcmp(curword,"genomestart")==0) {

++curwordnum;

//cout<<"genomestart"<<endl;

}

//Ignore comments surrounded by - they get printed to screen

else if (strcmp(curword,"/*")==0) {

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

            ss >> curword;

while (strcmp(curword,"*/")!=0) {

//cout<<curword<<" ";

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

                ss >> curword;

}

//cout<<endl;

}

//Read in a trait

else if (strcmp(curword,"trait")==0) {

Trait *newtrait;

char argline[1024];

//strcpy(argline, NEAT::getUnits(curline, curwordnum, wordcount, delimiters));

curwordnum = wordcount + 1;

            ss.getline(argline, 1024);

//Allocate the new trait

newtrait=new Trait(argline);

//Add trait to vector of traits

traits.push_back(newtrait);

}

//Read in a node

else if (strcmp(curword,"node")==0) {

NNode *newnode;

char argline[1024];

//strcpy(argline, NEAT::getUnits(curline, curwordnum, wordcount, delimiters));

curwordnum = wordcount + 1;

            

            ss.getline(argline, 1024);

//Allocate the new node

newnode=new NNode(argline,traits);

//Add the node to the list of nodes

nodes.push_back(newnode);

}

//Read in a Gene

else if (strcmp(curword,"gene")==0) {

Gene *newgene;

char argline[1024];

//strcpy(argline, NEAT::getUnits(curline, curwordnum, wordcount, delimiters));

curwordnum = wordcount + 1;

            ss.getline(argline, 1024);

            //std::cout << "New gene: " << ss.str() << std::endl;

//Allocate the new Gene

            newgene=new Gene(argline,traits,nodes);

//Add the gene to the genome

genes.push_back(newgene);

            //std::cout<<"Added gene " << newgene << std::endl;

}

}

}

Genome::Genome(int new_id,int i, int o, int n,int nmax, bool r, double linkprob) {

int totalnodes;

bool *cm; //The connection matrix which will be randomized

bool *cmp; //Connection matrix pointer

int matrixdim;

int count;

int ncount; //Node and connection counters

int ccount;

int row;  //For navigating the matrix

int col;

double new_weight;

int maxnode; //No nodes above this number for this genome

int first_output; //Number of first output node

totalnodes=i+o+nmax;

matrixdim=totalnodes*totalnodes;

cm=new bool[matrixdim];  //Dimension the connection matrix

maxnode=i+n;

first_output=totalnodes-o+1;

//For creating the new genes

NNode *newnode;

Gene *newgene;

Trait *newtrait;

NNode *in_node;

NNode *out_node;

//Retrieves the nodes pointed to by connection genes

std::vector<NNode*>::iterator node_iter;

//Assign the id

genome_id=new_id;

//cout<<"Assigned id "<<genome_id<<endl;

//Step through the connection matrix, randomly assigning bits

cmp=cm;

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

if (randfloat()<linkprob)

*cmp=true;

else *cmp=false;

cmp++;

}

//Create a dummy trait (this is for future expansion of the system)

newtrait=new Trait(1,0,0,0,0,0,0,0,0,0);

traits.push_back(newtrait);

//Build the input nodes

for(ncount=1;ncount<=i;ncount++) {

if (ncount<i)

newnode=new NNode(SENSOR,ncount,INPUT);

else newnode=new NNode(SENSOR,ncount,BIAS);

newnode->nodetrait=newtrait;

//Add the node to the list of nodes

nodes.push_back(newnode);

}

//Build the hidden nodes

for(ncount=i+1;ncount<=i+n;ncount++) {

newnode=new NNode(NEURON,ncount,HIDDEN);

newnode->nodetrait=newtrait;

//Add the node to the list of nodes

nodes.push_back(newnode);

}

//Build the output nodes

for(ncount=first_output;ncount<=totalnodes;ncount++) {

newnode=new NNode(NEURON,ncount,OUTPUT);

newnode->nodetrait=newtrait;

//Add the node to the list of nodes

nodes.push_back(newnode);

}

//cout<<"Built nodes"<<endl;

//Connect the nodes 

ccount=1;  //Start the connection counter

//Step through the connection matrix, creating connection genes

cmp=cm;

count=0;

for(col=1;col<=totalnodes;col++)

for(row=1;row<=totalnodes;row++) {

//Only try to create a link if it is in the matrix

//and not leading into a sensor

if ((*cmp==true)&&(col>i)&&

((col<=maxnode)||(col>=first_output))&&

((row<=maxnode)||(row>=first_output))) {

//If it isn't recurrent, create the connection no matter what

if (col>row) {

//Retrieve the in_node

node_iter=nodes.begin();

while((*node_iter)->node_id!=row)

node_iter++;

in_node=(*node_iter);

//Retrieve the out_node

node_iter=nodes.begin();

while((*node_iter)->node_id!=col)

node_iter++;

out_node=(*node_iter);

//Create the gene

new_weight=randposneg()*randfloat();

newgene=new Gene(newtrait,new_weight, in_node, out_node,false,count,new_weight);

//Add the gene to the genome

genes.push_back(newgene);

}

else if (r) {

//Create a recurrent connection

//Retrieve the in_node

node_iter=nodes.begin();

while((*node_iter)->node_id!=row)

node_iter++;

in_node=(*node_iter);

//Retrieve the out_node

node_iter=nodes.begin();

while((*node_iter)->node_id!=col)

node_iter++;

out_node=(*node_iter);

//Create the gene

new_weight=randposneg()*randfloat();

newgene=new Gene(newtrait,new_weight, in_node, out_node,true,count,new_weight);

//Add the gene to the genome

genes.push_back(newgene);

}

}

count++; //increment gene counter    

cmp++;

}

delete [] cm;

}

Genome::Genome(int num_in,int num_out,int num_hidden,int type) {

//Temporary lists of nodes

std::vector<NNode*> inputs;

std::vector<NNode*> outputs;

std::vector<NNode*> hidden;

NNode *bias; //Remember the bias

std::vector<NNode*>::iterator curnode1; //Node iterator1

std::vector<NNode*>::iterator curnode2; //Node iterator2

std::vector<NNode*>::iterator curnode3; //Node iterator3

//For creating the new genes

NNode *newnode;

Gene *newgene;

Trait *newtrait;

int count;

int ncount;

//Assign the id 0

genome_id=0;

//Create a dummy trait (this is for future expansion of the system)

newtrait=new Trait(1,0,0,0,0,0,0,0,0,0);

traits.push_back(newtrait);

//Adjust hidden number

if (type==0) 

num_hidden=0;

else if (type==1)

num_hidden=num_in*num_out;

//Create the inputs and outputs

//Build the input nodes

for(ncount=1;ncount<=num_in;ncount++) {

if (ncount<num_in)

newnode=new NNode(SENSOR,ncount,INPUT);

else { 

newnode=new NNode(SENSOR,ncount,BIAS);

bias=newnode;

}

//newnode->nodetrait=newtrait;

//Add the node to the list of nodes

nodes.push_back(newnode);

inputs.push_back(newnode);

}

//Build the hidden nodes

for(ncount=num_in+1;ncount<=num_in+num_hidden;ncount++) {

newnode=new NNode(NEURON,ncount,HIDDEN);

//newnode->nodetrait=newtrait;

//Add the node to the list of nodes

nodes.push_back(newnode);

hidden.push_back(newnode);

}

//Build the output nodes

for(ncount=num_in+num_hidden+1;ncount<=num_in+num_hidden+num_out;ncount++) {

newnode=new NNode(NEURON,ncount,OUTPUT);

//newnode->nodetrait=newtrait;

//Add the node to the list of nodes

nodes.push_back(newnode);

outputs.push_back(newnode);

}

//Create the links depending on the type

if (type==0) {

//Just connect inputs straight to outputs

count=1;

//Loop over the outputs

for(curnode1=outputs.begin();curnode1!=outputs.end();++curnode1) {

//Loop over the inputs

for(curnode2=inputs.begin();curnode2!=inputs.end();++curnode2) {

//Connect each input to each output

newgene=new Gene(newtrait,0, (*curnode2), (*curnode1),false,count,0);

//Add the gene to the genome

genes.push_back(newgene);  

count++;

}

}

} //end type 0

//A split link from each input to each output

else if (type==1) {

count=1; //Start the gene number counter

curnode3=hidden.begin(); //One hidden for ever input-output pair

//Loop over the outputs

for(curnode1=outputs.begin();curnode1!=outputs.end();++curnode1) {

//Loop over the inputs

for(curnode2=inputs.begin();curnode2!=inputs.end();++curnode2) {

//Connect Input to hidden

newgene=new Gene(newtrait,0, (*curnode2), (*curnode3),false,count,0);

//Add the gene to the genome

genes.push_back(newgene);

count++; //Next gene

//Connect hidden to output

newgene=new Gene(newtrait,0, (*curnode3), (*curnode1),false,count,0);

//Add the gene to the genome

genes.push_back(newgene);

++curnode3; //Next hidden node

count++; //Next gene

}

}

}//end type 1

//Fully connected 

else if (type==2) {

count=1; //Start gene counter at 1

//Connect all inputs to all hidden nodes

for(curnode1=hidden.begin();curnode1!=hidden.end();++curnode1) {

//Loop over the inputs

for(curnode2=inputs.begin();curnode2!=inputs.end();++curnode2) {

//Connect each input to each hidden

newgene=new Gene(newtrait,0, (*curnode2), (*curnode1),false,count,0);

//Add the gene to the genome

genes.push_back(newgene);  

count++;

}

}

//Connect all hidden units to all outputs

for(curnode1=outputs.begin();curnode1!=outputs.end();++curnode1) {

//Loop over the inputs

for(curnode2=hidden.begin();curnode2!=hidden.end();++curnode2) {

//Connect each input to each hidden

newgene=new Gene(newtrait,0, (*curnode2), (*curnode1),false,count,0);

//Add the gene to the genome

genes.push_back(newgene);  

count++;

}

}

//Connect the bias to all outputs

for(curnode1=outputs.begin();curnode1!=outputs.end();++curnode1) {

newgene=new Gene(newtrait,0, bias, (*curnode1),false,count,0);

//Add the gene to the genome

genes.push_back(newgene);  

count++;

}

//Recurrently connect the hidden nodes

for(curnode1=hidden.begin();curnode1!=hidden.end();++curnode1) {

//Loop Over all Hidden

for(curnode2=hidden.begin();curnode2!=hidden.end();++curnode2) {

//Connect each hidden to each hidden

newgene=new Gene(newtrait,0, (*curnode2), (*curnode1),true,count,0);

//Add the gene to the genome

genes.push_back(newgene);  

count++;

}

}

}//end type 2

}

Genome* Genome::new_Genome_load(char *filename) {

Genome *newgenome;

int id;

//char curline[1024];

char curword[20];  //max word size of 20 characters

//char delimiters[] = " \n";

//int curwordnum = 0;

std::ifstream iFile(filename);

//Make sure it worked

//if (!iFile) {

// cerr<<"Can't open "<<filename<<" for input"<<endl;

// return 0;

//}

iFile>>curword;

//iFile.getline(curline, sizeof(curline));

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

//Bypass initial comment

if (strcmp(curword,"/*")==0) {

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

iFile>>curword;

while (strcmp(curword,"*/")!=0) {

printf("%s ",curword);

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

iFile>>curword;

}

//cout<<endl;

iFile>>curword;

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

}

//strcpy(curword, NEAT::getUnit(curline, curwordnum++, delimiters));

//id = atoi(curword);

iFile>>id;

newgenome=new Genome(id,iFile);

iFile.close();

return newgenome;

}

Genome::~Genome() {

std::vector<Trait*>::iterator curtrait;

std::vector<NNode*>::iterator curnode;

std::vector<Gene*>::iterator curgene;

for(curtrait=traits.begin();curtrait!=traits.end();++curtrait) {

delete (*curtrait);

}

for(curnode=nodes.begin();curnode!=nodes.end();++curnode) {

delete (*curnode);

}

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

delete (*curgene);

}

}

Network *Genome::genesis(int id) {

std::vector<NNode*>::iterator curnode; 

std::vector<Gene*>::iterator curgene;

NNode *newnode;

Trait *curtrait;

Link *curlink;

Link *newlink;

double maxweight=0.0; //Compute the maximum weight for adaptation purposes

double weight_mag; //Measures absolute value of weights

//Inputs and outputs will be collected here for the network

//All nodes are collected in an all_list- 

//this will be used for later safe destruction of the net

std::vector<NNode*> inlist;

std::vector<NNode*> outlist;

std::vector<NNode*> all_list;

//Gene translation variables

NNode *inode;

NNode *onode;

//The new network

Network *newnet;

//Create the nodes

for(curnode=nodes.begin();curnode!=nodes.end();++curnode) {

newnode=new NNode((*curnode)->type,(*curnode)->node_id);

//Derive the node parameters from the trait pointed to

curtrait=(*curnode)->nodetrait;

newnode->derive_trait(curtrait);

//Check for input or output designation of node

if (((*curnode)->gen_node_label)==INPUT) 

inlist.push_back(newnode);

if (((*curnode)->gen_node_label)==BIAS) 

inlist.push_back(newnode);

if (((*curnode)->gen_node_label)==OUTPUT)

outlist.push_back(newnode);

//Keep track of all nodes, not just input and output

all_list.push_back(newnode);

//Have the node specifier point to the node it generated

(*curnode)->analogue=newnode;

}

//Create the links by iterating through the genes

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

//Only create the link if the gene is enabled

if (((*curgene)->enable)==true) {

curlink=(*curgene)->lnk;

inode=(curlink->in_node)->analogue;

onode=(curlink->out_node)->analogue;

//NOTE: This line could be run through a recurrency check if desired

// (no need to in the current implementation of NEAT)

newlink=new Link(curlink->weight,inode,onode,curlink->is_recurrent);

(onode->incoming).push_back(newlink);

(inode->outgoing).push_back(newlink);

//Derive link's parameters from its Trait pointer

curtrait=(curlink->linktrait);

newlink->derive_trait(curtrait);

//Keep track of maximum weight

if (newlink->weight>0)

weight_mag=newlink->weight;

else weight_mag=-newlink->weight;

if (weight_mag>maxweight)

maxweight=weight_mag;

}

}

//Create the new network

newnet=new Network(inlist,outlist,all_list,id);

//Attach genotype and phenotype together

newnet->genotype=this;

phenotype=newnet;

newnet->maxweight=maxweight;

return newnet;

}

bool Genome::verify() {

std::vector<NNode*>::iterator curnode;

std::vector<Gene*>::iterator curgene;

std::vector<Gene*>::iterator curgene2;

NNode *inode;

NNode *onode;

bool disab;

int last_id;

//int pause;

//cout<<"Verifying Genome id: "<<this->genome_id<<endl;

if (this==0) {

//cout<<"ERROR GENOME EMPTY"<<endl;

//cin>>pause;

}

//Check each gene's nodes

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

inode=((*curgene)->lnk)->in_node;

onode=((*curgene)->lnk)->out_node;

//Look for inode

curnode=nodes.begin();

while((curnode!=nodes.end())&&

((*curnode)!=inode))

++curnode;

if (curnode==nodes.end()) {

//cout<<"MISSING iNODE FROM GENE NOT IN NODES OF GENOME!!"<<endl;

//cin>>pause;

return false;

}

//Look for onode

curnode=nodes.begin();

while((curnode!=nodes.end())&&

((*curnode)!=onode))

++curnode;

if (curnode==nodes.end()) {

//cout<<"MISSING oNODE FROM GENE NOT IN NODES OF GENOME!!"<<endl;

//cin>>pause;

return false;

}

}

//Check for NNodes being out of order

last_id=0;

for(curnode=nodes.begin();curnode!=nodes.end();++curnode) {

if ((*curnode)->node_id<last_id) {

//cout<<"ALERT: NODES OUT OF ORDER in "<<this<<endl;

//cin>>pause;

return false;

}

last_id=(*curnode)->node_id;

}

//Make sure there are no duplicate genes

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

for(curgene2=genes.begin();curgene2!=genes.end();++curgene2) {

if (((*curgene)!=(*curgene2))&&

((((*curgene)->lnk)->is_recurrent)==(((*curgene2)->lnk)->is_recurrent))&&

((((((*curgene2)->lnk)->in_node)->node_id)==((((*curgene)->lnk)->in_node)->node_id))&&

(((((*curgene2)->lnk)->out_node)->node_id)==((((*curgene)->lnk)->out_node)->node_id)))) {

//cout<<"ALERT: DUPLICATE GENES: "<<(*curgene)<<(*curgene2)<<endl;

//cout<<"INSIDE GENOME: "<<this<<endl;

//cin>>pause;

}

}

}

//See if a gene is not disabled properly

//Note this check does not necessary mean anything is wrong

//

//if (nodes.size()>=15) {

//disab=false;

////Go through genes and see if one is disabled

//for(curgene=genes.begin();curgene!=genes.end();++curgene) {

//if (((*curgene)->enable)==false) disab=true;

//}

//if (disab==false) {

//cout<<"ALERT: NO DISABLED GENE IN GENOME: "<<this<<endl;

////cin>>pause;

//}

//}

//

//Check for 2 disables in a row

//Note:  Again, this is not necessarily a bad sign

if (nodes.size()>=500) {

disab=false;

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

if ((((*curgene)->enable)==false)&&(disab==true)) {

//cout<<"ALERT: 2 DISABLES IN A ROW: "<<this<<endl;

}

if (((*curgene)->enable)==false) disab=true;

else disab=false;

}

}

//cout<<"GENOME OK!"<<endl;

return true;

}

//Print the genome to a file

void Genome::print_to_file(std::ofstream &outFile) {

  std::vector<Trait*>::iterator curtrait;

  std::vector<NNode*>::iterator curnode;

  std::vector<Gene*>::iterator curgene;

  outFile<<"genomestart "<<genome_id<<std::endl;

  //Output the traits

  for(curtrait=traits.begin();curtrait!=traits.end();++curtrait) {

    (*curtrait)->trait_id=curtrait-traits.begin()+1;

    (*curtrait)->print_to_file(outFile);

  }

  //Output the nodes

  for(curnode=nodes.begin();curnode!=nodes.end();++curnode) {

    (*curnode)->print_to_file(outFile);

  }

  //Output the genes

  for(curgene=genes.begin();curgene!=genes.end();++curgene) {

    (*curgene)->print_to_file(outFile);

  }

  outFile<<"genomeend "<<genome_id<<std::endl;

}

void Genome::print_to_file(std::ostream &outFile) {

std::vector<Trait*>::iterator curtrait;

std::vector<NNode*>::iterator curnode;

std::vector<Gene*>::iterator curgene;

//char tempbuf[128];

//sprintf(tempbuf, "genomestart %d\n", genome_id);

//outFile.write(strlen(tempbuf), tempbuf);

    outFile<<"genomestart "<<genome_id<<std::endl;

//Output the traits

for(curtrait=traits.begin();curtrait!=traits.end();++curtrait) {

(*curtrait)->trait_id=curtrait-traits.begin()+1;

(*curtrait)->print_to_file(outFile);

}

//Output the nodes

for(curnode=nodes.begin();curnode!=nodes.end();++curnode) {

(*curnode)->print_to_file(outFile);

}

//Output the genes

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

(*curgene)->print_to_file(outFile);

}

//char tempbuf2[128];

//sprintf(tempbuf2, sizeof(tempbuf2), "genomeend %d\n", genome_id);

//outFile.write(strlen(tempbuf2), tempbuf2);

    outFile << "genomeend " << genome_id << std::endl << std::endl << std::endl;

//char tempbuf4[1024];

//sprintf(tempbuf4, sizeof(tempbuf4), "\n\n");

//outFile.write(strlen(tempbuf4), tempbuf4);

}

void Genome::print_to_filename(char *filename) {

std::ofstream oFile(filename);

//oFile.open(filename, std::ostream::Write);

print_to_file(oFile);

oFile.close();

}

int Genome::get_last_node_id() {

return ((*(nodes.end() - 1))->node_id)+1;

}

double Genome::get_last_gene_innovnum() {

return ((*(genes.end() - 1))->innovation_num)+1;

}

Genome *Genome::duplicate(int new_id) {

//Collections for the new Genome

std::vector<Trait*> traits_dup;

std::vector<NNode*> nodes_dup;

std::vector<Gene*> genes_dup;

//Iterators for the old Genome

std::vector<Trait*>::iterator curtrait;

std::vector<NNode*>::iterator curnode;

std::vector<Gene*>::iterator curgene;

//New item pointers

Trait *newtrait;

NNode *newnode;

Gene *newgene;

Trait *assoc_trait;  //Trait associated with current item

NNode *inode; //For forming a gene 

NNode *onode; //For forming a gene

Trait *traitptr;

Genome *newgenome;

//verify();

//Duplicate the traits

for(curtrait=traits.begin();curtrait!=traits.end();++curtrait) {

newtrait=new Trait(*curtrait);

traits_dup.push_back(newtrait);

}

//Duplicate NNodes

for(curnode=nodes.begin();curnode!=nodes.end();++curnode) {

//First, find the trait that this node points to

if (((*curnode)->nodetrait)==0) assoc_trait=0;

else {

curtrait=traits_dup.begin();

while(((*curtrait)->trait_id)!=(((*curnode)->nodetrait)->trait_id))

++curtrait;

assoc_trait=(*curtrait);

}

newnode=new NNode(*curnode,assoc_trait);

(*curnode)->dup=newnode;  //Remember this node's old copy

//    (*curnode)->activation_count=55;

nodes_dup.push_back(newnode);    

}

//Duplicate Genes

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

//First find the nodes connected by the gene's link

inode=(((*curgene)->lnk)->in_node)->dup;

onode=(((*curgene)->lnk)->out_node)->dup;

//Get a pointer to the trait expressed by this gene

traitptr=((*curgene)->lnk)->linktrait;

if (traitptr==0) assoc_trait=0;

else {

curtrait=traits_dup.begin();

while(((*curtrait)->trait_id)!=(traitptr->trait_id))

++curtrait;

assoc_trait=(*curtrait);

}

newgene=new Gene(*curgene,assoc_trait,inode,onode);

genes_dup.push_back(newgene);

}

//Finally, return the genome

newgenome=new Genome(new_id,traits_dup,nodes_dup,genes_dup);

return newgenome;

}

void Genome::mutate_random_trait() {

std::vector<Trait*>::iterator thetrait; //Trait to be mutated

int traitnum;

//Choose a random traitnum

traitnum=randint(0,(traits.size())-1);

//Retrieve the trait and mutate it

thetrait=traits.begin();

(*(thetrait[traitnum])).mutate();

//TRACK INNOVATION? (future possibility)

}

void Genome::mutate_link_trait(int times) {

int traitnum;

int genenum;

std::vector<Gene*>::iterator thegene;     //Link to be mutated

std::vector<Trait*>::iterator thetrait; //Trait to be attached

int count;

int loop;

for(loop=1;loop<=times;loop++) {

//Choose a random traitnum

traitnum=randint(0,(traits.size())-1);

//Choose a random linknum

genenum=randint(0,genes.size()-1);

//set the link to point to the new trait

thegene=genes.begin();

for(count=0;count<genenum;count++)

++thegene;

//Do not alter frozen genes

if (!((*thegene)->frozen)) {

thetrait=traits.begin();

((*thegene)->lnk)->linktrait=thetrait[traitnum];

}

//TRACK INNOVATION- future use

//(*thegene)->mutation_num+=randposneg()*randfloat()*linktrait_mut_sig;

}

}

void Genome::mutate_node_trait(int times) {

int traitnum;

int nodenum;

std::vector<NNode*>::iterator thenode;     //Link to be mutated

std::vector<Gene*>::iterator thegene;  //Gene to record innovation

std::vector<Trait*>::iterator thetrait; //Trait to be attached

int count;

int loop;

for(loop=1;loop<=times;loop++) {

//Choose a random traitnum

traitnum=randint(0,(traits.size())-1);

//Choose a random nodenum

nodenum=randint(0,nodes.size()-1);

//set the link to point to the new trait

thenode=nodes.begin();

for(count=0;count<nodenum;count++)

++thenode;

//Do not mutate frozen nodes

if (!((*thenode)->frozen)) {

thetrait=traits.begin();

(*thenode)->nodetrait=thetrait[traitnum];

}

//TRACK INNOVATION! - possible future use

//for any gene involving the mutated node, perturb that gene's

//mutation number

//for(thegene=genes.begin();thegene!=genes.end();++thegene) {

//  if (((((*thegene)->lnk)->in_node)==(*thenode))

//  ||

//  ((((*thegene)->lnk)->out_node)==(*thenode)))

//(*thegene)->mutation_num+=randposneg()*randfloat()*nodetrait_mut_sig;

//}

}

}

void Genome::mutate_link_weights(double power,double rate,mutator mut_type) {

std::vector<Gene*>::iterator curgene;

double num;  //counts gene placement

double gene_total;

double powermod; //Modified power by gene number

//The power of mutation will rise farther into the genome

//on the theory that the older genes are more fit since

//they have stood the test of time

double randnum;

double randchoice; //Decide what kind of mutation to do on a gene

double endpart; //Signifies the last part of the genome

double gausspoint;

double coldgausspoint;

bool severe;  //Once in a while really shake things up

//Wright variables

//double oldval;

//double perturb;

// --------------- WRIGHT'S MUTATION METHOD -------------- 

////Use the fact that we know ends are newest

//gene_total=(double) genes.size();

//endpart=gene_total*0.8;

//num=0.0;

//for(curgene=genes.begin();curgene!=genes.end();curgene++) {

////Mutate rate 0.2 controls how many params mutate in the list

//if ((randfloat()<rate)||

//((gene_total>=10.0)&&(num>endpart))) {

//oldval=((*curgene)->lnk)->weight;

////The amount to perturb the value by

//perturb=randfloat()*power;

////Once in a while leave the end part alone

//if (num>endpart)

//if (randfloat()<0.2) perturb=0;  

////Decide positive or negative

//if (gRandGen.randI()%2) {

////Positive case

////if it goes over the max, find something smaller

//if (oldval+perturb>100.0) {

//perturb=(100.0-oldval)*randfloat();

//}

//((*curgene)->lnk)->weight+=perturb;

//}

//else {

////Negative case

////if it goes below the min, find something smaller

//if (oldval-perturb<100.0) {

//perturb=(oldval+100.0)*randfloat();

//}

//((*curgene)->lnk)->weight-=perturb;

//}

//}

//num+=1.0;

//}


// ------------------------------------------------------ 

if (randfloat()>0.5) severe=true;

else severe=false;

//Go through all the Genes and perturb their link's weights

num=0.0;

gene_total=(double) genes.size();

endpart=gene_total*0.8;

//powermod=randposneg()*power*randfloat();  //Make power of mutation random

//powermod=randfloat();

powermod=1.0;

//Possibility: Jiggle the newest gene randomly

//if (gene_total>10.0) {

//  lastgene=genes.end();

//  lastgene--;

//  if (randfloat()>0.4)

//    ((*lastgene)->lnk)->weight+=0.5*randposneg()*randfloat();

//}

/*

//KENHACK: NOTE THIS HAS BEEN MAJORLY ALTERED

//     THE LOOP BELOW IS THE ORIGINAL METHOD

if (mut_type==COLDGAUSSIAN) {

//printf("COLDGAUSSIAN");

for(curgene=genes.begin();curgene!=genes.end();curgene++) {

if (randfloat()<0.9) {

randnum=randposneg()*randfloat()*power*powermod;

((*curgene)->lnk)->weight+=randnum;

}

}

}


for(curgene=genes.begin();curgene!=genes.end();curgene++) {

if (randfloat()<0.2) {

randnum=randposneg()*randfloat()*power*powermod;

((*curgene)->lnk)->weight+=randnum;

//Cap the weights at 20.0 (experimental)

if (((*curgene)->lnk)->weight>1.0) ((*curgene)->lnk)->weight=1.0;

else if (((*curgene)->lnk)->weight<-1.0) ((*curgene)->lnk)->weight=-1.0;

}

}

*/

//Loop on all genes  (ORIGINAL METHOD)

for(curgene=genes.begin();curgene!=genes.end();curgene++) {


//Possibility: Have newer genes mutate with higher probability

//Only make mutation power vary along genome if it's big enough

//if (gene_total>=10.0) {

//This causes the mutation power to go up towards the end up the genome

//powermod=((power-0.7)/gene_total)*num+0.7;

//}

//else powermod=power;

//The following if determines the probabilities of doing cold gaussian

//mutation, meaning the probability of replacing a link weight with

//another, entirely random weight.  It is meant to bias such mutations

//to the tail of a genome, because that is where less time-tested genes

//reside.  The gausspoint and coldgausspoint represent values above

//which a random float will signify that kind of mutation.  

//Don't mutate weights of frozen links

if (!((*curgene)->frozen)) {

if (severe) {

gausspoint=0.3;

coldgausspoint=0.1;

}

else if ((gene_total>=10.0)&&(num>endpart)) {

gausspoint=0.5;  //Mutate by modification % of connections

coldgausspoint=0.3; //Mutate the rest by replacement % of the time

}

else {

//Half the time don't do any cold mutations

if (randfloat()>0.5) {

gausspoint=1.0-rate;

coldgausspoint=1.0-rate-0.1;

}

else {

gausspoint=1.0-rate;

coldgausspoint=1.0-rate;

}

}

//Possible methods of setting the perturbation:

//randnum=gaussrand()*powermod;

//randnum=gaussrand();

randnum=randposneg()*randfloat()*power*powermod;

            //std::cout << "RANDOM: " << randnum << " " << randposneg() << " " << randfloat() << " " << power << " " << powermod << std::endl;

if (mut_type==GAUSSIAN) {

randchoice=randfloat();

if (randchoice>gausspoint)

((*curgene)->lnk)->weight+=randnum;

else if (randchoice>coldgausspoint)

((*curgene)->lnk)->weight=randnum;

}

else if (mut_type==COLDGAUSSIAN)

((*curgene)->lnk)->weight=randnum;

//Cap the weights at 20.0 (experimental)

if (((*curgene)->lnk)->weight > 3.0) ((*curgene)->lnk)->weight = 3.0;

else if (((*curgene)->lnk)->weight < -3.0) ((*curgene)->lnk)->weight = -3.0;

//Record the innovation

//(*curgene)->mutation_num+=randnum;

(*curgene)->mutation_num=((*curgene)->lnk)->weight;

num+=1.0;

}

} //end for loop

}

void Genome::mutate_toggle_enable(int times) {

int genenum;

int count;

std::vector<Gene*>::iterator thegene;  //Gene to toggle

std::vector<Gene*>::iterator checkgene;  //Gene to check

int genecount;

for (count=1;count<=times;count++) {

//Choose a random genenum

genenum=randint(0,genes.size()-1);

//find the gene

thegene=genes.begin();

for(genecount=0;genecount<genenum;genecount++)

++thegene;

//Toggle the enable on this gene

if (((*thegene)->enable)==true) {

//We need to make sure that another gene connects out of the in-node

//Because if not a section of network will break off and become isolated

checkgene=genes.begin();

while((checkgene!=genes.end())&&

(((((*checkgene)->lnk)->in_node)!=(((*thegene)->lnk)->in_node))||

(((*checkgene)->enable)==false)||

((*checkgene)->innovation_num==(*thegene)->innovation_num)))

++checkgene;

//Disable the gene if it's safe to do so

if (checkgene!=genes.end())

(*thegene)->enable=false;

}

else (*thegene)->enable=true;

}

}

void Genome::mutate_gene_reenable() {

std::vector<Gene*>::iterator thegene;  //Gene to enable

thegene=genes.begin();

//Search for a disabled gene

while((thegene!=genes.end())&&((*thegene)->enable==true))

++thegene;

//Reenable it

if (thegene!=genes.end())

if (((*thegene)->enable)==false) (*thegene)->enable=true;

}

bool Genome::mutate_add_node(std::vector<Innovation*> &innovs,int &curnode_id,double &curinnov) {

std::vector<Gene*>::iterator thegene;  //random gene containing the original link

int genenum;  //The random gene number

NNode *in_node; //Here are the nodes connected by the gene

NNode *out_node; 

Link *thelink;  //The link inside the random gene

//double randmult;  //using a gaussian to find the random gene

std::vector<Innovation*>::iterator theinnov; //For finding a historical match

bool done=false;

Gene *newgene1;  //The new Genes

Gene *newgene2;

NNode *newnode;   //The new NNode

Trait *traitptr; //The original link's trait

//double splitweight;  //If used, Set to sqrt(oldweight of oldlink)

double oldweight;  //The weight of the original link

int trycount;  //Take a few tries to find an open node

bool found;

//First, find a random gene already in the genome  

trycount=0;

found=false;

//Split next link with a bias towards older links

//NOTE: 7/2/01 - for robots, went back to random split

//        because of large # of inputs

if (randfloat()>1.0) {

thegene=genes.begin();

while (((thegene!=genes.end())

&&(!((*thegene)->enable)))||

((thegene!=genes.end())

&&(((*thegene)->lnk->in_node)->gen_node_label==BIAS)))

++thegene;

//Now randomize which node is chosen at this point

//We bias the search towards older genes because 

//this encourages splitting to distribute evenly

while (((thegene!=genes.end())&&

(randfloat()<0.3))||

((thegene!=genes.end())

&&(((*thegene)->lnk->in_node)->gen_node_label==BIAS)))

{

++thegene;

}

if ((!(thegene==genes.end()))&&

((*thegene)->enable))

{

found=true;

}

}

//In this else:

//Alternative random gaussian choice of genes NOT USED in this

//version of NEAT

//NOTE: 7/2/01 now we use this after all

else {

while ((trycount<20)&&(!found)) {

//Choose a random genenum

//randmult=gaussrand()/4;

//if (randmult>1.0) randmult=1.0;

//This tends to select older genes for splitting

//genenum=(int) floor((randmult*(genes.size()-1.0))+0.5);

//This old totally random selection is bad- splitting

//inside something recently splitted adds little power

//to the system (should use a gaussian if doing it this way)

genenum=randint(0,genes.size()-1);

//find the gene

thegene=genes.begin();

for(int genecount=0;genecount<genenum;genecount++)

++thegene;

//If either the gene is disabled, or it has a bias input, try again

if (!(((*thegene)->enable==false)||

(((((*thegene)->lnk)->in_node)->gen_node_label)==BIAS)))

found=true;

++trycount;

}

}

//If we couldn't find anything so say goodbye

if (!found) 

return false;

//Disabled the gene

(*thegene)->enable=false;

//Extract the link

thelink=(*thegene)->lnk;

oldweight=(*thegene)->lnk->weight;

//Extract the nodes

in_node=thelink->in_node;

out_node=thelink->out_node;

//Check to see if this innovation has already been done   

//in another genome

//Innovations are used to make sure the same innovation in

//two separate genomes in the same generation receives

//the same innovation number.

theinnov=innovs.begin();

while(!done) {

if (theinnov==innovs.end()) {

//The innovation is totally novel

//Get the old link's trait

traitptr=thelink->linktrait;

//Create the new NNode

//By convention, it will point to the first trait

newnode=new NNode(NEURON,curnode_id++,HIDDEN);

newnode->nodetrait=(*(traits.begin()));

//Create the new Genes

if (thelink->is_recurrent) {

newgene1=new Gene(traitptr,1.0,in_node,newnode,true,curinnov,0);

newgene2=new Gene(traitptr,oldweight*0.3,newnode,out_node,false,curinnov+1,0);

curinnov+=2.0;

}

else {

newgene1=new Gene(traitptr,1.0,in_node,newnode,false,curinnov,0);

newgene2=new Gene(traitptr,oldweight*0.3,newnode,out_node,false,curinnov+1,0);

curinnov+=2.0;

}

//Add the innovations (remember what was done)

innovs.push_back(new Innovation(in_node->node_id,out_node->node_id,curinnov-2.0,curinnov-1.0,newnode->node_id,(*thegene)->innovation_num));      

done=true;

}

// We check to see if an innovation already occured that was:

//   -A new node

//   -Stuck between the same nodes as were chosen for this mutation

//   -Splitting the same gene as chosen for this mutation 

//   If so, we know this mutation is not a novel innovation

//   in this generation

//   so we make it match the original, identical mutation which occured

//   elsewhere in the population by coincidence 

else if (((*theinnov)->innovation_type==NEWNODE)&&

((*theinnov)->node_in_id==(in_node->node_id))&&

((*theinnov)->node_out_id==(out_node->node_id))&&

((*theinnov)->old_innov_num==(*thegene)->innovation_num)) 

{

//Here, the innovation has been done before

//Get the old link's trait

traitptr=thelink->linktrait;

//Create the new NNode

newnode=new NNode(NEURON,(*theinnov)->newnode_id,HIDDEN);      

//By convention, it will point to the first trait

//Note: In future may want to change this

newnode->nodetrait=(*(traits.begin()));

//Create the new Genes

if (thelink->is_recurrent) {

newgene1=new Gene(traitptr,1.0,in_node,newnode,true,(*theinnov)->innovation_num1,0);

newgene2=new Gene(traitptr,oldweight*0.3,newnode,out_node,false,(*theinnov)->innovation_num2,0);

}

else {

newgene1=new Gene(traitptr,1.0,in_node,newnode,false,(*theinnov)->innovation_num1,0);

newgene2=new Gene(traitptr,oldweight*0.3,newnode,out_node,false,(*theinnov)->innovation_num2,0);

}

done=true;

}

else ++theinnov;

}

//Now add the new NNode and new Genes to the Genome

//genes.push_back(newgene1);   //Old way to add genes- may result in genes becoming out of order

//genes.push_back(newgene2);

add_gene(genes,newgene1);  //Add genes in correct order

add_gene(genes,newgene2);

node_insert(nodes,newnode);

return true;

bool Genome::mutate_add_link(std::vector<Innovation*> &innovs,double &curinnov,int tries) {

int nodenum1,nodenum2;  //Random node numbers

std::vector<NNode*>::iterator thenode1,thenode2;  //Random node iterators

int nodecount;  //Counter for finding nodes

int trycount; //Iterates over attempts to find an unconnected pair of nodes

NNode *nodep1; //Pointers to the nodes

NNode *nodep2; //Pointers to the nodes

std::vector<Gene*>::iterator thegene; //Searches for existing link

bool found=false;  //Tells whether an open pair was found

std::vector<Innovation*>::iterator theinnov; //For finding a historical match

int recurflag; //Indicates whether proposed link is recurrent

Gene *newgene;  //The new Gene

int traitnum;  //Random trait finder

std::vector<Trait*>::iterator thetrait;

double newweight;  //The new weight for the new link

bool done;

bool do_recur;

bool loop_recur;

int first_nonsensor;

//These are used to avoid getting stuck in an infinite loop checking

//for recursion

//Note that we check for recursion to control the frequency of

//adding recurrent links rather than to prevent any paricular

//kind of error

int thresh=(nodes.size())*(nodes.size());

int count=0;

//Make attempts to find an unconnected pair

trycount=0;

//Decide whether to make this recurrent

if (randfloat()<NEAT::recur_only_prob) 

do_recur=true;

else do_recur=false;

//Find the first non-sensor so that the to-node won't look at sensors as

//possible destinations

first_nonsensor=0;

thenode1=nodes.begin();

while(((*thenode1)->get_type())==SENSOR) {

first_nonsensor++;

++thenode1;

}

//Here is the recurrent finder loop- it is done separately

if (do_recur) {

while(trycount<tries) {

//Some of the time try to make a recur loop

if (randfloat()>0.5) {

loop_recur=true;

}

else loop_recur=false;

if (loop_recur) {

nodenum1=randint(first_nonsensor,nodes.size()-1);

nodenum2=nodenum1;

}

else {

//Choose random nodenums

nodenum1=randint(0,nodes.size()-1);

nodenum2=randint(first_nonsensor,nodes.size()-1);

}

//Find the first node

thenode1=nodes.begin();

for(nodecount=0;nodecount<nodenum1;nodecount++)

++thenode1;

//Find the second node

thenode2=nodes.begin();

for(nodecount=0;nodecount<nodenum2;nodecount++)

++thenode2;

nodep1=(*thenode1);

nodep2=(*thenode2);

//See if a recur link already exists  ALSO STOP AT END OF GENES!!!!

thegene=genes.begin();

while ((thegene!=genes.end()) && 

((nodep2->type)!=SENSOR) &&   //Don't allow SENSORS to get input

(!((((*thegene)->lnk)->in_node==nodep1)&&

(((*thegene)->lnk)->out_node==nodep2)&&

((*thegene)->lnk)->is_recurrent))) {

++thegene;

}

if (thegene!=genes.end())

trycount++;

else {

count=0;

recurflag=phenotype->is_recur(nodep1->analogue,nodep2->analogue,count,thresh);

//ADDED: CONSIDER connections out of outputs recurrent

if (((nodep1->type)==OUTPUT)||

((nodep2->type)==OUTPUT))

recurflag=true;

//Exit if the network is faulty (contains an infinite loop)

//NOTE: A loop doesn't really matter

//if (count>thresh) {

//  cout<<"LOOP DETECTED DURING A RECURRENCY CHECK"<<std::endl;

//  return false;

//}

//Make sure it finds the right kind of link (recur)

if (!(recurflag))

trycount++;

else {

trycount=tries;

found=true;

}

}

}

}

else {

//Loop to find a nonrecurrent link

while(trycount<tries) {

//cout<<"TRY "<<trycount<<std::endl;

//Choose random nodenums

nodenum1=randint(0,nodes.size()-1);

nodenum2=randint(first_nonsensor,nodes.size()-1);

//Find the first node

thenode1=nodes.begin();

for(nodecount=0;nodecount<nodenum1;nodecount++)

++thenode1;

//cout<<"RETRIEVED NODE# "<<(*thenode1)->node_id<<std::endl;

//Find the second node

thenode2=nodes.begin();

for(nodecount=0;nodecount<nodenum2;nodecount++)

++thenode2;

nodep1=(*thenode1);

nodep2=(*thenode2);

//See if a link already exists  ALSO STOP AT END OF GENES!!!!

thegene=genes.begin();

while ((thegene!=genes.end()) && 

((nodep2->type)!=SENSOR) &&   //Don't allow SENSORS to get input

(!((((*thegene)->lnk)->in_node==nodep1)&&

(((*thegene)->lnk)->out_node==nodep2)&&

(!(((*thegene)->lnk)->is_recurrent))))) {

++thegene;

}

if (thegene!=genes.end())

trycount++;

else {

count=0;

recurflag=phenotype->is_recur(nodep1->analogue,nodep2->analogue,count,thresh);

//ADDED: CONSIDER connections out of outputs recurrent

if (((nodep1->type)==OUTPUT)||

((nodep2->type)==OUTPUT))

recurflag=true;

//Exit if the network is faulty (contains an infinite loop)

if (count>thresh) {

//cout<<"LOOP DETECTED DURING A RECURRENCY CHECK"<<std::endl;

//return false;

}

//Make sure it finds the right kind of link (recur or not)

if (recurflag)

trycount++;

else {

trycount=tries;

found=true;

}

}

} //End of normal link finding loop

}

//Continue only if an open link was found

if (found) {

//Check to see if this innovation already occured in the population

theinnov=innovs.begin();

//If it was supposed to be recurrent, make sure it gets labeled that way

if (do_recur) recurflag=1;

done=false;

while(!done) {

//The innovation is totally novel

if (theinnov==innovs.end()) {

//If the phenotype does not exist, exit on false,print error

//Note: This should never happen- if it does there is a bug

if (phenotype==0) {

//cout<<"ERROR: Attempt to add link to genome with no phenotype"<<std::endl;

return false;

}

//Useful for debugging

//cout<<"nodep1 id: "<<nodep1->node_id<<std::endl;

//cout<<"nodep1: "<<nodep1<<std::endl;

//cout<<"nodep1 analogue: "<<nodep1->analogue<<std::endl;

//cout<<"nodep2 id: "<<nodep2->node_id<<std::endl;

//cout<<"nodep2: "<<nodep2<<std::endl;

//cout<<"nodep2 analogue: "<<nodep2->analogue<<std::endl;

//cout<<"recurflag: "<<recurflag<<std::endl;

//NOTE: Something like this could be used for time delays,

//      which are not yet supported.  However, this does not

//      have an application with recurrency.

//If not recurrent, randomize recurrency

//if (!recurflag) 

//  if (randfloat()<recur_prob) recurflag=1;

//Choose a random trait

traitnum=randint(0,(traits.size())-1);

thetrait=traits.begin();

//Choose the new weight

//newweight=(gaussrand())/1.5;  //Could use a gaussian

newweight=randposneg()*randfloat()*1.0; //used to be 10.0

//Create the new gene

newgene=new Gene(((thetrait[traitnum])),newweight,nodep1,nodep2,recurflag,curinnov,newweight);

//Add the innovation

innovs.push_back(new Innovation(nodep1->node_id,nodep2->node_id,curinnov,newweight,traitnum));

curinnov=curinnov+1.0;

done=true;

}

//OTHERWISE, match the innovation in the innovs list

else if (((*theinnov)->innovation_type==NEWLINK)&&

((*theinnov)->node_in_id==(nodep1->node_id))&&

((*theinnov)->node_out_id==(nodep2->node_id))&&

((*theinnov)->recur_flag==(bool)recurflag)) {

thetrait=traits.begin();

//Create new gene

newgene=new Gene(((thetrait[(*theinnov)->new_traitnum])),(*theinnov)->new_weight,nodep1,nodep2,recurflag,(*theinnov)->innovation_num1,0);

done=true;

}

else {

//Keep looking for a matching innovation from this generation

++theinnov;

}

}

//Now add the new Genes to the Genome

//genes.push_back(newgene);  //Old way - could result in out-of-order innovation numbers in rtNEAT

add_gene(genes,newgene);  //Adds the gene in correct order

return true;

}

else {

return false;

}

}

void Genome::mutate_add_sensor(std::vector<Innovation*> &innovs,double &curinnov) {

std::vector<NNode*> sensors;

std::vector<NNode*> outputs;

NNode *node;

NNode *sensor;

NNode *output;

Gene *gene;

double newweight = 0.0;

Gene* newgene;

int i,j; //counters

bool found;

bool done;

int outputConnections;

std::vector<Trait*>::iterator thetrait;

int traitnum;

std::vector<Innovation*>::iterator theinnov; //For finding a historical match

//Find all the sensors and outputs

for (i = 0; i < nodes.size(); i++) {

node=nodes[i];

if ((node->type) == SENSOR)

sensors.push_back(node);

else if (node->gen_node_label == OUTPUT)

outputs.push_back(node);

}

// eliminate from contention any sensors that are already connected

    std::vector<NNode*>::iterator iter;

for (iter = sensors.begin(); iter != sensors.end(); ++iter) {

sensor = *iter;

outputConnections=0;

for (int j = 0; j < genes.size(); j++) {

gene=genes[j];

if ((gene->lnk)->out_node->gen_node_label == OUTPUT)

outputConnections++;

}

if (outputConnections == outputs.size()) {

iter = sensors.erase(iter); //Does this work? remove by number from a vector?

}

}

//If all sensors are connected, quit

if (sensors.size() == 0)

return;

//Pick randomly from remaining sensors

sensor=sensors[randint(0,sensors.size()-1)];

//Add new links to chosen sensor, avoiding redundancy

for (int i = 0; i < outputs.size(); i++) {

output=outputs[i];

found=false;

for (j = 0; j < genes.size(); j++) {

gene=genes[j];

if ((gene->lnk->in_node==sensor)&&

(gene->lnk->out_node==output))

found=true;

}

//Record the innovation

if (!found) {

theinnov=innovs.begin();

done=false;

while (!done) {

//The innovation is novel

if (theinnov==innovs.end()) {

//Choose a random trait

traitnum=randint(0,(traits.size())-1);

thetrait=traits.begin();

//Choose the new weight

//newweight=(gaussrand())/1.5;  //Could use a gaussian

newweight=randposneg()*randfloat()*3.0; //used to be 10.0

//Create the new gene

newgene=new Gene(((thetrait[traitnum])),

newweight,sensor,output,false,

curinnov,newweight);

//Add the innovation

innovs.push_back(new Innovation(sensor->node_id,

output->node_id,curinnov,newweight,traitnum));

curinnov=curinnov+1.0;

done=true;

} //end novel innovation case

//OTHERWISE, match the innovation in the innovs list

else if (((*theinnov)->innovation_type==NEWLINK)&&

((*theinnov)->node_in_id==(sensor->node_id))&&

((*theinnov)->node_out_id==(output->node_id))&&

((*theinnov)->recur_flag==false)) {

thetrait=traits.begin();

//Create new gene

newgene=

new Gene(((thetrait[(*theinnov)->new_traitnum])),

(*theinnov)->new_weight,sensor,output,

false,(*theinnov)->innovation_num1,0);

done=true;

} //end prior innovation case

//Keep looking for matching innovation

else ++theinnov;

}  //end while

//genes.push_back(newgene);

add_gene(genes,newgene);  //adds the gene in correct order

} //end case where the gene didn't previously exist

}

}

//Adds a new gene that has been created through a mutation in the

//*correct order* into the list of genes in the genome

void Genome::add_gene(std::vector<Gene*> &glist,Gene *g) {

  std::vector<Gene*>::iterator curgene;

  double p1innov;

  double inum=g->innovation_num;

  //std::cout<<"**ADDING GENE: "<<g->innovation_num<<std::endl;

  curgene=glist.begin();

  while ((curgene!=glist.end())&&

(((*curgene)->innovation_num)<inum)) {

    //p1innov=(*curgene)->innovation_num;

    //printf("Innov num: %f",p1innov);  

    ++curgene;

    //Con::printf("looking gene %f", (*curgene)->innovation_num);

  }

  glist.insert(curgene,g);

}

void Genome::node_insert(std::vector<NNode*> &nlist,NNode *n) {

std::vector<NNode*>::iterator curnode;

int id=n->node_id;

curnode=nlist.begin();

while ((curnode!=nlist.end())&&

(((*curnode)->node_id)<id)) 

++curnode;

nlist.insert(curnode,n);

}

Genome *Genome::mate_multipoint(Genome *g,int genomeid,double fitness1,double fitness2, bool interspec_flag) {

//The baby Genome will contain these new Traits, NNodes, and Genes

std::vector<Trait*> newtraits; 

std::vector<NNode*> newnodes;   

std::vector<Gene*> newgenes;    

Genome *new_genome;

std::vector<Gene*>::iterator curgene2;  //Checks for link duplication

//iterators for moving through the two parents' traits

std::vector<Trait*>::iterator p1trait;

std::vector<Trait*>::iterator p2trait;

Trait *newtrait;

//iterators for moving through the two parents' genes

std::vector<Gene*>::iterator p1gene;

std::vector<Gene*>::iterator p2gene;

double p1innov;  //Innovation numbers for genes inside parents' Genomes

double p2innov;

Gene *chosengene;  //Gene chosen for baby to inherit

int traitnum;  //Number of trait new gene points to

NNode *inode;  //NNodes connected to the chosen Gene

NNode *onode;

NNode *new_inode;

NNode *new_onode;

std::vector<NNode*>::iterator curnode;  //For checking if NNodes exist already 

int nodetraitnum;  //Trait number for a NNode

bool disable;  //Set to true if we want to disabled a chosen gene

disable=false;

Gene *newgene;

bool p1better; //Tells if the first genome (this one) has better fitness or not

bool skip;

//First, average the Traits from the 2 parents to form the baby's Traits

//It is assumed that trait lists are the same length

//In the future, may decide on a different method for trait mating

p2trait=(g->traits).begin();

for(p1trait=traits.begin();p1trait!=traits.end();++p1trait) {

newtrait=new Trait(*p1trait,*p2trait);  //Construct by averaging

newtraits.push_back(newtrait);

++p2trait;

}

//Figure out which genome is better

//The worse genome should not be allowed to add extra structural baggage

//If they are the same, use the smaller one's disjoint and excess genes only

if (fitness1>fitness2) 

p1better=true;

else if (fitness1==fitness2) {

if (genes.size()<(g->genes.size()))

p1better=true;

else p1better=false;

}

else 

p1better=false;

//NEW 3/17/03 Make sure all sensors and outputs are included

for(curnode=(g->nodes).begin();curnode!=(g->nodes).end();++curnode) {

if ((((*curnode)->gen_node_label)==INPUT)||

(((*curnode)->gen_node_label)==BIAS)||

(((*curnode)->gen_node_label)==OUTPUT)) {

if (!((*curnode)->nodetrait)) nodetraitnum=0;

else

nodetraitnum=(((*curnode)->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;

//Create a new node off the sensor or output

new_onode=new NNode((*curnode),newtraits[nodetraitnum]);

//Add the new node

node_insert(newnodes,new_onode);

}

}

//Now move through the Genes of each parent until both genomes end

p1gene=genes.begin();

p2gene=(g->genes).begin();

while(!((p1gene==genes.end())&&

(p2gene==(g->genes).end()))) {

skip=false;  //Default to not skipping a chosen gene

if (p1gene==genes.end()) {

chosengene=*p2gene;

++p2gene;

if (p1better) skip=true;  //Skip excess from the worse genome

}

else if (p2gene==(g->genes).end()) {

chosengene=*p1gene;

++p1gene;

if (!p1better) skip=true; //Skip excess from the worse genome

}

else {

//Extract current innovation numbers

p1innov=(*p1gene)->innovation_num;

p2innov=(*p2gene)->innovation_num;

if (p1innov==p2innov) {

if (randfloat()<0.5) {

chosengene=*p1gene;

}

else {

chosengene=*p2gene;

}

//If one is disabled, the corresponding gene in the offspring

//will likely be disabled

if ((((*p1gene)->enable)==false)||

(((*p2gene)->enable)==false)) 

if (randfloat()<0.75) disable=true;

++p1gene;

++p2gene;

}

else if (p1innov<p2innov) {

chosengene=*p1gene;

++p1gene;

if (!p1better) skip=true;

}

else if (p2innov<p1innov) {

chosengene=*p2gene;

++p2gene;

if (p1better) skip=true;

}

}

//Uncomment this line to let growth go faster (from both parents excesses)

skip=false;

//For interspecies mating, allow all genes through:

if (interspec_flag)

skip=false;

//Check to see if the chosengene conflicts with an already chosen gene

//i.e. do they represent the same link    

curgene2=newgenes.begin();

while ((curgene2!=newgenes.end())&&

(!((((((*curgene2)->lnk)->in_node)->node_id)==((((chosengene)->lnk)->in_node)->node_id))&&

(((((*curgene2)->lnk)->out_node)->node_id)==((((chosengene)->lnk)->out_node)->node_id))&&((((*curgene2)->lnk)->is_recurrent)== (((chosengene)->lnk)->is_recurrent)) ))&&

(!((((((*curgene2)->lnk)->in_node)->node_id)==((((chosengene)->lnk)->out_node)->node_id))&&

(((((*curgene2)->lnk)->out_node)->node_id)==((((chosengene)->lnk)->in_node)->node_id))&&

(!((((*curgene2)->lnk)->is_recurrent)))&&

(!((((chosengene)->lnk)->is_recurrent))) )))

{

++curgene2;

}

if (curgene2!=newgenes.end()) skip=true;  //Links conflicts, abort adding

if (!skip) {

//Now add the chosengene to the baby

//First, get the trait pointer

if ((((chosengene->lnk)->linktrait))==0) traitnum=(*(traits.begin()))->trait_id - 1; 

else

traitnum=(((chosengene->lnk)->linktrait)->trait_id)-(*(traits.begin()))->trait_id;  //The subtracted number normalizes depending on whether traits start counting at 1 or 0

//Next check for the nodes, add them if not in the baby Genome already

inode=(chosengene->lnk)->in_node;

onode=(chosengene->lnk)->out_node;

//Check for inode in the newnodes list

if (inode->node_id<onode->node_id) {

//inode before onode

//Checking for inode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=inode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//(normalized trait number for new NNode)

//old buggy version:

// if (!(onode->nodetrait)) nodetraitnum=((*(traits.begin()))->trait_id);

if (!(inode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((inode->nodetrait)->trait_id)-((*(traits.begin()))->trait_id);       

new_inode=new NNode(inode,newtraits[nodetraitnum]);

node_insert(newnodes,new_inode);

}

else {

new_inode=(*curnode);

}

//Checking for onode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=onode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(onode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((onode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;       

new_onode=new NNode(onode,newtraits[nodetraitnum]);

node_insert(newnodes,new_onode);

}

else {

new_onode=(*curnode);

}

}

//If the onode has a higher id than the inode we want to add it first

else {

//Checking for onode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=onode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(onode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((onode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;       

new_onode=new NNode(onode,newtraits[nodetraitnum]);

//newnodes.push_back(new_onode);

node_insert(newnodes,new_onode);

}

else {

new_onode=(*curnode);

}

//Checking for inode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=inode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(inode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((inode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;    

new_inode=new NNode(inode,newtraits[nodetraitnum]);

node_insert(newnodes,new_inode);

}

else {

new_inode=(*curnode);

}

} //End NNode checking section- NNodes are now in new Genome

//Add the Gene

newgene=new Gene(chosengene,newtraits[traitnum],new_inode,new_onode);

if (disable) {

newgene->enable=false;

disable=false;

}

newgenes.push_back(newgene);

}

}

new_genome=new Genome(genomeid,newtraits,newnodes,newgenes);

//Return the baby Genome

return (new_genome);

}

Genome *Genome::mate_multipoint_avg(Genome *g,int genomeid,double fitness1,double fitness2,bool interspec_flag) {

//The baby Genome will contain these new Traits, NNodes, and Genes

std::vector<Trait*> newtraits;

std::vector<NNode*> newnodes;

std::vector<Gene*> newgenes;

//iterators for moving through the two parents' traits

std::vector<Trait*>::iterator p1trait;

std::vector<Trait*>::iterator p2trait;

Trait *newtrait;

std::vector<Gene*>::iterator curgene2; //Checking for link duplication

//iterators for moving through the two parents' genes

std::vector<Gene*>::iterator p1gene;

std::vector<Gene*>::iterator p2gene;

double p1innov;  //Innovation numbers for genes inside parents' Genomes

double p2innov;

Gene *chosengene;  //Gene chosen for baby to inherit

int traitnum;  //Number of trait new gene points to

NNode *inode;  //NNodes connected to the chosen Gene

NNode *onode;

NNode *new_inode;

NNode *new_onode;

std::vector<NNode*>::iterator curnode;  //For checking if NNodes exist already 

int nodetraitnum;  //Trait number for a NNode

//This Gene is used to hold the average of the two genes to be averaged

Gene *avgene;

Gene *newgene;

bool skip;

bool p1better;  //Designate the better genome

// BLX-alpha variables - for assigning weights within a good space 

// This is for BLX-style mating, which isn't used in this implementation,

//   but can easily be made from multipoint_avg 

//double blx_alpha;

//double w1,w2;

//double blx_min, blx_max;

//double blx_range;   //The space range

//double blx_explore;  //Exploration space on left or right

//double blx_pos;  //Decide where to put gnes distancewise

//blx_pos=randfloat();

//First, average the Traits from the 2 parents to form the baby's Traits

//It is assumed that trait lists are the same length

//In future, could be done differently

p2trait=(g->traits).begin();

for(p1trait=traits.begin();p1trait!=traits.end();++p1trait) {

newtrait=new Trait(*p1trait,*p2trait);  //Construct by averaging

newtraits.push_back(newtrait);

++p2trait;

}

//Set up the avgene

avgene=new Gene(0,0,0,0,0,0,0);

//NEW 3/17/03 Make sure all sensors and outputs are included

for(curnode=(g->nodes).begin();curnode!=(g->nodes).end();++curnode) {

if ((((*curnode)->gen_node_label)==INPUT)||

(((*curnode)->gen_node_label)==OUTPUT)||

(((*curnode)->gen_node_label)==BIAS)) {

if (!((*curnode)->nodetrait)) nodetraitnum=0;

else

nodetraitnum=(((*curnode)->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;

//Create a new node off the sensor or output

new_onode=new NNode((*curnode),newtraits[nodetraitnum]);

//Add the new node

node_insert(newnodes,new_onode);

}

}

//Figure out which genome is better

//The worse genome should not be allowed to add extra structural baggage

//If they are the same, use the smaller one's disjoint and excess genes only

if (fitness1>fitness2) 

p1better=true;

else if (fitness1==fitness2) {

if (genes.size()<(g->genes.size()))

p1better=true;

else p1better=false;

}

else 

p1better=false;

//Now move through the Genes of each parent until both genomes end

p1gene=genes.begin();

p2gene=(g->genes).begin();

while(!((p1gene==genes.end())&&

(p2gene==(g->genes).end()))) {

avgene->enable=true;  //Default to enabled

skip=false;

if (p1gene==genes.end()) {

chosengene=*p2gene;

++p2gene;

if (p1better) skip=true;

}

else if (p2gene==(g->genes).end()) {

chosengene=*p1gene;

++p1gene;

if (!p1better) skip=true;

}

else {

//Extract current innovation numbers

p1innov=(*p1gene)->innovation_num;

p2innov=(*p2gene)->innovation_num;

if (p1innov==p2innov) {

//Average them into the avgene

if (randfloat()>0.5) (avgene->lnk)->linktrait=((*p1gene)->lnk)->linktrait;

else (avgene->lnk)->linktrait=((*p2gene)->lnk)->linktrait;

//WEIGHTS AVERAGED HERE

(avgene->lnk)->weight=(((*p1gene)->lnk)->weight+((*p2gene)->lnk)->weight)/2.0;


////BLX-alpha method (Eschelman et al 1993)

////Not used in this implementation, but the commented code works

////with alpha=0.5, this will produce babies evenly in exploitation and exploration space

////and uniformly distributed throughout

//blx_alpha=-0.4;

//w1=(((*p1gene)->lnk)->weight);

//w2=(((*p2gene)->lnk)->weight);

//if (w1>w2) {

//blx_max=w1; blx_min=w2;

//}

//else {

//blx_max=w2; blx_min=w1;

//}

//blx_range=blx_max-blx_min;

//blx_explore=blx_alpha*blx_range;

////Now extend the range into the exploraton space

//blx_min-=blx_explore;

//blx_max+=blx_explore;

//blx_range=blx_max-blx_min;

////Set the weight in the new range

//(avgene->lnk)->weight=blx_min+blx_pos*blx_range;

//

if (randfloat()>0.5) (avgene->lnk)->in_node=((*p1gene)->lnk)->in_node;

else (avgene->lnk)->in_node=((*p2gene)->lnk)->in_node;

if (randfloat()>0.5) (avgene->lnk)->out_node=((*p1gene)->lnk)->out_node;

else (avgene->lnk)->out_node=((*p2gene)->lnk)->out_node;

if (randfloat()>0.5) (avgene->lnk)->is_recurrent=((*p1gene)->lnk)->is_recurrent;

else (avgene->lnk)->is_recurrent=((*p2gene)->lnk)->is_recurrent;

avgene->innovation_num=(*p1gene)->innovation_num;

avgene->mutation_num=((*p1gene)->mutation_num+(*p2gene)->mutation_num)/2.0;

if ((((*p1gene)->enable)==false)||

(((*p2gene)->enable)==false)) 

if (randfloat()<0.75) avgene->enable=false;

chosengene=avgene;

++p1gene;

++p2gene;

}

else if (p1innov<p2innov) {

chosengene=*p1gene;

++p1gene;

if (!p1better) skip=true;

}

else if (p2innov<p1innov) {

chosengene=*p2gene;

++p2gene;

if (p1better) skip=true;

}

}

//THIS LINE MUST BE DELETED TO SLOW GROWTH

skip=false;

//For interspecies mating, allow all genes through:

if (interspec_flag)

skip=false;

//Check to see if the chosengene conflicts with an already chosen gene

//i.e. do they represent the same link    

curgene2=newgenes.begin();

while ((curgene2!=newgenes.end()))

{

if (((((((*curgene2)->lnk)->in_node)->node_id)==((((chosengene)->lnk)->in_node)->node_id))&&

(((((*curgene2)->lnk)->out_node)->node_id)==((((chosengene)->lnk)->out_node)->node_id))&&

((((*curgene2)->lnk)->is_recurrent)== (((chosengene)->lnk)->is_recurrent)))||

((((((*curgene2)->lnk)->out_node)->node_id)==((((chosengene)->lnk)->in_node)->node_id))&&

(((((*curgene2)->lnk)->in_node)->node_id)==((((chosengene)->lnk)->out_node)->node_id))&&

(!((((*curgene2)->lnk)->is_recurrent)))&&

(!((((chosengene)->lnk)->is_recurrent)))     ))

skip=true;

}

++curgene2;

}

if (!skip) {

//Now add the chosengene to the baby

//First, get the trait pointer

if ((((chosengene->lnk)->linktrait))==0) traitnum=(*(traits.begin()))->trait_id - 1;

else

traitnum=(((chosengene->lnk)->linktrait)->trait_id)-(*(traits.begin()))->trait_id;  //The subtracted number normalizes depending on whether traits start counting at 1 or 0

//Next check for the nodes, add them if not in the baby Genome already

inode=(chosengene->lnk)->in_node;

onode=(chosengene->lnk)->out_node;

//Check for inode in the newnodes list

if (inode->node_id<onode->node_id) {

//Checking for inode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=inode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(inode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((inode->nodetrait)->trait_id)-((*(traits.begin()))->trait_id);       

new_inode=new NNode(inode,newtraits[nodetraitnum]);

node_insert(newnodes,new_inode);

}

else {

new_inode=(*curnode);

}

//Checking for onode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=onode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(onode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((onode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;

new_onode=new NNode(onode,newtraits[nodetraitnum]);

node_insert(newnodes,new_onode);

}

else {

new_onode=(*curnode);

}

}

//If the onode has a higher id than the inode we want to add it first

else {

//Checking for onode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=onode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(onode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((onode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;       

new_onode=new NNode(onode,newtraits[nodetraitnum]);

node_insert(newnodes,new_onode);

}

else {

new_onode=(*curnode);

}

//Checking for inode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=inode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(inode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((inode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;       

new_inode=new NNode(inode,newtraits[nodetraitnum]);

node_insert(newnodes,new_inode);

}

else {

new_inode=(*curnode);

}

} //End NNode checking section- NNodes are now in new Genome

//Add the Gene

newgene=new Gene(chosengene,newtraits[traitnum],new_inode,new_onode);

newgenes.push_back(newgene);

}  //End if which checked for link duplicationb

}

delete avgene;  //Clean up used object

//Return the baby Genome

return (new Genome(genomeid,newtraits,newnodes,newgenes));

}

Genome *Genome::mate_singlepoint(Genome *g,int genomeid) {

//The baby Genome will contain these new Traits, NNodes, and Genes

std::vector<Trait*> newtraits; 

std::vector<NNode*> newnodes;   

std::vector<Gene*> newgenes;    

//iterators for moving through the two parents' traits

std::vector<Trait*>::iterator p1trait;

std::vector<Trait*>::iterator p2trait;

Trait *newtrait;

std::vector<Gene*>::iterator curgene2;  //Check for link duplication

//iterators for moving through the two parents' genes

std::vector<Gene*>::iterator p1gene;

std::vector<Gene*>::iterator p2gene;

std::vector<Gene*>::iterator stopper;  //To tell when finished

std::vector<Gene*>::iterator p2stop;

std::vector<Gene*>::iterator p1stop;

double p1innov;  //Innovation numbers for genes inside parents' Genomes

double p2innov;

Gene *chosengene;  //Gene chosen for baby to inherit

int traitnum;  //Number of trait new gene points to

NNode *inode;  //NNodes connected to the chosen Gene

NNode *onode;

NNode *new_inode;

NNode *new_onode;

std::vector<NNode*>::iterator curnode;  //For checking if NNodes exist already 

int nodetraitnum;  //Trait number for a NNode

//This Gene is used to hold the average of the two genes to be averaged

Gene *avgene;

int crosspoint; //The point in the Genome to cross at

int genecounter; //Counts up to the crosspoint

bool skip; //Used for skipping unwanted genes

//First, average the Traits from the 2 parents to form the baby's Traits

//It is assumed that trait lists are the same length

p2trait=(g->traits).begin();

for(p1trait=traits.begin();p1trait!=traits.end();++p1trait) {

newtrait=new Trait(*p1trait,*p2trait);  //Construct by averaging

newtraits.push_back(newtrait);

++p2trait;

}

//Set up the avgene

avgene=new Gene(0,0,0,0,0,0,0);

//Decide where to cross  (p1gene will always be in smaller Genome)

if (genes.size()<(g->genes).size()) {

crosspoint=randint(0,(genes.size())-1);

p1gene=genes.begin();

p2gene=(g->genes).begin();

stopper=(g->genes).end();

p1stop=genes.end();

p2stop=(g->genes).end();

}

else {

crosspoint=randint(0,((g->genes).size())-1);

p2gene=genes.begin();

p1gene=(g->genes).begin();

stopper=genes.end();

p1stop=(g->genes.end());

p2stop=genes.end();

}

genecounter=0;  //Ready to count to crosspoint

skip=false;  //Default to not skip a Gene

//Note that we skip when we are on the wrong Genome before

//crossing

//Now move through the Genes of each parent until both genomes end

while(p2gene!=stopper) {

avgene->enable=true;  //Default to true

if (p1gene==p1stop) {

chosengene=*p2gene;

++p2gene;

}

else if (p2gene==p2stop) {

chosengene=*p1gene;

++p1gene;

}

else {

//Extract current innovation numbers

//if (p1gene==g->genes.end()) cout<<"WARNING p1"<<std::endl;

//if (p2gene==g->genes.end()) cout<<"WARNING p2"<<std::endl;

p1innov=(*p1gene)->innovation_num;

p2innov=(*p2gene)->innovation_num;

if (p1innov==p2innov) {

//Pick the chosengene depending on whether we've crossed yet

if (genecounter<crosspoint) {

chosengene=*p1gene;

}

else if (genecounter>crosspoint) {

chosengene=*p2gene;

}

//We are at the crosspoint here

else {

//Average them into the avgene

if (randfloat()>0.5) (avgene->lnk)->linktrait=((*p1gene)->lnk)->linktrait;

else (avgene->lnk)->linktrait=((*p2gene)->lnk)->linktrait;

//WEIGHTS AVERAGED HERE

(avgene->lnk)->weight=(((*p1gene)->lnk)->weight+((*p2gene)->lnk)->weight)/2.0;

if (randfloat()>0.5) (avgene->lnk)->in_node=((*p1gene)->lnk)->in_node;

else (avgene->lnk)->in_node=((*p2gene)->lnk)->in_node;

if (randfloat()>0.5) (avgene->lnk)->out_node=((*p1gene)->lnk)->out_node;

else (avgene->lnk)->out_node=((*p2gene)->lnk)->out_node;

if (randfloat()>0.5) (avgene->lnk)->is_recurrent=((*p1gene)->lnk)->is_recurrent;

else (avgene->lnk)->is_recurrent=((*p2gene)->lnk)->is_recurrent;

avgene->innovation_num=(*p1gene)->innovation_num;

avgene->mutation_num=((*p1gene)->mutation_num+(*p2gene)->mutation_num)/2.0;

if ((((*p1gene)->enable)==false)||

(((*p2gene)->enable)==false)) 

avgene->enable=false;

chosengene=avgene;

}

++p1gene;

++p2gene;

++genecounter;

}

else if (p1innov<p2innov) {

if (genecounter<crosspoint) {

chosengene=*p1gene;

++p1gene;

++genecounter;

}

else {

chosengene=*p2gene;

++p2gene;

}

}

else if (p2innov<p1innov) {

++p2gene;

skip=true;  //Special case: we need to skip to the next iteration

//becase this Gene is before the crosspoint on the wrong Genome

}

}

//Check to see if the chosengene conflicts with an already chosen gene

//i.e. do they represent the same link    

curgene2=newgenes.begin();

while ((curgene2!=newgenes.end())&&

(!((((((*curgene2)->lnk)->in_node)->node_id)==((((chosengene)->lnk)->in_node)->node_id))&&

(((((*curgene2)->lnk)->out_node)->node_id)==((((chosengene)->lnk)->out_node)->node_id))&&((((*curgene2)->lnk)->is_recurrent)== (((chosengene)->lnk)->is_recurrent)) ))&&

(!((((((*curgene2)->lnk)->in_node)->node_id)==((((chosengene)->lnk)->out_node)->node_id))&&

(((((*curgene2)->lnk)->out_node)->node_id)==((((chosengene)->lnk)->in_node)->node_id))&&

(!((((*curgene2)->lnk)->is_recurrent)))&&

(!((((chosengene)->lnk)->is_recurrent))) )))

{

++curgene2;

}

if (curgene2!=newgenes.end()) skip=true;  //Link is a duplicate

if (!skip) {

//Now add the chosengene to the baby

//First, get the trait pointer

if ((((chosengene->lnk)->linktrait))==0) traitnum=(*(traits.begin()))->trait_id;

else

traitnum=(((chosengene->lnk)->linktrait)->trait_id)-(*(traits.begin()))->trait_id;  //The subtracted number normalizes depending on whether traits start counting at 1 or 0

//Next check for the nodes, add them if not in the baby Genome already

inode=(chosengene->lnk)->in_node;

onode=(chosengene->lnk)->out_node;

//Check for inode in the newnodes list

if (inode->node_id<onode->node_id) {

//cout<<"inode before onode"<<std::endl;

//Checking for inode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=inode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(inode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((inode->nodetrait)->trait_id)-((*(traits.begin()))->trait_id);       

new_inode=new NNode(inode,newtraits[nodetraitnum]);

node_insert(newnodes,new_inode);

}

else {

new_inode=(*curnode);

}

//Checking for onode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=onode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(onode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((onode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;     

new_onode=new NNode(onode,newtraits[nodetraitnum]);

node_insert(newnodes,new_onode);

}

else {

new_onode=(*curnode);

}

}

//If the onode has a higher id than the inode we want to add it first

else {

//Checking for onode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=onode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(onode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((onode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;       

new_onode=new NNode(onode,newtraits[nodetraitnum]);

node_insert(newnodes,new_onode);

}

else {

new_onode=(*curnode);

}

//Checking for inode's existence

curnode=newnodes.begin();

while((curnode!=newnodes.end())&&

((*curnode)->node_id!=inode->node_id)) 

++curnode;

if (curnode==newnodes.end()) {

//Here we know the node doesn't exist so we have to add it

//normalized trait number for new NNode

if (!(inode->nodetrait)) nodetraitnum=0;

else

nodetraitnum=((inode->nodetrait)->trait_id)-(*(traits.begin()))->trait_id;       

new_inode=new NNode(inode,newtraits[nodetraitnum]);

//newnodes.push_back(new_inode);

node_insert(newnodes,new_inode);

}

else {

new_inode=(*curnode);

}

} //End NNode checking section- NNodes are now in new Genome

//Add the Gene

newgenes.push_back(new Gene(chosengene,newtraits[traitnum],new_inode,new_onode));

}  //End of if (!skip)

skip=false;

}

delete avgene;  //Clean up used object

//Return the baby Genome

return (new Genome(genomeid,newtraits,newnodes,newgenes));

}

double Genome::compatibility(Genome *g) {

//iterators for moving through the two potential parents' Genes

std::vector<Gene*>::iterator p1gene;

std::vector<Gene*>::iterator p2gene;  

//Innovation numbers

double p1innov;

double p2innov;

//Intermediate value

double mut_diff;

//Set up the counters

double num_disjoint=0.0;

double num_excess=0.0;

double mut_diff_total=0.0;

double num_matching=0.0;  //Used to normalize mutation_num differences

double max_genome_size; //Size of larger Genome

//Get the length of the longest Genome for percentage computations

if (genes.size()<(g->genes).size()) 

max_genome_size=(g->genes).size();

else max_genome_size=genes.size();

//Now move through the Genes of each potential parent 

//until both Genomes end

p1gene=genes.begin();

p2gene=(g->genes).begin();

while(!((p1gene==genes.end())&&

(p2gene==(g->genes).end()))) {

if (p1gene==genes.end()) {

++p2gene;

num_excess+=1.0;

}

else if (p2gene==(g->genes).end()) {

++p1gene;

num_excess+=1.0;

}

else {

//Extract current innovation numbers

p1innov=(*p1gene)->innovation_num;

p2innov=(*p2gene)->innovation_num;

if (p1innov==p2innov) {

num_matching+=1.0;

mut_diff=((*p1gene)->mutation_num)-((*p2gene)->mutation_num);

if (mut_diff<0.0) mut_diff=0.0-mut_diff;

//mut_diff+=trait_compare((*p1gene)->lnk->linktrait,(*p2gene)->lnk->linktrait); //CONSIDER TRAIT DIFFERENCES

mut_diff_total+=mut_diff;

++p1gene;

++p2gene;

}

else if (p1innov<p2innov) {

++p1gene;

num_disjoint+=1.0;

}

else if (p2innov<p1innov) {

++p2gene;

num_disjoint+=1.0;

}

}

} //End while

//Return the compatibility number using compatibility formula

//Note that mut_diff_total/num_matching gives the AVERAGE

//difference between mutation_nums for any two matching Genes

//in the Genome

//Normalizing for genome size

//return (disjoint_coeff*(num_disjoint/max_genome_size)+

//  excess_coeff*(num_excess/max_genome_size)+

//  mutdiff_coeff*(mut_diff_total/num_matching));

//Look at disjointedness and excess in the absolute (ignoring size)

//cout<<"COMPAT: size = "<<max_genome_size<<" disjoint = "<<num_disjoint<<" excess = "<<num_excess<<" diff = "<<mut_diff_total<<"  TOTAL = "<<(disjoint_coeff*(num_disjoint/1.0)+excess_coeff*(num_excess/1.0)+mutdiff_coeff*(mut_diff_total/num_matching))<<std::endl;

return (NEAT::disjoint_coeff*(num_disjoint/1.0)+

NEAT::excess_coeff*(num_excess/1.0)+

NEAT::mutdiff_coeff*(mut_diff_total/num_matching));

}

double Genome::trait_compare(Trait *t1,Trait *t2) {

int id1=t1->trait_id;

int id2=t2->trait_id;

int count;

double params_diff=0.0; //Measures parameter difference

//See if traits represent different fundamental types of connections

if ((id1==1)&&(id2>=2)) {

return 0.5;

}

else if ((id2==1)&&(id1>=2)) {

return 0.5;

}

//Otherwise, when types are same, compare the actual parameters

else {

if (id1>=2) {

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

params_diff += fabs(t1->params[count]-t2->params[count]);

}

return params_diff/4.0;

}

else return 0.0; //For type 1, params are not applicable

}

}

int Genome::extrons() {

std::vector<Gene*>::iterator curgene;

int total=0;

for(curgene=genes.begin();curgene!=genes.end();curgene++) {

if ((*curgene)->enable) ++total;

}

return total;

}

void Genome::randomize_traits() {

int numtraits=traits.size();

int traitnum; //number of selected random trait

std::vector<NNode*>::iterator curnode;

std::vector<Gene*>::iterator curgene;

std::vector<Trait*>::iterator curtrait;

//Go through all nodes and randomize their trait pointers

for(curnode=nodes.begin();curnode!=nodes.end();++curnode) {

traitnum=randint(1,numtraits); //randomize trait

(*curnode)->trait_id=traitnum;

curtrait=traits.begin();

while(((*curtrait)->trait_id)!=traitnum)

++curtrait;

(*curnode)->nodetrait=(*curtrait);

//if ((*curtrait)==0) cout<<"ERROR: Random trait empty"<<std::endl;

}

//Go through all connections and randomize their trait pointers

for(curgene=genes.begin();curgene!=genes.end();++curgene) {

traitnum=randint(1,numtraits); //randomize trait

(*curgene)->lnk->trait_id=traitnum;

curtrait=traits.begin();

while(((*curtrait)->trait_id)!=traitnum)

++curtrait;

(*curgene)->lnk->linktrait=(*curtrait);

//if ((*curtrait)==0) cout<<"ERROR: Random trait empty"<<std::endl;

}

}

//Calls special constructor that creates a Genome of 3 possible types:

//0 - Fully linked, no hidden nodes

//1 - Fully linked, one hidden node splitting each link

//2 - Fully connected with a hidden layer 

//num_hidden is only used in type 2

//Saves to filename argument

Genome* NEAT::new_Genome_auto(int num_in,int num_out,int num_hidden,int type, const char *filename) {

Genome *g=new Genome(num_in,num_out,num_hidden,type);

//print_Genome_tofile(g,"auto_genome");

print_Genome_tofile(g, filename);

return g;

}

void NEAT::print_Genome_tofile(Genome *g,const char *filename) {

//ofstream oFile(filename,ios::out);

    std::string file = "nero/data/neat/";

    file += filename;

    //strcpyl(file, 100, "nero/data/neat/", filename, 0);

std::ofstream oFile(file.c_str());

// oFile.open(file, std::ostream::Write);

//Make sure it worked

//if (!oFile) {

// cerr<<"Can't open "<<filename<<" for output"<<std::endl;

// return 0;

//}

g->print_to_file(oFile);

oFile.close();

}