create NEAT app repo
This commit is contained in:
commit
9cd2d19fb9
34 files changed
+4454
No files matched your search
@@ -0,0 +1,76 @@
|
|||||||
|
#include "ConnectionGene.h"
|
||||||
|
|
||||||
|
#include "Innovator.h"
|
||||||
|
#include "NEAT.h"
|
||||||
|
#include "Random.h"
|
||||||
|
|
||||||
|
ConnectionGene::ConnectionGene(Innovator& innovator, int input_id, int output_id) :
|
||||||
|
Gene(innovator.GetConnectionInnovation(input_id,output_id)),
|
||||||
|
m_in_node(input_id),
|
||||||
|
m_out_node(output_id),
|
||||||
|
m_weight(RandomWeight()),
|
||||||
|
m_enabled(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionGene::ConnectionGene(Innovator& innovator, int input_id, int output_id, float weight) :
|
||||||
|
Gene(innovator.GetConnectionInnovation(input_id,output_id)),
|
||||||
|
m_in_node(input_id),
|
||||||
|
m_out_node(output_id),
|
||||||
|
m_weight(weight),
|
||||||
|
m_enabled(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionGene::Mutate()
|
||||||
|
{
|
||||||
|
if ( RandomChance(NEAT::pUniformWeightPerturbation) )
|
||||||
|
{
|
||||||
|
m_weight += RandomPreturbation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_weight = RandomWeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionGene::Disable()
|
||||||
|
{
|
||||||
|
m_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionGene::Enable()
|
||||||
|
{
|
||||||
|
m_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectionGene::IsEnabled() const
|
||||||
|
{
|
||||||
|
return m_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectionGene::GetInputNeuron() const
|
||||||
|
{
|
||||||
|
return m_in_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectionGene::GetOutputNeuron() const
|
||||||
|
{
|
||||||
|
return m_out_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectionGene::operator< (const ConnectionGene& rhs) const
|
||||||
|
{
|
||||||
|
return static_cast<Gene>(*this) < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectionGene::operator== (const ConnectionGene& rhs) const
|
||||||
|
{
|
||||||
|
return static_cast<Gene>(*this) == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ConnectionGene::GetWeight() const
|
||||||
|
{
|
||||||
|
return m_weight;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef __ConnectionGene_h__
|
||||||
|
#define __ConnectionGene_h__
|
||||||
|
|
||||||
|
#include "Gene.h"
|
||||||
|
|
||||||
|
class Innovator;
|
||||||
|
|
||||||
|
class ConnectionGene: public Gene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ConnectionGene(Innovator& innovator, int input_id, int output_id);
|
||||||
|
ConnectionGene(Innovator& innovator, int input_id, int output_id, float weight);
|
||||||
|
|
||||||
|
void Mutate();
|
||||||
|
|
||||||
|
void Disable();
|
||||||
|
void Enable();
|
||||||
|
bool IsEnabled() const;
|
||||||
|
|
||||||
|
int GetInputNeuron() const;
|
||||||
|
int GetOutputNeuron() const;
|
||||||
|
float GetWeight() const;
|
||||||
|
|
||||||
|
bool operator< (const ConnectionGene& rhs) const;
|
||||||
|
bool operator== (const ConnectionGene& rhs) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int m_in_node;
|
||||||
|
int m_out_node;
|
||||||
|
float m_weight;
|
||||||
|
bool m_enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __ConnectionGene_h__
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#include "Gene.h"
|
||||||
|
|
||||||
|
Gene::Gene() :
|
||||||
|
m_innovation(-1)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Gene::Gene(int innovation) :
|
||||||
|
m_innovation(innovation)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Gene::~Gene()
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
int Gene::GetInnovation() const
|
||||||
|
{
|
||||||
|
return m_innovation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gene::operator< (const Gene& rhs) const
|
||||||
|
{
|
||||||
|
return m_innovation < rhs.m_innovation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gene::operator== (const Gene& rhs) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(m_innovation != -1) &&
|
||||||
|
(rhs.m_innovation != -1) &&
|
||||||
|
(m_innovation == rhs.m_innovation);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef __Gene_h__
|
||||||
|
#define __Gene_h__
|
||||||
|
|
||||||
|
class Gene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Gene();
|
||||||
|
Gene(int innovation);
|
||||||
|
virtual ~Gene();
|
||||||
|
|
||||||
|
int GetInnovation() const;
|
||||||
|
|
||||||
|
bool operator< (const Gene& rhs) const;
|
||||||
|
bool operator== (const Gene& rhs) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_innovation;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __Gene_h__
|
||||||
|
|
||||||
+330
@@ -0,0 +1,330 @@
|
|||||||
|
#include "Genotype.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "IteratorHelper.h"
|
||||||
|
#include "MathHelper.h"
|
||||||
|
#include "NEAT.h"
|
||||||
|
#include "Random.h"
|
||||||
|
|
||||||
|
|
||||||
|
Genotype::Genotype(Innovator& innovator, int num_inputs, int num_outputs)
|
||||||
|
{
|
||||||
|
assert(num_inputs > 0 && num_inputs > 0);
|
||||||
|
|
||||||
|
// create bias neuron
|
||||||
|
Neurons.push_back( NeuronGene(innovator) );
|
||||||
|
|
||||||
|
// create input neurons
|
||||||
|
for (int i=0;i<num_inputs;++i)
|
||||||
|
{
|
||||||
|
Neurons.push_back( NeuronGene(innovator,NeuronGene::INPUT,i,num_inputs) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// create output neurons
|
||||||
|
for (int i=0;i<num_outputs;++i)
|
||||||
|
{
|
||||||
|
Neurons.push_back( NeuronGene(innovator,NeuronGene::OUTPUT,i,num_outputs) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect the bias and each input to each output
|
||||||
|
for (int i=0;i<(num_inputs+1);++i)
|
||||||
|
{
|
||||||
|
for (int j=(num_inputs+1);j<(num_inputs+num_outputs+1);++j)
|
||||||
|
{
|
||||||
|
Connections.push_back( ConnectionGene(innovator,Neurons[i].GetInnovation(),Neurons[j].GetInnovation()) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Genotype::Genotype(const Genotype& mom, const Genotype& dad)
|
||||||
|
{
|
||||||
|
// assuming that the mom is the more fit parent, NEAT crossover can
|
||||||
|
// be simplified to:
|
||||||
|
// 1. copy the mom
|
||||||
|
// 2. for each shared mom/dad connection gene, randomly replace that gene in the mom with the one from the dad
|
||||||
|
|
||||||
|
// step one, copy the mom directly
|
||||||
|
Neurons = mom.Neurons;
|
||||||
|
Connections = mom.Connections;
|
||||||
|
|
||||||
|
// step two, randomly replace shared connection genes from dad into mom
|
||||||
|
iterate_each ( std::vector<ConnectionGene>::const_iterator, it_dad, dad.Connections )
|
||||||
|
{
|
||||||
|
// see if mom has matching gene, via brute force search
|
||||||
|
iterate_each( std::vector<ConnectionGene>::iterator, it_mom, Connections )
|
||||||
|
{
|
||||||
|
// does this one match? and, does the PRNG say we should do it?
|
||||||
|
if ( RandomBool() && (*it_mom) == (*it_dad) )
|
||||||
|
{
|
||||||
|
// yes, there's a match, make the swap
|
||||||
|
(*it_mom) = (*it_dad);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - handle case where mom & dad have the same fitness
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genotype::MutateConnectionWeights()
|
||||||
|
{
|
||||||
|
// mutate every connection
|
||||||
|
iterate_each ( std::vector<ConnectionGene>::iterator, it, Connections )
|
||||||
|
{
|
||||||
|
(*it).Mutate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Genotype::MutateAddNeuron(Innovator& innovator, int retries)
|
||||||
|
{
|
||||||
|
// pointers to the two neurons we're adding a neuron in between
|
||||||
|
NeuronGene* input;
|
||||||
|
NeuronGene* output;
|
||||||
|
|
||||||
|
// figure out a connection to split
|
||||||
|
size_t connection_id;
|
||||||
|
int i;
|
||||||
|
for (i=0;i<retries;++i)
|
||||||
|
{
|
||||||
|
// choose a random connection
|
||||||
|
connection_id = RandomRange(0,(int)Connections.size()-1);
|
||||||
|
|
||||||
|
// make certain this connection is enabled
|
||||||
|
if ( !Connections[connection_id].IsEnabled() )
|
||||||
|
{
|
||||||
|
// don't split disabled connections
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the new neurons on either side of the chosen connection
|
||||||
|
input = GetNeuronByInnovation(Connections[connection_id].GetInputNeuron());
|
||||||
|
output = GetNeuronByInnovation(Connections[connection_id].GetOutputNeuron());
|
||||||
|
assert(input && output);
|
||||||
|
|
||||||
|
// see if that node exists and is already in this genotype
|
||||||
|
int new_id = innovator.FindNeuronInnovation((*input).GetInnovation(),(*output).GetInnovation());
|
||||||
|
if ( new_id >= 0 && GetNeuronByInnovation(new_id) )
|
||||||
|
{
|
||||||
|
// neuron already exists in this individual
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we're not splitting a recurrent link
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// make sure we're not splitting a looped link
|
||||||
|
if ( (*input) == (*output) )
|
||||||
|
{
|
||||||
|
// no sense in splitting a looped link
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we're not splitting a bias neuron
|
||||||
|
if ( input->GetType() == NeuronGene::BIAS )
|
||||||
|
{
|
||||||
|
// no sense in splitting bias neurons
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we get here, we have a good split
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we found nothing, bail out
|
||||||
|
if ( i >= retries )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable it
|
||||||
|
Connections[connection_id].Disable();
|
||||||
|
|
||||||
|
// create a nueron splitting these two nodes
|
||||||
|
NeuronGene new_neuron = NeuronGene(innovator,*input,*output);
|
||||||
|
|
||||||
|
// link the new node in with two new connections
|
||||||
|
float orig_weight = Connections[connection_id].GetWeight();
|
||||||
|
Connections.push_back( ConnectionGene(innovator,(*input).GetInnovation(),new_neuron.GetInnovation(),1.0f) );
|
||||||
|
Connections.push_back( ConnectionGene(innovator,new_neuron.GetInnovation(),(*output).GetInnovation(),orig_weight) );
|
||||||
|
|
||||||
|
// finally, add neuron to our list
|
||||||
|
// this invalidates the input, output pointers used above
|
||||||
|
Neurons.push_back(new_neuron);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Genotype::MutateAddConnection(Innovator& innovator, int retries)
|
||||||
|
{
|
||||||
|
// decide if this will be a looped, recurrent, or forward connection
|
||||||
|
|
||||||
|
while (retries--)
|
||||||
|
{
|
||||||
|
// choose two random neurons
|
||||||
|
int neuron_a_id = RandomRange(0,(int)Neurons.size()-1);
|
||||||
|
int neuron_b_id = RandomRange(0,(int)Neurons.size()-1);
|
||||||
|
|
||||||
|
// make sure target is not bias or input neuron
|
||||||
|
if ( Neurons[neuron_b_id].GetType() == NeuronGene::BIAS || Neurons[neuron_b_id].GetType() == NeuronGene::INPUT )
|
||||||
|
{
|
||||||
|
// TODO could skip this if we'd just select from (m_num_inputs+1,num_neurons) instead of (0,num_neurons)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for loop
|
||||||
|
if ( neuron_a_id == neuron_b_id )
|
||||||
|
{
|
||||||
|
// TODO this could actually be allowed
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for recurrent
|
||||||
|
if ( IsRecurrent(neuron_a_id,neuron_b_id) )
|
||||||
|
{
|
||||||
|
// make forward
|
||||||
|
std::swap(neuron_a_id,neuron_b_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if this connection exists
|
||||||
|
if ( GetConnectionByNeuron(Neurons[neuron_a_id].GetInnovation(),Neurons[neuron_b_id].GetInnovation()) )
|
||||||
|
{
|
||||||
|
// exists
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we got a match, add the connection
|
||||||
|
Connections.push_back( ConnectionGene(innovator,Neurons[neuron_a_id].GetInnovation(),Neurons[neuron_b_id].GetInnovation()) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NeuronGene* Genotype::GetNeuronByInnovation(int innovation)
|
||||||
|
{
|
||||||
|
// search every neuron for this innovation
|
||||||
|
iterate_each ( std::vector<NeuronGene>::iterator, it, Neurons )
|
||||||
|
{
|
||||||
|
if ( (*it).GetInnovation() == innovation )
|
||||||
|
{
|
||||||
|
return &(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionGene* Genotype::GetConnectionByNeuron(int from_neuron, int to_neuron)
|
||||||
|
{
|
||||||
|
// search for every connection that matches these neurons
|
||||||
|
iterate_each ( std::vector<ConnectionGene>::iterator, it, Connections )
|
||||||
|
{
|
||||||
|
if ( (*it).GetInputNeuron() == from_neuron && (*it).GetOutputNeuron() == to_neuron )
|
||||||
|
{
|
||||||
|
return &(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing found
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Genotype::IsRecurrent(int from_neuron, int to_neuron)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(Neurons[to_neuron].GetY() < Neurons[from_neuron].GetY()) ||
|
||||||
|
(Neurons[to_neuron].GetY() == Neurons[from_neuron].GetY() && Neurons[to_neuron].GetY() < Neurons[from_neuron].GetY());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genotype::Output()
|
||||||
|
{
|
||||||
|
static char* typestr[5] = { "unknown", "bias", "input", "output", "hidden" };
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
for (size_t i=0;i<Neurons.size();++i)
|
||||||
|
{
|
||||||
|
printf("neuron %d %s\n",Neurons[i].GetInnovation(),typestr[Neurons[i].GetType()]);
|
||||||
|
}
|
||||||
|
for (size_t i=0;i<Connections.size();++i)
|
||||||
|
{
|
||||||
|
if ( Connections[i].IsEnabled() )
|
||||||
|
{
|
||||||
|
printf("connection %3d %3d %0.10f\n",Connections[i].GetInputNeuron(),Connections[i].GetOutputNeuron(),Connections[i].GetWeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genotype::SetFitness(float fitness)
|
||||||
|
{
|
||||||
|
Fitness = fitness;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Genotype::GetFitness() const
|
||||||
|
{
|
||||||
|
return Fitness;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Genotype::operator< (const Genotype& rhs) const
|
||||||
|
{
|
||||||
|
return Fitness < rhs.Fitness;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Genotype::GetCompatibility(const Genotype& genome) const
|
||||||
|
{
|
||||||
|
int disjoint_excess = 0, common = 0;
|
||||||
|
float weight_diff = 0.0f;
|
||||||
|
|
||||||
|
iterate_each ( std::vector<ConnectionGene>::const_iterator, it_lhs, Connections )
|
||||||
|
{
|
||||||
|
bool match = false;
|
||||||
|
iterate_each ( std::vector<ConnectionGene>::const_iterator, it_rhs, genome.Connections )
|
||||||
|
{
|
||||||
|
if ( (*it_lhs) == (*it_rhs) )
|
||||||
|
{
|
||||||
|
weight_diff += fabs((*it_lhs).GetWeight() - (*it_rhs).GetWeight());
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( match )
|
||||||
|
{
|
||||||
|
++common;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++disjoint_excess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t lhs_size = Connections.size() + Neurons.size();
|
||||||
|
size_t rhs_size = genome.Connections.size() + genome.Neurons.size();
|
||||||
|
size_t N = std::max(lhs_size, rhs_size);
|
||||||
|
float weight_diff_avg = weight_diff / (float)common;
|
||||||
|
return ((float)disjoint_excess/(float)N) + (0.4f * weight_diff_avg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Genotype::Mutate(Innovator& innovator)
|
||||||
|
{
|
||||||
|
switch ( Roulette(3,NEAT::pAddConnection,NEAT::pAddNeuron,NEAT::pWeightsMutated))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
MutateAddConnection(innovator);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
MutateAddNeuron(innovator);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
MutateConnectionWeights();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef __Genotype_h__
|
||||||
|
#define __Genotype_h__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ConnectionGene.h"
|
||||||
|
#include "NeuronGene.h"
|
||||||
|
|
||||||
|
class Innovator;
|
||||||
|
|
||||||
|
class Genotype
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// construct a new random genotype
|
||||||
|
Genotype(Innovator& innovator, int num_inputs, int num_outputs);
|
||||||
|
|
||||||
|
// construct a new genotype via crossover
|
||||||
|
Genotype(const Genotype& mom, const Genotype& dad);
|
||||||
|
|
||||||
|
void Output();
|
||||||
|
|
||||||
|
int CalculateLayers();
|
||||||
|
|
||||||
|
void SetFitness(float fitness);
|
||||||
|
float GetFitness() const;
|
||||||
|
|
||||||
|
void Mutate(Innovator& innovator);
|
||||||
|
|
||||||
|
bool operator< (const Genotype& rhs) const;
|
||||||
|
|
||||||
|
// calculate compatibility with another genotype
|
||||||
|
float GetCompatibility(const Genotype& genome) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// preturb weights
|
||||||
|
void MutateConnectionWeights();
|
||||||
|
|
||||||
|
// add a neuron
|
||||||
|
bool MutateAddNeuron(Innovator& innovator, int retries=100);
|
||||||
|
|
||||||
|
// add a connection
|
||||||
|
bool MutateAddConnection(Innovator& innovator, int retries=100);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
friend class NeuralNetwork;
|
||||||
|
|
||||||
|
NeuronGene* GetNeuronByInnovation(int innovation); // todo could be a bool?
|
||||||
|
ConnectionGene* GetConnectionByNeuron(int from_neuron, int to_neuron);
|
||||||
|
bool IsRecurrent(int from_neuron, int to_neuron);
|
||||||
|
|
||||||
|
std::vector<NeuronGene> Neurons;
|
||||||
|
std::vector<ConnectionGene> Connections;
|
||||||
|
|
||||||
|
float Fitness;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __Genotype_h__
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include "Innovation.h"
|
||||||
|
|
||||||
|
// deprecated
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef __Innovation_h__
|
||||||
|
#define __Innovation_h__
|
||||||
|
|
||||||
|
// deprecated
|
||||||
|
|
||||||
|
#endif // __Innovation_h__
|
||||||
|
|
||||||
+132
@@ -0,0 +1,132 @@
|
|||||||
|
#include "Innovator.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "IteratorHelper.h"
|
||||||
|
|
||||||
|
Innovator::Innovation::Innovation(int type, int in_id, int out_id, float pos_x, float pos_y) :
|
||||||
|
in_id(in_id),
|
||||||
|
out_id(out_id),
|
||||||
|
innovation_id(-1),
|
||||||
|
type(type),
|
||||||
|
pos_x(pos_x),
|
||||||
|
pos_y(pos_y)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Innovator::Innovation::operator<(const Innovation& rhs) const
|
||||||
|
{
|
||||||
|
// this method is really only used for sorting and searching
|
||||||
|
return
|
||||||
|
(type < rhs.type) ||
|
||||||
|
(type == rhs.type && in_id < rhs.in_id) ||
|
||||||
|
(type == rhs.type && in_id == rhs.in_id && out_id < rhs.out_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Innovator::Innovation::operator==(const Innovation& rhs) const
|
||||||
|
{
|
||||||
|
// equality ignores the innovation number
|
||||||
|
return (in_id == rhs.in_id) && (out_id == rhs.out_id) && (type == rhs.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int Innovator::GetConnectionInnovation(int input_id, int output_id)
|
||||||
|
{
|
||||||
|
Innovation target = Innovation(Innovation::CONNECTION, input_id, output_id);
|
||||||
|
Innovation result = GetInnovation(target);
|
||||||
|
return result.innovation_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int Innovator::GetNeuronInnovation(int prev_id, int next_id, float pos_x, float pos_y)
|
||||||
|
{
|
||||||
|
Innovation target = Innovation(Innovation::NEURON, prev_id, next_id, pos_x, pos_y);
|
||||||
|
Innovation result = GetInnovation(target);
|
||||||
|
return result.innovation_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Innovator::FindNeuronInnovation(int prev_id, int next_id)
|
||||||
|
{
|
||||||
|
// TODO: this code is duplicated in GetInnovation() - refactor
|
||||||
|
|
||||||
|
// create a temp neuron to search for
|
||||||
|
Innovation target(Innovation::NEURON, prev_id, next_id, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
// search master innovation list
|
||||||
|
std::vector<Innovation>::iterator result;
|
||||||
|
result = std::lower_bound(m_innovations.begin(), m_innovations.end(), target);
|
||||||
|
if ( result != m_innovations.end() && (*result) == target )
|
||||||
|
{
|
||||||
|
// found in master list
|
||||||
|
return (*result).innovation_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// search new innovation list
|
||||||
|
result = std::find(m_new_innovations.begin(), m_new_innovations.end(), target);
|
||||||
|
if ( result != m_new_innovations.end() )
|
||||||
|
{
|
||||||
|
// found in new temp list
|
||||||
|
return (*result).innovation_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found!
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Innovator::Update()
|
||||||
|
{
|
||||||
|
// make sure we have something to process
|
||||||
|
if ( m_new_innovations.size() == 0 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy new innovations into global innovations
|
||||||
|
iterate_each ( std::vector<Innovation>::iterator, it, m_new_innovations )
|
||||||
|
{
|
||||||
|
m_innovations.push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear new innovations
|
||||||
|
m_new_innovations.clear();
|
||||||
|
|
||||||
|
// sort global innovations
|
||||||
|
std::sort(m_innovations.begin(), m_innovations.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Innovator::Innovation Innovator::GetInnovation(Innovation& target)
|
||||||
|
{
|
||||||
|
// search master innovation list
|
||||||
|
std::vector<Innovation>::iterator result;
|
||||||
|
result = std::lower_bound(m_innovations.begin(), m_innovations.end(), target);
|
||||||
|
if ( result != m_innovations.end() && (*result) == target )
|
||||||
|
{
|
||||||
|
// found in master list
|
||||||
|
return (*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// search new innovation list
|
||||||
|
result = std::find(m_new_innovations.begin(), m_new_innovations.end(), target);
|
||||||
|
if ( result != m_new_innovations.end() )
|
||||||
|
{
|
||||||
|
// found in new temp list
|
||||||
|
return (*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// innovation not found, create new innovation
|
||||||
|
|
||||||
|
// first get an id
|
||||||
|
target.innovation_id = (int)m_innovations.size() + (int)m_new_innovations.size();
|
||||||
|
|
||||||
|
// finally, add the new innovation to the new innovation list
|
||||||
|
m_new_innovations.push_back(target);
|
||||||
|
|
||||||
|
// return new id
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
#ifndef __Innovator_h__
|
||||||
|
#define __Innovator_h__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Innovator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
int GetConnectionInnovation(int input_id, int output_id);
|
||||||
|
|
||||||
|
int GetNeuronInnovation(int prev_id, int next_id, float pos_x, float pos_y);
|
||||||
|
|
||||||
|
int FindNeuronInnovation(int prev_id, int next_id);
|
||||||
|
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// data structure used to track innovations
|
||||||
|
struct Innovation
|
||||||
|
{
|
||||||
|
// data
|
||||||
|
int in_id, out_id, innovation_id;
|
||||||
|
int type;
|
||||||
|
float pos_x, pos_y;
|
||||||
|
|
||||||
|
// innovation types
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
NEURON,
|
||||||
|
CONNECTION
|
||||||
|
};
|
||||||
|
|
||||||
|
// construct an innovation
|
||||||
|
Innovation(int type, int in_id, int out_id, float pos_x = 0.0f, float pos_y = 0.0f);
|
||||||
|
|
||||||
|
// used for sorting, searching
|
||||||
|
bool operator<(const Innovation& rhs) const;
|
||||||
|
bool operator==(const Innovation& rhs) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// look in the list for a matching innovation to the one passed in
|
||||||
|
Innovation GetInnovation(Innovation& target);
|
||||||
|
|
||||||
|
// master list of our innovations
|
||||||
|
std::vector<Innovation> m_innovations;
|
||||||
|
|
||||||
|
// temporary (smaller) list of current new innovations, rolls into master list on calls to Update
|
||||||
|
std::vector<Innovation> m_new_innovations;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __Innovator_h__
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __IteratorHelper_h__
|
||||||
|
#define __IteratorHelper_h__
|
||||||
|
|
||||||
|
// code Ruby for awhile and C++ iterators start to look crude and disgusting
|
||||||
|
#define iterate_each( iterator_type, iterator_name, container ) \
|
||||||
|
for ( iterator_type iterator_name = container.begin(); iterator_name != container.end(); ++iterator_name )
|
||||||
|
|
||||||
|
#define iterate_times( x ) \
|
||||||
|
for ( unsigned int i__LINE__ = 0; i__LINE__ < (x); ++i__LINE__ )
|
||||||
|
|
||||||
|
#endif // __IteratorHelper_h__
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#ifndef __MathHelper_h__
|
||||||
|
#define __MathHelper_h__
|
||||||
|
|
||||||
|
#endif // __MathHelper_h__
|
||||||
@@ -0,0 +1,321 @@
|
|||||||
|
#include "NEAT.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "IteratorHelper.h"
|
||||||
|
#include "NeuralNetwork.h"
|
||||||
|
#include "Random.h"
|
||||||
|
|
||||||
|
|
||||||
|
const int NEAT::kPopulation = 150; // size of population
|
||||||
|
const float NEAT::kC1 = 1.0f; // coefficient for excess genes in compatibility equation
|
||||||
|
const float NEAT::kC2 = 1.0f; // coefficient for disjoint genes in compatibility equation
|
||||||
|
const float NEAT::kC3 = 0.4f; // coefficient for weight delta in compatibility equation
|
||||||
|
const float NEAT::kCompatibilityThreshold = 3.0f; // used in speciation
|
||||||
|
const int NEAT::kNumUnimprovedGensAllowed = 15; // # generations a species is allowed to not improve
|
||||||
|
const int NEAT::kMinSpeciesSizeForChampionReproduction = 5; // species must be at least this big
|
||||||
|
const float NEAT::pWeightsMutated = 0.8f; // chance a genome has its weights mutated
|
||||||
|
const float NEAT::pUniformWeightPerturbation = 0.9f; // each weight's chance of uniform perturbation
|
||||||
|
const float NEAT::pAssignNewWeight = 0.1f; // each weight's chance of getting replaced
|
||||||
|
const float NEAT::pInheritedGeneDisabled = 0.75f; // chance gene disabled if it was disabled in either parent
|
||||||
|
const float NEAT::pMutationOnly = 0.25f; // chance of reproduction through mutation, without crossover
|
||||||
|
const float NEAT::kInterSpeciesRate = 0.001f; // inter-species mating rate
|
||||||
|
const float NEAT::pAddNeuron = 0.03f; // chance of adding a neuron (mutation)
|
||||||
|
const float NEAT::pAddConnection = 0.05f; // chance of adding a new connection (mutation)
|
||||||
|
const float NEAT::kMaxWeightPerturbation = 0.1f; // +/- weight perturbation (mutation)
|
||||||
|
const float NEAT::kMaxNewWeight = 0.5f; // +/- range for new weights
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
NEAT::NEAT(int num_inputs, int num_outputs) :
|
||||||
|
m_next_species_id(0)
|
||||||
|
{
|
||||||
|
// create initial population
|
||||||
|
iterate_times(NEAT::kPopulation)
|
||||||
|
{
|
||||||
|
m_population.push_back( Genotype(m_innovator, num_inputs, num_outputs) );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NEAT::SortPopulation()
|
||||||
|
{
|
||||||
|
std::sort(m_population.begin(),m_population.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NEAT::SaveBestGenomes()
|
||||||
|
{
|
||||||
|
// add best of current population to best ever
|
||||||
|
assert(m_population.size() >= 4);
|
||||||
|
for( unsigned int i = 0; i < 4; ++i )
|
||||||
|
{
|
||||||
|
m_best.push_back( m_population[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort
|
||||||
|
std::sort(m_best.begin(),m_best.end());
|
||||||
|
|
||||||
|
// kill off all but 4
|
||||||
|
while ( m_best.size() > 4 )
|
||||||
|
{
|
||||||
|
m_best.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NEAT::SpeciatePopulation()
|
||||||
|
{
|
||||||
|
// clear old members out of all species, and choose a representative member in each species
|
||||||
|
iterate_each( std::vector<Species>::iterator, it_species, m_species )
|
||||||
|
{
|
||||||
|
// make sure species is not dead
|
||||||
|
if ( !(*it_species).member_ids.empty() )
|
||||||
|
{
|
||||||
|
// has members, just choose random as representative for next generation
|
||||||
|
int rep_id = RandomRange(0,(int)(*it_species).member_ids.size()-1);
|
||||||
|
(*it_species).representative = m_population[rep_id];
|
||||||
|
(*it_species).member_ids.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add each genome into a species, or create a new species if necessary
|
||||||
|
for ( int i=0; i<(int)m_population.size(); ++i )
|
||||||
|
{
|
||||||
|
// test every species for compatibility with genome i
|
||||||
|
bool added = false;
|
||||||
|
iterate_each( std::vector<Species>::iterator, it_species, m_species )
|
||||||
|
{
|
||||||
|
// test genotype for compatibility with this species
|
||||||
|
if ( (*it_species).representative.GetCompatibility(m_population[i]) < NEAT::kCompatibilityThreshold )
|
||||||
|
{
|
||||||
|
// add it
|
||||||
|
(*it_species).member_ids.push_back(i);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we didn't add this genome to any species, create one now
|
||||||
|
if ( !added )
|
||||||
|
{
|
||||||
|
m_species.push_back(Species(m_population[i],i,m_next_species_id++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kill off any dead species
|
||||||
|
iterate_each( std::vector<Species>::iterator, it_species, m_species )
|
||||||
|
{
|
||||||
|
if ( (*it_species).member_ids.empty() )
|
||||||
|
{
|
||||||
|
// erase it
|
||||||
|
// TODO - need to actually remove it???
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%d species\n",m_species.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NEAT::AdjustAndShareFitness()
|
||||||
|
{
|
||||||
|
// fitness for each genome is divided by the total number of genomes in its species
|
||||||
|
iterate_each( std::vector<Species>::iterator, it_species, m_species )
|
||||||
|
{
|
||||||
|
float divisor = (float)((*it_species).member_ids.size());
|
||||||
|
iterate_each( std::vector<int>::iterator, it_member_id, (*it_species).member_ids )
|
||||||
|
{
|
||||||
|
float old_fitness = m_population[*it_member_id].GetFitness();
|
||||||
|
float new_fitness = old_fitness / divisor;
|
||||||
|
m_population[*it_member_id].SetFitness( new_fitness );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NEAT::Reproduce()
|
||||||
|
{
|
||||||
|
// get population size (we'll make sure it ends up with this many)
|
||||||
|
size_t pop_size = m_population.size();
|
||||||
|
|
||||||
|
// waste old population
|
||||||
|
std::vector<Genotype> old_population(m_population);
|
||||||
|
m_population.clear();
|
||||||
|
|
||||||
|
// get total fitness (assumes already adjusted)
|
||||||
|
float fitness_total = 0.0f;
|
||||||
|
iterate_each( std::vector<Genotype>::iterator, it, old_population )
|
||||||
|
{
|
||||||
|
fitness_total += (*it).GetFitness();
|
||||||
|
}
|
||||||
|
|
||||||
|
// now have each species spawn amounts based on its share population average
|
||||||
|
iterate_each( std::vector<Species>::iterator, it_species, m_species )
|
||||||
|
{
|
||||||
|
// ignore this species if it's dead
|
||||||
|
if ( (*it_species).member_ids.empty() )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum total fitness for this species
|
||||||
|
float species_fitness = 0.0f;
|
||||||
|
iterate_each( std::vector<int>::iterator, it_member_id, (*it_species).member_ids )
|
||||||
|
{
|
||||||
|
species_fitness += old_population[*it_member_id].GetFitness();
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate how many to spawn
|
||||||
|
float fitness_share = species_fitness / fitness_total;
|
||||||
|
size_t num_to_spawn = (int)(fitness_share * (float)pop_size + 0.5f);
|
||||||
|
|
||||||
|
// now do the reproductions
|
||||||
|
// first one is simply the best in the species
|
||||||
|
m_population.push_back( old_population[(*it_species).member_ids[0]] );
|
||||||
|
|
||||||
|
// and fill up the rest with random based reproduction
|
||||||
|
iterate_times(num_to_spawn-1)
|
||||||
|
{
|
||||||
|
// determine if this is sexual or asexual
|
||||||
|
if ( RandomChance(NEAT::pMutationOnly) )
|
||||||
|
{
|
||||||
|
// asexual reproduction
|
||||||
|
// choose one random genome from the species
|
||||||
|
int survivor_count = (int)(*it_species).member_ids.size();
|
||||||
|
if ( survivor_count < 1 )
|
||||||
|
{
|
||||||
|
survivor_count = 1;
|
||||||
|
}
|
||||||
|
int a = RandomZeroBiased(survivor_count-1);
|
||||||
|
|
||||||
|
// copy
|
||||||
|
Genotype g = old_population[a];
|
||||||
|
|
||||||
|
// mutate
|
||||||
|
g.Mutate(m_innovator);
|
||||||
|
|
||||||
|
// add to population
|
||||||
|
m_population.push_back(g);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// sexual reproduction
|
||||||
|
// choose two random genomes from the species
|
||||||
|
int survivor_count = (int)(*it_species).member_ids.size();
|
||||||
|
if ( survivor_count < 1 )
|
||||||
|
{
|
||||||
|
survivor_count = 1;
|
||||||
|
}
|
||||||
|
int a = RandomZeroBiased(survivor_count-1);
|
||||||
|
int b = RandomZeroBiased(survivor_count-1);
|
||||||
|
if ( b < a )
|
||||||
|
{
|
||||||
|
std::swap(a,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mate them
|
||||||
|
Genotype g = Genotype(old_population[a], old_population[b]);
|
||||||
|
|
||||||
|
// mutate
|
||||||
|
g.Mutate(m_innovator);
|
||||||
|
|
||||||
|
// add to population
|
||||||
|
m_population.push_back( g );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NEAT::Run()
|
||||||
|
{
|
||||||
|
iterate_times(10000)
|
||||||
|
{
|
||||||
|
// update the innovator
|
||||||
|
m_innovator.Update();
|
||||||
|
|
||||||
|
// build networks from genomes
|
||||||
|
std::vector<NeuralNetwork> networks;
|
||||||
|
iterate_each( std::vector<Genotype>::iterator, it_genotype, m_population )
|
||||||
|
{
|
||||||
|
networks.push_back( NeuralNetwork(*it_genotype) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// test networks
|
||||||
|
std::vector<float> fitness;
|
||||||
|
bool finished = TestNetworks(networks,fitness);
|
||||||
|
|
||||||
|
// store results
|
||||||
|
assert(fitness.size() == m_population.size());
|
||||||
|
for( unsigned int i = 0; i < fitness.size(); ++i )
|
||||||
|
{
|
||||||
|
m_population[i].SetFitness( fitness[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by fitness
|
||||||
|
SortPopulation();
|
||||||
|
|
||||||
|
// save off the best of the population
|
||||||
|
SaveBestGenomes();
|
||||||
|
|
||||||
|
// now quit if TestNetworks(..) returned true
|
||||||
|
if ( finished )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// speciate
|
||||||
|
SpeciatePopulation();
|
||||||
|
|
||||||
|
// adjust & share fitness
|
||||||
|
AdjustAndShareFitness();
|
||||||
|
|
||||||
|
// finally, create the new population
|
||||||
|
Reproduce();
|
||||||
|
|
||||||
|
printf("best fitness = %0.10f\n",m_best[0].GetFitness());
|
||||||
|
m_best[0].Output();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NEAT::Species::Species(const Genotype& originator, int originator_id, int species_id) :
|
||||||
|
species_id(species_id),
|
||||||
|
representative(originator)
|
||||||
|
{
|
||||||
|
member_ids.push_back(originator_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#ifndef __NEAT_h__
|
||||||
|
#define __NEAT_h__
|
||||||
|
|
||||||
|
#include "Genotype.h"
|
||||||
|
#include "Innovator.h"
|
||||||
|
#include "NeuralNetwork.h"
|
||||||
|
|
||||||
|
class NEAT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const static int kPopulation; // size of population
|
||||||
|
const static float kC1; // coefficient for excess genes in compatibility equation
|
||||||
|
const static float kC2; // coefficient for disjoint genes in compatibility equation
|
||||||
|
const static float kC3; // coefficient for weight delta in compatibility equation
|
||||||
|
const static float kCompatibilityThreshold; // used in speciation
|
||||||
|
const static int kNumUnimprovedGensAllowed; // # generations a species is allowed to not improve
|
||||||
|
const static int kMinSpeciesSizeForChampionReproduction; // species must be at least this big
|
||||||
|
const static float pWeightsMutated; // chance a genome has its weights mutated
|
||||||
|
const static float pUniformWeightPerturbation; // each weight's chance of uniform perturbation
|
||||||
|
const static float pAssignNewWeight; // each weight's chance of getting replaced
|
||||||
|
const static float pInheritedGeneDisabled; // chance gene disabled if it was disabled in either parent
|
||||||
|
const static float pMutationOnly; // chance of reproduction through mutation, without crossover
|
||||||
|
const static float kInterSpeciesRate; // inter-species mating rate
|
||||||
|
const static float pAddNeuron; // chance of adding a neuron (mutation)
|
||||||
|
const static float pAddConnection; // chance of adding a new connection (mutation)
|
||||||
|
const static float kMaxWeightPerturbation; // +/- weight perturbation (mutation)
|
||||||
|
const static float kMaxNewWeight; // +/- range for new weights
|
||||||
|
|
||||||
|
NEAT(int num_inputs, int num_outputs);
|
||||||
|
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual bool TestNetworks(std::vector<NeuralNetwork>& networks, std::vector<float>& fitness) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Species
|
||||||
|
{
|
||||||
|
Species(const Genotype& originator, int originator_id, int species_id);
|
||||||
|
|
||||||
|
int species_id;
|
||||||
|
Genotype representative;
|
||||||
|
std::vector<int> member_ids;
|
||||||
|
};
|
||||||
|
|
||||||
|
Innovator m_innovator;
|
||||||
|
std::vector<Genotype> m_population;
|
||||||
|
std::vector<Genotype> m_best;
|
||||||
|
std::vector<Species> m_species;
|
||||||
|
int m_next_species_id;
|
||||||
|
|
||||||
|
void SortPopulation();
|
||||||
|
void SaveBestGenomes();
|
||||||
|
void SpeciatePopulation();
|
||||||
|
void AdjustAndShareFitness();
|
||||||
|
void Reproduce();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __NEAT_h__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
#include "NeuralNetwork.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "IteratorHelper.h"
|
||||||
|
|
||||||
|
NeuralNetwork::Neuron::Neuron(int id, float x, float y, bool fixed, float activation):
|
||||||
|
ID(id),
|
||||||
|
X(x),
|
||||||
|
Y(y),
|
||||||
|
Fixed(fixed),
|
||||||
|
Activation(activation)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeuralNetwork::Neuron::operator< (const NeuralNetwork::Neuron& rhs) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(Y < rhs.Y) ||
|
||||||
|
((Y == rhs.Y) && (X < rhs.X));
|
||||||
|
}
|
||||||
|
|
||||||
|
NeuralNetwork::NeuralNetwork(const Genotype& genotype)
|
||||||
|
{
|
||||||
|
// reset out input/output count
|
||||||
|
NumInputs = NumOutputs = 0;
|
||||||
|
|
||||||
|
// copy the neurons
|
||||||
|
for ( std::vector<NeuronGene>::const_iterator it = genotype.Neurons.begin(); it != genotype.Neurons.end(); ++it )
|
||||||
|
{
|
||||||
|
switch ( (*it).GetType() )
|
||||||
|
{
|
||||||
|
case NeuronGene::BIAS:
|
||||||
|
Neurons.push_back(Neuron((*it).GetInnovation(),(*it).GetX(),(*it).GetY(),true,1.0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NeuronGene::INPUT:
|
||||||
|
++NumInputs;
|
||||||
|
Neurons.push_back(Neuron((*it).GetInnovation(),(*it).GetX(),(*it).GetY(),true,0.0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NeuronGene::OUTPUT:
|
||||||
|
++NumOutputs;
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case NeuronGene::HIDDEN:
|
||||||
|
Neurons.push_back(Neuron((*it).GetInnovation(),(*it).GetX(),(*it).GetY()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort neurons by position
|
||||||
|
std::sort(Neurons.begin(), Neurons.end());
|
||||||
|
|
||||||
|
// copy the connections
|
||||||
|
for ( std::vector<ConnectionGene>::const_iterator it = genotype.Connections.begin(); it != genotype.Connections.end(); ++it )
|
||||||
|
{
|
||||||
|
if ( (*it).IsEnabled() )
|
||||||
|
{
|
||||||
|
// figure out which two neurons this thing connects
|
||||||
|
int index_a = GetNeuronIndexFromID((*it).GetInputNeuron());
|
||||||
|
int index_b = GetNeuronIndexFromID((*it).GetOutputNeuron());
|
||||||
|
assert(index_a < (int)Neurons.size() && index_b < (int)Neurons.size());
|
||||||
|
|
||||||
|
// now add to the neuron
|
||||||
|
Neurons[index_b].Inputs.push_back( Connection(index_a,(*it).GetWeight()) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print out this network
|
||||||
|
#if 0
|
||||||
|
int i = 0;
|
||||||
|
iterate_each ( std::vector<Neuron>::iterator, it_neuron, Neurons )
|
||||||
|
{
|
||||||
|
printf("Neuron %2d (%2d) %0.2f %0.2f\n",i,(*it_neuron).ID,(*it_neuron).X,(*it_neuron).Y);
|
||||||
|
iterate_each ( std::vector<Connection>::iterator, it_connection, (*it_neuron).Inputs )
|
||||||
|
{
|
||||||
|
printf(" %d %0.5f\n",(*it_connection).id,(*it_connection).weight);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NeuralNetwork::~NeuralNetwork()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NeuralNetwork::Reset()
|
||||||
|
{
|
||||||
|
iterate_each ( std::vector<Neuron>::iterator, it_neuron, Neurons )
|
||||||
|
{
|
||||||
|
if ( !(*it_neuron).Fixed )
|
||||||
|
{
|
||||||
|
(*it_neuron).Activation = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NeuralNetwork::Update(const std::vector<float>& inputs, std::vector<float>& outputs) // TODO make input STL-like, begin(), end() & array compatible
|
||||||
|
{
|
||||||
|
// assign inputs
|
||||||
|
for ( int i=0;i<NumInputs;++i )
|
||||||
|
{
|
||||||
|
// TODO range check this!!!
|
||||||
|
Neurons[i+1].Activation = inputs[i]; // +1 is because Bias is #0 - this is messy TODO: clean up, make safer
|
||||||
|
// TODO make sure this is really an input Neuron!!! and its ID matches up, etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
// update each neuron
|
||||||
|
iterate_each ( std::vector<Neuron>::iterator, it_neuron, Neurons )
|
||||||
|
{
|
||||||
|
// if this is a fixed neuron, skip
|
||||||
|
if ( (*it_neuron).Fixed )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum the inputs into this neuron
|
||||||
|
float sum = 0.0f;
|
||||||
|
iterate_each ( std::vector<Connection>::iterator, it_connection, (*it_neuron).Inputs )
|
||||||
|
{
|
||||||
|
sum += Neurons[(*it_connection).id].Activation * (*it_connection).weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// activate
|
||||||
|
(*it_neuron).Activation = 1.0f / (1.0f + (expf(-4.9f * sum)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear outputs
|
||||||
|
outputs.clear();
|
||||||
|
|
||||||
|
// copy outputs
|
||||||
|
for ( int i=0;i<NumOutputs;++i )
|
||||||
|
{
|
||||||
|
size_t index = Neurons.size() - NumOutputs + i;
|
||||||
|
outputs.push_back( Neurons[index].Activation );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int NeuralNetwork::GetNeuronIndexFromID(int id)
|
||||||
|
{
|
||||||
|
for ( int i=0;i<(int)Neurons.size();++i )
|
||||||
|
{
|
||||||
|
if ( Neurons[i].ID == id )
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef __NeuralNetwork_h__
|
||||||
|
#define __NeuralNetwork_h__
|
||||||
|
|
||||||
|
#include "Genotype.h"
|
||||||
|
|
||||||
|
|
||||||
|
class NeuralNetwork
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NeuralNetwork(const Genotype& genotype);
|
||||||
|
virtual ~NeuralNetwork();
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
void Update(const std::vector<float>& inputs, std::vector<float>& outputs); // TODO make input STL-like, begin(), end() & array compatible
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Connection
|
||||||
|
{
|
||||||
|
Connection(int id, float weight):
|
||||||
|
id(id),
|
||||||
|
weight(weight)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
int id;
|
||||||
|
float weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Neuron
|
||||||
|
{
|
||||||
|
Neuron(int id, float x, float y, bool fixed=false, float activation=0.0);
|
||||||
|
|
||||||
|
bool operator< (const Neuron& rhs) const;
|
||||||
|
|
||||||
|
int ID;
|
||||||
|
float X,Y;
|
||||||
|
bool Fixed;
|
||||||
|
float Activation;
|
||||||
|
std::vector<Connection> Inputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Neuron> Neurons;
|
||||||
|
int NumInputs, NumOutputs;
|
||||||
|
|
||||||
|
int GetNeuronIndexFromID(int id);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __NeuralNetwork_h__
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#include "NeuronGene.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "Innovator.h"
|
||||||
|
|
||||||
|
// construct a bias neuron
|
||||||
|
NeuronGene::NeuronGene(Innovator& innovator) :
|
||||||
|
Gene( innovator.GetNeuronInnovation(-1,-1,m_x_position,m_y_position) ),
|
||||||
|
m_x_position(0.0f),
|
||||||
|
m_y_position(0.0f),
|
||||||
|
m_type(BIAS)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct input|output neuron
|
||||||
|
NeuronGene::NeuronGene(Innovator& innovator, int type, int index, int total) :
|
||||||
|
m_type(type)
|
||||||
|
{
|
||||||
|
assert(type == INPUT || type == OUTPUT);
|
||||||
|
|
||||||
|
if ( type == INPUT )
|
||||||
|
{
|
||||||
|
m_x_position = (float)(index+1)/(float)(total);
|
||||||
|
m_y_position = 0.0f;
|
||||||
|
m_innovation = innovator.GetNeuronInnovation(-(index+2),-1,m_x_position,m_y_position);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_x_position = (float)(index+1)/(float)(total+1); // TODO this isn't in the right position
|
||||||
|
m_y_position = 1.0f;
|
||||||
|
m_innovation = innovator.GetNeuronInnovation(-1,-(index+2),m_x_position,m_y_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct hidden neuron
|
||||||
|
NeuronGene::NeuronGene(Innovator& innovator, const NeuronGene& prev, const NeuronGene& next) :
|
||||||
|
Gene( innovator.GetNeuronInnovation(prev.m_innovation,next.m_innovation,m_x_position,m_y_position) ),
|
||||||
|
m_x_position((prev.m_x_position+next.m_x_position)/2.0f),
|
||||||
|
m_y_position((prev.m_y_position+next.m_y_position)/2.0f),
|
||||||
|
m_type(HIDDEN)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeuronGene::operator< (const NeuronGene& rhs) const
|
||||||
|
{
|
||||||
|
return static_cast<Gene>(*this) < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NeuronGene::operator== (const NeuronGene& rhs) const
|
||||||
|
{
|
||||||
|
return static_cast<Gene>(*this) == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int NeuronGene::GetType() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
float NeuronGene::GetX() const
|
||||||
|
{
|
||||||
|
return m_x_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
float NeuronGene::GetY() const
|
||||||
|
{
|
||||||
|
return m_y_position;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef __NeuronGene_h__
|
||||||
|
#define __NeuronGene_h__
|
||||||
|
|
||||||
|
#include "Gene.h"
|
||||||
|
|
||||||
|
class Innovator;
|
||||||
|
|
||||||
|
class NeuronGene: public Gene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// neuron types
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
BIAS,
|
||||||
|
INPUT,
|
||||||
|
OUTPUT,
|
||||||
|
HIDDEN
|
||||||
|
};
|
||||||
|
|
||||||
|
// construct a bias neuron
|
||||||
|
NeuronGene(Innovator& innovator);
|
||||||
|
|
||||||
|
// construct in input or output neuron
|
||||||
|
NeuronGene(Innovator& innovator, int type, int index, int total);
|
||||||
|
|
||||||
|
// create a hidden neuron between two other neurons
|
||||||
|
NeuronGene(Innovator& innovator, const NeuronGene& prev, const NeuronGene& next);
|
||||||
|
|
||||||
|
bool operator< (const NeuronGene& rhs) const;
|
||||||
|
bool operator== (const NeuronGene& rhs) const;
|
||||||
|
|
||||||
|
int GetType() const;
|
||||||
|
float GetX() const;
|
||||||
|
float GetY() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
float m_x_position;
|
||||||
|
float m_y_position;
|
||||||
|
int m_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __NeuronGene_h__
|
||||||
|
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
#include "Random.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "IteratorHelper.h"
|
||||||
|
#include "NEAT.h"
|
||||||
|
|
||||||
|
static float Random()
|
||||||
|
{
|
||||||
|
return (float)rand() / (float)RAND_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
float RandomFloatRange(float min, float max)
|
||||||
|
{
|
||||||
|
if ( max < min )
|
||||||
|
{
|
||||||
|
std::swap(min,max);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Random() * (max - min)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
float RandomWeight()
|
||||||
|
{
|
||||||
|
return RandomFloatRange(-NEAT::kMaxNewWeight,NEAT::kMaxNewWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RandomBool()
|
||||||
|
{
|
||||||
|
return ((rand() % 2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float RandomPreturbation()
|
||||||
|
{
|
||||||
|
return RandomFloatRange(-NEAT::kMaxWeightPerturbation,NEAT::kMaxWeightPerturbation);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RandomRange(int min, int max)
|
||||||
|
{
|
||||||
|
return (rand() % (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RandomChance(float pSuccess)
|
||||||
|
{
|
||||||
|
return Random() <= pSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RandomZeroBiased(int max)
|
||||||
|
{
|
||||||
|
float fmin = (float)-max;
|
||||||
|
float fmax = (float)max;
|
||||||
|
float fsum = 0.0f;
|
||||||
|
|
||||||
|
for (int i=0;i<6;++i)
|
||||||
|
{
|
||||||
|
fsum += RandomFloatRange(fmin,fmax);
|
||||||
|
}
|
||||||
|
if ( fsum < 0.0f )
|
||||||
|
{
|
||||||
|
fsum = -fsum;
|
||||||
|
}
|
||||||
|
return (int)(fsum / 6.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Roulette(int n, ...)
|
||||||
|
{
|
||||||
|
// store the arguments so we can use them more easily
|
||||||
|
va_list args;
|
||||||
|
va_start(args,n);
|
||||||
|
std::vector<float> weights;
|
||||||
|
iterate_times(n)
|
||||||
|
{
|
||||||
|
weights.push_back((float)va_arg(args,double));
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// sum them
|
||||||
|
float sum = 0.0;
|
||||||
|
iterate_each(std::vector<float>::iterator, it, weights)
|
||||||
|
{
|
||||||
|
sum += (*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// roll the dice
|
||||||
|
float roll = RandomFloatRange(0.0f, sum);
|
||||||
|
|
||||||
|
// see where it falls
|
||||||
|
sum = 0.0f;
|
||||||
|
for( unsigned int i = 0; i < weights.size(); ++i )
|
||||||
|
{
|
||||||
|
sum += weights[i];
|
||||||
|
if ( roll <= sum )
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// failure, should not get here!
|
||||||
|
assert(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __Random_h__
|
||||||
|
#define __Random_h__
|
||||||
|
|
||||||
|
int RandomRange(int min, int max); // [min,max]
|
||||||
|
float RandomFloatRange(float min, float max);
|
||||||
|
float RandomWeight();
|
||||||
|
float RandomPreturbation();
|
||||||
|
bool RandomBool();
|
||||||
|
bool RandomChance(float pSuccess);
|
||||||
|
int RandomZeroBiased(int max);
|
||||||
|
int Roulette(int n, ...);
|
||||||
|
|
||||||
|
#endif // __Random_h__
|
||||||
|
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
#include "Species.h"
|
||||||
|
|
||||||
|
#include "IteratorHelper.h"
|
||||||
|
#include "Random.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
Species::Species(const Genotype& leader):
|
||||||
|
m_leader(leader)
|
||||||
|
{
|
||||||
|
m_members.push_back(m_leader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Species::Reset()
|
||||||
|
{
|
||||||
|
m_members.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Species::AddMember(const Genotype& genome)
|
||||||
|
{
|
||||||
|
m_members.push_back(genome);
|
||||||
|
if ( genome < m_leader )
|
||||||
|
{
|
||||||
|
m_leader = genome;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Species::AddIfCompatible(const Genotype& genome)
|
||||||
|
{
|
||||||
|
if ( m_leader.GetCompatibility(genome) < 3.0f )
|
||||||
|
{
|
||||||
|
// yes, it's compatible, add it to this species
|
||||||
|
AddMember(genome);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default case, not added
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Species::AdjustFitness()
|
||||||
|
{
|
||||||
|
float total_members = (float)m_members.size();
|
||||||
|
iterate_each( std::vector<Genotype>::iterator, it, m_members )
|
||||||
|
{
|
||||||
|
(*it).SetFitness( (*it).GetFitness() / total_members );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float Species::GetFitness()
|
||||||
|
{
|
||||||
|
float total = 0.0f;
|
||||||
|
iterate_each( std::vector<Genotype>::iterator, it, m_members )
|
||||||
|
{
|
||||||
|
total += (*it).GetFitness();
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
Genotype Species::Spawn() const
|
||||||
|
{
|
||||||
|
int a = RandomRange(0,(int)m_members.size()-1);
|
||||||
|
int b = RandomRange(0,(int)m_members.size()-1);
|
||||||
|
return Genotype(m_members[a],m_members[b]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Genotype Species::GetLeader() const
|
||||||
|
{
|
||||||
|
return m_leader;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef __Species_h__
|
||||||
|
#define __Species_h__
|
||||||
|
|
||||||
|
#include "Genotype.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
class Species
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Species(const Genotype& leader);
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
void AddMember(const Genotype& genome);
|
||||||
|
bool AddIfCompatible(const Genotype& genome);
|
||||||
|
void AdjustFitness();
|
||||||
|
float GetFitness();
|
||||||
|
|
||||||
|
Genotype Spawn() const;
|
||||||
|
Genotype GetLeader() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genotype m_leader;
|
||||||
|
std::vector<Genotype> m_members;
|
||||||
|
float m_spawn_amount;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __Species_h__
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
* create NEAT parameters
|
||||||
|
* make sure all NEAT parameters are very strictly adhered to (through evolutionary process)
|
||||||
|
* use dynamic speciation compatibility constant
|
||||||
|
* make all parameters match (i.e. innovation_id's, or neurons)
|
||||||
|
it's confusing that we have the innovation number, genotype index, and Gene itself
|
||||||
|
* consider getting innovator to construct new Genes
|
||||||
|
* make all files formatted similarly
|
||||||
|
* clean up Random setup
|
||||||
|
* profile, optimize
|
||||||
|
* find all TODO's
|
||||||
|
* output dot files
|
||||||
|
* NEAT save/restore state
|
||||||
|
* network save/restore
|
||||||
|
* separate out network code
|
||||||
|
* make sure innovation numbers aren't overflowing
|
||||||
|
* make innovation numbers generation-specific
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
# BFS method
|
||||||
|
def ao_bfs(net, cur_layer, seen=nil, order=nil)
|
||||||
|
# setup some state for this recursion
|
||||||
|
seen ||= Hash.new
|
||||||
|
order ||= Array.new
|
||||||
|
|
||||||
|
# mark current nodes as seen
|
||||||
|
cur_layer.each { |n| seen[n] = true }
|
||||||
|
|
||||||
|
# prepend current layer to final order
|
||||||
|
order = [cur_layer.sort] + order
|
||||||
|
|
||||||
|
# get next layer
|
||||||
|
next_layer = cur_layer.collect { |n| net[n] }
|
||||||
|
next_layer = next_layer.flatten.select { |n| not seen[n] }
|
||||||
|
|
||||||
|
if not next_layer.empty?
|
||||||
|
# recurse into next layer if it exists
|
||||||
|
ao_bfs(net, next_layer, seen, order)
|
||||||
|
else
|
||||||
|
# finished
|
||||||
|
order
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# network format is a reverse digraph, so if node 0 feeds into node 1, you'd have 1 => [0]
|
||||||
|
# ... in other words, node 1 directly depends upon node 0
|
||||||
|
|
||||||
|
# 0,1,2 = inputs; 7,8,9 = outputs
|
||||||
|
net = { 0 => [], 1 => [4], 2 => [], 3 => [0,4,5], 4 => [2,6], 5 => [1], 6 => [5], 7 => [3], 8 => [5], 9 => [6] }
|
||||||
|
|
||||||
|
# call ao_bfs with output layer (or last layer)
|
||||||
|
puts ao_bfs(net, [7,8,9]).inspect
|
||||||
|
|
||||||
|
|
||||||
|
# DFS method
|
||||||
|
# use DFS to find terminal nodes
|
||||||
|
# as each terminal node is encountered, push it on the end of the order
|
||||||
|
# and as each node becomes terminal node (i.e. all leaves explored), push it on
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "NEAT.h"
|
||||||
|
|
||||||
|
#include "IteratorHelper.h"
|
||||||
|
|
||||||
|
class MyNEAT: public NEAT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyNEAT(int num_inputs, int num_outputs) : NEAT(num_inputs,num_outputs)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool TestNetworks(std::vector<NeuralNetwork>& networks, std::vector<float>& fitness)
|
||||||
|
{
|
||||||
|
bool solution_found = false;
|
||||||
|
iterate_each( std::vector<NeuralNetwork>::iterator, it_network, networks )
|
||||||
|
{
|
||||||
|
std::vector<float> inputs;
|
||||||
|
std::vector<float> outputs;
|
||||||
|
float error_sum = 0.0f;
|
||||||
|
float error;
|
||||||
|
int hits = 0;
|
||||||
|
|
||||||
|
#define ON (1.0f)
|
||||||
|
#define OFF (0.0f)
|
||||||
|
|
||||||
|
// 0, 0 = 0
|
||||||
|
inputs.push_back(OFF);
|
||||||
|
inputs.push_back(OFF);
|
||||||
|
(*it_network).Reset();
|
||||||
|
(*it_network).Update(inputs,outputs);
|
||||||
|
error = outputs[0] - OFF;
|
||||||
|
error_sum += error * error;
|
||||||
|
if ( outputs[0] < 0.44f )
|
||||||
|
{
|
||||||
|
++hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0, 1 = 1
|
||||||
|
inputs.clear();
|
||||||
|
inputs.push_back(OFF);
|
||||||
|
inputs.push_back(ON);
|
||||||
|
(*it_network).Reset();
|
||||||
|
(*it_network).Update(inputs,outputs);
|
||||||
|
error = outputs[0] - ON;
|
||||||
|
error_sum += error * error;
|
||||||
|
if ( outputs[0] > 0.6f )
|
||||||
|
{
|
||||||
|
++hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1, 0 = 1
|
||||||
|
inputs.clear();
|
||||||
|
inputs.push_back(ON);
|
||||||
|
inputs.push_back(OFF);
|
||||||
|
(*it_network).Reset();
|
||||||
|
(*it_network).Update(inputs,outputs);
|
||||||
|
error = outputs[0] - ON;
|
||||||
|
error_sum += error * error;
|
||||||
|
if ( outputs[0] > 0.6f )
|
||||||
|
{
|
||||||
|
++hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1, 1 = 0
|
||||||
|
inputs.clear();
|
||||||
|
inputs.push_back(ON);
|
||||||
|
inputs.push_back(ON);
|
||||||
|
(*it_network).Reset();
|
||||||
|
(*it_network).Update(inputs,outputs);
|
||||||
|
error = outputs[0] - OFF;
|
||||||
|
error_sum += error * error;
|
||||||
|
if ( outputs[0] < 0.5f )
|
||||||
|
{
|
||||||
|
++hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// average
|
||||||
|
error_sum /= 4.0f;
|
||||||
|
|
||||||
|
// store
|
||||||
|
fitness.push_back(error_sum);
|
||||||
|
//printf("error = %0.5f\n",error_sum);
|
||||||
|
|
||||||
|
// did we solve it?
|
||||||
|
if ( hits == 4 )
|
||||||
|
{
|
||||||
|
solution_found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//printf("\n");
|
||||||
|
return solution_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int main (int argc, char * const argv[])
|
||||||
|
{
|
||||||
|
MyNEAT n(2,1);
|
||||||
|
|
||||||
|
srand( (unsigned)time( NULL ) );
|
||||||
|
|
||||||
|
n.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
|
||||||
|
.\"See Also:
|
||||||
|
.\"man mdoc.samples for a complete listing of options
|
||||||
|
.\"man mdoc for the short list of editing options
|
||||||
|
.\"/usr/share/misc/mdoc.template
|
||||||
|
.Dd 12/6/06 \" DATE
|
||||||
|
.Dt neat 1 \" Program name and manual section number
|
||||||
|
.Os Darwin
|
||||||
|
.Sh NAME \" Section Header - required - don't modify
|
||||||
|
.Nm neat,
|
||||||
|
.\" The following lines are read in generating the apropos(man -k) database. Use only key
|
||||||
|
.\" words here as the database is built based on the words here and in the .ND line.
|
||||||
|
.Nm Other_name_for_same_program(),
|
||||||
|
.Nm Yet another name for the same program.
|
||||||
|
.\" Use .Nm macro to designate other names for the documented program.
|
||||||
|
.Nd This line parsed for whatis database.
|
||||||
|
.Sh SYNOPSIS \" Section Header - required - don't modify
|
||||||
|
.Nm
|
||||||
|
.Op Fl abcd \" [-abcd]
|
||||||
|
.Op Fl a Ar path \" [-a path]
|
||||||
|
.Op Ar file \" [file]
|
||||||
|
.Op Ar \" [file ...]
|
||||||
|
.Ar arg0 \" Underlined argument - use .Ar anywhere to underline
|
||||||
|
arg2 ... \" Arguments
|
||||||
|
.Sh DESCRIPTION \" Section Header - required - don't modify
|
||||||
|
Use the .Nm macro to refer to your program throughout the man page like such:
|
||||||
|
.Nm
|
||||||
|
Underlining is accomplished with the .Ar macro like this:
|
||||||
|
.Ar underlined text .
|
||||||
|
.Pp \" Inserts a space
|
||||||
|
A list of items with descriptions:
|
||||||
|
.Bl -tag -width -indent \" Begins a tagged list
|
||||||
|
.It item a \" Each item preceded by .It macro
|
||||||
|
Description of item a
|
||||||
|
.It item b
|
||||||
|
Description of item b
|
||||||
|
.El \" Ends the list
|
||||||
|
.Pp
|
||||||
|
A list of flags and their descriptions:
|
||||||
|
.Bl -tag -width -indent \" Differs from above in tag removed
|
||||||
|
.It Fl a \"-a flag as a list item
|
||||||
|
Description of -a flag
|
||||||
|
.It Fl b
|
||||||
|
Description of -b flag
|
||||||
|
.El \" Ends the list
|
||||||
|
.Pp
|
||||||
|
.\" .Sh ENVIRONMENT \" May not be needed
|
||||||
|
.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
|
||||||
|
.\" .It Ev ENV_VAR_1
|
||||||
|
.\" Description of ENV_VAR_1
|
||||||
|
.\" .It Ev ENV_VAR_2
|
||||||
|
.\" Description of ENV_VAR_2
|
||||||
|
.\" .El
|
||||||
|
.Sh FILES \" File used or created by the topic of the man page
|
||||||
|
.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
|
||||||
|
.It Pa /usr/share/file_name
|
||||||
|
FILE_1 description
|
||||||
|
.It Pa /Users/joeuser/Library/really_long_file_name
|
||||||
|
FILE_2 description
|
||||||
|
.El \" Ends the list
|
||||||
|
.\" .Sh DIAGNOSTICS \" May not be needed
|
||||||
|
.\" .Bl -diag
|
||||||
|
.\" .It Diagnostic Tag
|
||||||
|
.\" Diagnostic informtion here.
|
||||||
|
.\" .It Diagnostic Tag
|
||||||
|
.\" Diagnostic informtion here.
|
||||||
|
.\" .El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.\" List links in ascending order by section, alphabetically within a section.
|
||||||
|
.\" Please do not reference files that do not exist without filing a bug report
|
||||||
|
.Xr a 1 ,
|
||||||
|
.Xr b 1 ,
|
||||||
|
.Xr c 1 ,
|
||||||
|
.Xr a 2 ,
|
||||||
|
.Xr b 2 ,
|
||||||
|
.Xr a 3 ,
|
||||||
|
.Xr b 3
|
||||||
|
.\" .Sh BUGS \" Document known, unremedied bugs
|
||||||
|
.\" .Sh HISTORY \" Document history if command behaves in a unique manner
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "neat", "neat.vcproj", "{298877D3-11B7-4924-84B4-94F9EA83EDA0}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfiguration) = preSolution
|
||||||
|
Debug = Debug
|
||||||
|
Release = Release
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfiguration) = postSolution
|
||||||
|
{298877D3-11B7-4924-84B4-94F9EA83EDA0}.Debug.ActiveCfg = Debug|Win32
|
||||||
|
{298877D3-11B7-4924-84B4-94F9EA83EDA0}.Debug.Build.0 = Debug|Win32
|
||||||
|
{298877D3-11B7-4924-84B4-94F9EA83EDA0}.Release.ActiveCfg = Release|Win32
|
||||||
|
{298877D3-11B7-4924-84B4-94F9EA83EDA0}.Release.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>documents</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>children</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>children</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>BiasNeuron.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>BiasNeuron.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>ConnectionGene.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>ConnectionGene.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Gene.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Gene.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Genotype.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Genotype.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Innovation.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Innovation.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>InputNeuron.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>InputNeuron.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>NEAT.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>NEAT.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>NeuralNetwork.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>NeuralNetwork.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Neuron.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>Neuron.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>NeuronGene.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>NeuronGene.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>SigmoidNeuron.cpp</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>SigmoidNeuron.h</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>main.cpp</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>expanded</key>
|
||||||
|
<true/>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Source</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>children</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>neat.1</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>expanded</key>
|
||||||
|
<true/>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Documentation</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>children</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>filename</key>
|
||||||
|
<string>neat</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>expanded</key>
|
||||||
|
<true/>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Products</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>expanded</key>
|
||||||
|
<true/>
|
||||||
|
<key>name</key>
|
||||||
|
<string>neat</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>fileHierarchyDrawerWidth</key>
|
||||||
|
<integer>200</integer>
|
||||||
|
<key>metaData</key>
|
||||||
|
<dict/>
|
||||||
|
<key>showFileHierarchyDrawer</key>
|
||||||
|
<true/>
|
||||||
|
<key>windowFrame</key>
|
||||||
|
<string>{{142, 116}, {851, 661}}</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
+210
@@ -0,0 +1,210 @@
|
|||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="7.10"
|
||||||
|
Name="neat"
|
||||||
|
ProjectGUID="{298877D3-11B7-4924-84B4-94F9EA83EDA0}"
|
||||||
|
Keyword="Win32Proj">
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"/>
|
||||||
|
</Platforms>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="Debug"
|
||||||
|
IntermediateDirectory="Debug"
|
||||||
|
ConfigurationType="1"
|
||||||
|
CharacterSet="2">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||||
|
MinimalRebuild="TRUE"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="5"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
|
DebugInformationFormat="4"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
OutputFile="$(OutDir)/neat.exe"
|
||||||
|
LinkIncremental="2"
|
||||||
|
GenerateDebugInformation="TRUE"
|
||||||
|
ProgramDatabaseFile="$(OutDir)/neat.pdb"
|
||||||
|
SubSystem="1"
|
||||||
|
TargetMachine="1"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebDeploymentTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedWrapperGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="Release"
|
||||||
|
IntermediateDirectory="Release"
|
||||||
|
ConfigurationType="1"
|
||||||
|
CharacterSet="2">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||||
|
RuntimeLibrary="4"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="TRUE"
|
||||||
|
DebugInformationFormat="3"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
OutputFile="$(OutDir)/neat.exe"
|
||||||
|
LinkIncremental="1"
|
||||||
|
GenerateDebugInformation="TRUE"
|
||||||
|
SubSystem="1"
|
||||||
|
OptimizeReferences="2"
|
||||||
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebDeploymentTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedWrapperGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<File
|
||||||
|
RelativePath=".\BiasNeuron.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\BiasNeuron.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\ConnectionGene.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\ConnectionGene.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Gene.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Gene.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Genotype.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Genotype.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Innovation.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Innovation.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Innovator.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Innovator.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="InputNeuron.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="InputNeuron.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\IteratorHelper.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\main.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\MathHelper.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\NEAT.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\NEAT.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="NeuralNetwork.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="NeuralNetwork.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Neuron.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Neuron.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\NeuronGene.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\NeuronGene.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Random.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Random.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="SigmoidNeuron.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="SigmoidNeuron.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Species.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Species.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\TODO.txt">
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
||||||
@@ -0,0 +1,282 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 42;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
8DD76F650486A84900D96B5E /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* main.cpp */; settings = {ATTRIBUTES = (); }; };
|
||||||
|
8DD76F6A0486A84900D96B5E /* neat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859E8B029090EE04C91782 /* neat.1 */; };
|
||||||
|
C11C1D2F0B27CD8C00979D81 /* ConnectionGene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C11C1D190B27CD8C00979D81 /* ConnectionGene.cpp */; };
|
||||||
|
C11C1D300B27CD8C00979D81 /* ConnectionGene.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C11C1D1A0B27CD8C00979D81 /* ConnectionGene.h */; };
|
||||||
|
C11C1D310B27CD8C00979D81 /* Gene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C11C1D1B0B27CD8C00979D81 /* Gene.cpp */; };
|
||||||
|
C11C1D320B27CD8C00979D81 /* Gene.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C11C1D1C0B27CD8C00979D81 /* Gene.h */; };
|
||||||
|
C11C1D330B27CD8C00979D81 /* Genotype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C11C1D1D0B27CD8C00979D81 /* Genotype.cpp */; };
|
||||||
|
C11C1D340B27CD8C00979D81 /* Genotype.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C11C1D1E0B27CD8C00979D81 /* Genotype.h */; };
|
||||||
|
C11C1D350B27CD8C00979D81 /* Innovation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C11C1D1F0B27CD8C00979D81 /* Innovation.cpp */; };
|
||||||
|
C11C1D360B27CD8C00979D81 /* Innovation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C11C1D200B27CD8C00979D81 /* Innovation.h */; };
|
||||||
|
C11C1D390B27CD8C00979D81 /* NEAT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C11C1D230B27CD8C00979D81 /* NEAT.cpp */; };
|
||||||
|
C11C1D3A0B27CD8C00979D81 /* NEAT.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C11C1D240B27CD8C00979D81 /* NEAT.h */; };
|
||||||
|
C11C1D3B0B27CD8C00979D81 /* NeuralNetwork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C11C1D250B27CD8C00979D81 /* NeuralNetwork.cpp */; };
|
||||||
|
C11C1D3C0B27CD8C00979D81 /* NeuralNetwork.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C11C1D260B27CD8C00979D81 /* NeuralNetwork.h */; };
|
||||||
|
C11C1D3F0B27CD8C00979D81 /* NeuronGene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C11C1D290B27CD8C00979D81 /* NeuronGene.cpp */; };
|
||||||
|
C11C1D400B27CD8C00979D81 /* NeuronGene.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C11C1D2A0B27CD8C00979D81 /* NeuronGene.h */; };
|
||||||
|
C1230D060B7466E9005F79C9 /* Species.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C1230D040B7466E9005F79C9 /* Species.cpp */; };
|
||||||
|
C1230D070B7466E9005F79C9 /* Species.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C1230D050B7466E9005F79C9 /* Species.h */; };
|
||||||
|
C18013F00B2E60C500943E57 /* Innovator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C18013EC0B2E60C500943E57 /* Innovator.cpp */; };
|
||||||
|
C18013F10B2E60C500943E57 /* Innovator.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C18013ED0B2E60C500943E57 /* Innovator.h */; };
|
||||||
|
C18013F20B2E60C500943E57 /* Random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C18013EE0B2E60C500943E57 /* Random.cpp */; };
|
||||||
|
C18013F30B2E60C500943E57 /* Random.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C18013EF0B2E60C500943E57 /* Random.h */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
8DD76F690486A84900D96B5E /* CopyFiles */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 8;
|
||||||
|
dstPath = /usr/share/man/man1/;
|
||||||
|
dstSubfolderSpec = 0;
|
||||||
|
files = (
|
||||||
|
8DD76F6A0486A84900D96B5E /* neat.1 in CopyFiles */,
|
||||||
|
C11C1D300B27CD8C00979D81 /* ConnectionGene.h in CopyFiles */,
|
||||||
|
C11C1D320B27CD8C00979D81 /* Gene.h in CopyFiles */,
|
||||||
|
C11C1D340B27CD8C00979D81 /* Genotype.h in CopyFiles */,
|
||||||
|
C11C1D360B27CD8C00979D81 /* Innovation.h in CopyFiles */,
|
||||||
|
C11C1D3A0B27CD8C00979D81 /* NEAT.h in CopyFiles */,
|
||||||
|
C11C1D3C0B27CD8C00979D81 /* NeuralNetwork.h in CopyFiles */,
|
||||||
|
C11C1D400B27CD8C00979D81 /* NeuronGene.h in CopyFiles */,
|
||||||
|
C18013F10B2E60C500943E57 /* Innovator.h in CopyFiles */,
|
||||||
|
C18013F30B2E60C500943E57 /* Random.h in CopyFiles */,
|
||||||
|
C1230D070B7466E9005F79C9 /* Species.h in CopyFiles */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 1;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
08FB7796FE84155DC02AAC07 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
|
||||||
|
8DD76F6C0486A84900D96B5E /* neat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = neat; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
C11C1D190B27CD8C00979D81 /* ConnectionGene.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ConnectionGene.cpp; sourceTree = "<group>"; };
|
||||||
|
C11C1D1A0B27CD8C00979D81 /* ConnectionGene.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ConnectionGene.h; sourceTree = "<group>"; };
|
||||||
|
C11C1D1B0B27CD8C00979D81 /* Gene.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Gene.cpp; sourceTree = "<group>"; };
|
||||||
|
C11C1D1C0B27CD8C00979D81 /* Gene.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Gene.h; sourceTree = "<group>"; };
|
||||||
|
C11C1D1D0B27CD8C00979D81 /* Genotype.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Genotype.cpp; sourceTree = "<group>"; };
|
||||||
|
C11C1D1E0B27CD8C00979D81 /* Genotype.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Genotype.h; sourceTree = "<group>"; };
|
||||||
|
C11C1D1F0B27CD8C00979D81 /* Innovation.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Innovation.cpp; sourceTree = "<group>"; };
|
||||||
|
C11C1D200B27CD8C00979D81 /* Innovation.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Innovation.h; sourceTree = "<group>"; };
|
||||||
|
C11C1D230B27CD8C00979D81 /* NEAT.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = NEAT.cpp; sourceTree = "<group>"; };
|
||||||
|
C11C1D240B27CD8C00979D81 /* NEAT.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NEAT.h; sourceTree = "<group>"; };
|
||||||
|
C11C1D250B27CD8C00979D81 /* NeuralNetwork.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = NeuralNetwork.cpp; sourceTree = "<group>"; };
|
||||||
|
C11C1D260B27CD8C00979D81 /* NeuralNetwork.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NeuralNetwork.h; sourceTree = "<group>"; };
|
||||||
|
C11C1D290B27CD8C00979D81 /* NeuronGene.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = NeuronGene.cpp; sourceTree = "<group>"; };
|
||||||
|
C11C1D2A0B27CD8C00979D81 /* NeuronGene.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NeuronGene.h; sourceTree = "<group>"; };
|
||||||
|
C1230D040B7466E9005F79C9 /* Species.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Species.cpp; sourceTree = "<group>"; };
|
||||||
|
C1230D050B7466E9005F79C9 /* Species.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Species.h; sourceTree = "<group>"; };
|
||||||
|
C18013EC0B2E60C500943E57 /* Innovator.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Innovator.cpp; sourceTree = "<group>"; };
|
||||||
|
C18013ED0B2E60C500943E57 /* Innovator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Innovator.h; sourceTree = "<group>"; };
|
||||||
|
C18013EE0B2E60C500943E57 /* Random.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Random.cpp; sourceTree = "<group>"; };
|
||||||
|
C18013EF0B2E60C500943E57 /* Random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Random.h; sourceTree = "<group>"; };
|
||||||
|
C6859E8B029090EE04C91782 /* neat.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = neat.1; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
8DD76F660486A84900D96B5E /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
08FB7794FE84155DC02AAC07 /* neat */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
08FB7795FE84155DC02AAC07 /* Source */,
|
||||||
|
C6859E8C029090F304C91782 /* Documentation */,
|
||||||
|
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||||
|
);
|
||||||
|
name = neat;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
08FB7795FE84155DC02AAC07 /* Source */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C1230D040B7466E9005F79C9 /* Species.cpp */,
|
||||||
|
C1230D050B7466E9005F79C9 /* Species.h */,
|
||||||
|
C18013EC0B2E60C500943E57 /* Innovator.cpp */,
|
||||||
|
C18013ED0B2E60C500943E57 /* Innovator.h */,
|
||||||
|
C18013EE0B2E60C500943E57 /* Random.cpp */,
|
||||||
|
C18013EF0B2E60C500943E57 /* Random.h */,
|
||||||
|
C11C1D190B27CD8C00979D81 /* ConnectionGene.cpp */,
|
||||||
|
C11C1D1A0B27CD8C00979D81 /* ConnectionGene.h */,
|
||||||
|
C11C1D1B0B27CD8C00979D81 /* Gene.cpp */,
|
||||||
|
C11C1D1C0B27CD8C00979D81 /* Gene.h */,
|
||||||
|
C11C1D1D0B27CD8C00979D81 /* Genotype.cpp */,
|
||||||
|
C11C1D1E0B27CD8C00979D81 /* Genotype.h */,
|
||||||
|
C11C1D1F0B27CD8C00979D81 /* Innovation.cpp */,
|
||||||
|
C11C1D200B27CD8C00979D81 /* Innovation.h */,
|
||||||
|
C11C1D230B27CD8C00979D81 /* NEAT.cpp */,
|
||||||
|
C11C1D240B27CD8C00979D81 /* NEAT.h */,
|
||||||
|
C11C1D250B27CD8C00979D81 /* NeuralNetwork.cpp */,
|
||||||
|
C11C1D260B27CD8C00979D81 /* NeuralNetwork.h */,
|
||||||
|
C11C1D290B27CD8C00979D81 /* NeuronGene.cpp */,
|
||||||
|
C11C1D2A0B27CD8C00979D81 /* NeuronGene.h */,
|
||||||
|
08FB7796FE84155DC02AAC07 /* main.cpp */,
|
||||||
|
);
|
||||||
|
name = Source;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
1AB674ADFE9D54B511CA2CBB /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
8DD76F6C0486A84900D96B5E /* neat */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
C6859E8C029090F304C91782 /* Documentation */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C6859E8B029090EE04C91782 /* neat.1 */,
|
||||||
|
);
|
||||||
|
name = Documentation;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
8DD76F620486A84900D96B5E /* neat */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "neat" */;
|
||||||
|
buildPhases = (
|
||||||
|
8DD76F640486A84900D96B5E /* Sources */,
|
||||||
|
8DD76F660486A84900D96B5E /* Frameworks */,
|
||||||
|
8DD76F690486A84900D96B5E /* CopyFiles */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = neat;
|
||||||
|
productInstallPath = "$(HOME)/bin";
|
||||||
|
productName = neat;
|
||||||
|
productReference = 8DD76F6C0486A84900D96B5E /* neat */;
|
||||||
|
productType = "com.apple.product-type.tool";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "neat" */;
|
||||||
|
hasScannedForEncodings = 1;
|
||||||
|
mainGroup = 08FB7794FE84155DC02AAC07 /* neat */;
|
||||||
|
projectDirPath = "";
|
||||||
|
targets = (
|
||||||
|
8DD76F620486A84900D96B5E /* neat */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
8DD76F640486A84900D96B5E /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
8DD76F650486A84900D96B5E /* main.cpp in Sources */,
|
||||||
|
C11C1D2F0B27CD8C00979D81 /* ConnectionGene.cpp in Sources */,
|
||||||
|
C11C1D310B27CD8C00979D81 /* Gene.cpp in Sources */,
|
||||||
|
C11C1D330B27CD8C00979D81 /* Genotype.cpp in Sources */,
|
||||||
|
C11C1D350B27CD8C00979D81 /* Innovation.cpp in Sources */,
|
||||||
|
C11C1D390B27CD8C00979D81 /* NEAT.cpp in Sources */,
|
||||||
|
C11C1D3B0B27CD8C00979D81 /* NeuralNetwork.cpp in Sources */,
|
||||||
|
C11C1D3F0B27CD8C00979D81 /* NeuronGene.cpp in Sources */,
|
||||||
|
C18013F00B2E60C500943E57 /* Innovator.cpp in Sources */,
|
||||||
|
C18013F20B2E60C500943E57 /* Random.cpp in Sources */,
|
||||||
|
C1230D060B7466E9005F79C9 /* Species.cpp in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
1DEB923208733DC60010E9CD /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||||
|
GCC_MODEL_TUNING = G5;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
INSTALL_PATH = "$(HOME)/bin";
|
||||||
|
PRODUCT_NAME = neat;
|
||||||
|
ZERO_LINK = YES;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
1DEB923308733DC60010E9CD /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ARCHS = (
|
||||||
|
ppc,
|
||||||
|
i386,
|
||||||
|
);
|
||||||
|
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||||
|
GCC_MODEL_TUNING = G5;
|
||||||
|
INSTALL_PATH = "$(HOME)/bin";
|
||||||
|
PRODUCT_NAME = neat;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
1DEB923608733DC60010E9CD /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
|
GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
|
||||||
|
GCC_WARN_PEDANTIC = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
PREBINDING = NO;
|
||||||
|
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
1DEB923708733DC60010E9CD /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
|
GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
|
||||||
|
GCC_WARN_PEDANTIC = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
PREBINDING = NO;
|
||||||
|
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "neat" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
1DEB923208733DC60010E9CD /* Debug */,
|
||||||
|
1DEB923308733DC60010E9CD /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "neat" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
1DEB923608733DC60010E9CD /* Debug */,
|
||||||
|
1DEB923708733DC60010E9CD /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,308 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||||
|
activeBuildConfigurationName = Debug;
|
||||||
|
activeExecutable = C11C1D110B27CD4E00979D81 /* neat */;
|
||||||
|
activeTarget = 8DD76F620486A84900D96B5E /* neat */;
|
||||||
|
addToTargets = (
|
||||||
|
8DD76F620486A84900D96B5E /* neat */,
|
||||||
|
);
|
||||||
|
breakpoints = (
|
||||||
|
C123DD060B79A5CC00FB4F9C /* Roulette */,
|
||||||
|
);
|
||||||
|
breakpointsGroup = C187705C0B27D8F70060D99F /* XCBreakpointsBucket */;
|
||||||
|
codeSenseManager = C11C1D160B27CD6D00979D81 /* Code sense */;
|
||||||
|
executables = (
|
||||||
|
C11C1D110B27CD4E00979D81 /* neat */,
|
||||||
|
);
|
||||||
|
perUserDictionary = {
|
||||||
|
"PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = {
|
||||||
|
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||||
|
PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID;
|
||||||
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
210,
|
||||||
|
20,
|
||||||
|
110,
|
||||||
|
109,
|
||||||
|
20,
|
||||||
|
);
|
||||||
|
PBXFileTableDataSourceColumnsKey = (
|
||||||
|
PBXBreakpointsDataSource_ActionID,
|
||||||
|
PBXBreakpointsDataSource_TypeID,
|
||||||
|
PBXBreakpointsDataSource_BreakpointID,
|
||||||
|
PBXBreakpointsDataSource_UseID,
|
||||||
|
PBXBreakpointsDataSource_LocationID,
|
||||||
|
PBXBreakpointsDataSource_ConditionID,
|
||||||
|
PBXBreakpointsDataSource_ContinueID,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
"PBXConfiguration.PBXBreakpointsDataSource.v1:1CE0B20506471E060097A5F4" = {
|
||||||
|
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||||
|
PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID;
|
||||||
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
227,
|
||||||
|
20,
|
||||||
|
127,
|
||||||
|
126,
|
||||||
|
20,
|
||||||
|
);
|
||||||
|
PBXFileTableDataSourceColumnsKey = (
|
||||||
|
PBXBreakpointsDataSource_ActionID,
|
||||||
|
PBXBreakpointsDataSource_TypeID,
|
||||||
|
PBXBreakpointsDataSource_BreakpointID,
|
||||||
|
PBXBreakpointsDataSource_UseID,
|
||||||
|
PBXBreakpointsDataSource_LocationID,
|
||||||
|
PBXBreakpointsDataSource_ConditionID,
|
||||||
|
PBXBreakpointsDataSource_ContinueID,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
PBXConfiguration.PBXFileTableDataSource3.PBXErrorsWarningsDataSource = {
|
||||||
|
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||||
|
PBXFileTableDataSourceColumnSortingKey = PBXErrorsWarningsDataSource_LocationID;
|
||||||
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
|
20,
|
||||||
|
433,
|
||||||
|
200,
|
||||||
|
);
|
||||||
|
PBXFileTableDataSourceColumnsKey = (
|
||||||
|
PBXErrorsWarningsDataSource_TypeID,
|
||||||
|
PBXErrorsWarningsDataSource_MessageID,
|
||||||
|
PBXErrorsWarningsDataSource_LocationID,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
|
||||||
|
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||||
|
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
||||||
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
|
20,
|
||||||
|
342,
|
||||||
|
20,
|
||||||
|
48,
|
||||||
|
43,
|
||||||
|
43,
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
);
|
||||||
|
PBXFileTableDataSourceColumnsKey = (
|
||||||
|
PBXFileDataSource_FiletypeID,
|
||||||
|
PBXFileDataSource_Filename_ColumnID,
|
||||||
|
PBXFileDataSource_Built_ColumnID,
|
||||||
|
PBXFileDataSource_ObjectSize_ColumnID,
|
||||||
|
PBXFileDataSource_Errors_ColumnID,
|
||||||
|
PBXFileDataSource_Warnings_ColumnID,
|
||||||
|
PBXFileDataSource_Target_ColumnID,
|
||||||
|
PBXFileDataSource_SCM_ColumnID,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
PBXConfiguration.PBXFileTableDataSource3.PBXSymbolsDataSource = {
|
||||||
|
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||||
|
PBXFileTableDataSourceColumnSortingKey = PBXSymbolsDataSource_SymbolNameID;
|
||||||
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
|
16,
|
||||||
|
200,
|
||||||
|
111,
|
||||||
|
245.2085,
|
||||||
|
);
|
||||||
|
PBXFileTableDataSourceColumnsKey = (
|
||||||
|
PBXSymbolsDataSource_SymbolTypeIconID,
|
||||||
|
PBXSymbolsDataSource_SymbolNameID,
|
||||||
|
PBXSymbolsDataSource_SymbolTypeID,
|
||||||
|
PBXSymbolsDataSource_ReferenceNameID,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
PBXConfiguration.PBXFileTableDataSource3.XCSCMDataSource = {
|
||||||
|
PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
|
||||||
|
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
|
||||||
|
PBXFileTableDataSourceColumnWidthsKey = (
|
||||||
|
20,
|
||||||
|
20,
|
||||||
|
342,
|
||||||
|
20,
|
||||||
|
48,
|
||||||
|
43,
|
||||||
|
43,
|
||||||
|
20,
|
||||||
|
);
|
||||||
|
PBXFileTableDataSourceColumnsKey = (
|
||||||
|
PBXFileDataSource_SCM_ColumnID,
|
||||||
|
PBXFileDataSource_FiletypeID,
|
||||||
|
PBXFileDataSource_Filename_ColumnID,
|
||||||
|
PBXFileDataSource_Built_ColumnID,
|
||||||
|
PBXFileDataSource_ObjectSize_ColumnID,
|
||||||
|
PBXFileDataSource_Errors_ColumnID,
|
||||||
|
PBXFileDataSource_Warnings_ColumnID,
|
||||||
|
PBXFileDataSource_Target_ColumnID,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
PBXPerProjectTemplateStateSaveDate = 192521644;
|
||||||
|
PBXWorkspaceStateSaveDate = 192521644;
|
||||||
|
};
|
||||||
|
sourceControlManager = C11C1D150B27CD6D00979D81 /* Source Control */;
|
||||||
|
userBuildSettings = {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
08FB7796FE84155DC02AAC07 /* main.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {584, 876}}";
|
||||||
|
sepNavSelRange = "{1444, 0}";
|
||||||
|
sepNavVisRect = "{{0, 199}, {545, 670}}";
|
||||||
|
sepNavWindowFrame = "{{73, 273}, {750, 558}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
8DD76F620486A84900D96B5E /* neat */ = {
|
||||||
|
activeExec = 0;
|
||||||
|
executables = (
|
||||||
|
C11C1D110B27CD4E00979D81 /* neat */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
C11C1D110B27CD4E00979D81 /* neat */ = {
|
||||||
|
isa = PBXExecutable;
|
||||||
|
activeArgIndex = 2147483647;
|
||||||
|
activeArgIndices = (
|
||||||
|
);
|
||||||
|
argumentStrings = (
|
||||||
|
);
|
||||||
|
autoAttachOnCrash = 1;
|
||||||
|
configStateDict = {
|
||||||
|
};
|
||||||
|
customDataFormattersEnabled = 1;
|
||||||
|
debuggerPlugin = GDBDebugging;
|
||||||
|
disassemblyDisplayState = 0;
|
||||||
|
dylibVariantSuffix = "";
|
||||||
|
enableDebugStr = 1;
|
||||||
|
environmentEntries = (
|
||||||
|
);
|
||||||
|
executableSystemSymbolLevel = 0;
|
||||||
|
executableUserSymbolLevel = 0;
|
||||||
|
libgmallocEnabled = 0;
|
||||||
|
name = neat;
|
||||||
|
savedGlobals = {
|
||||||
|
};
|
||||||
|
sourceDirectories = (
|
||||||
|
);
|
||||||
|
variableFormatDictionary = {
|
||||||
|
$mm0 = 1;
|
||||||
|
$mm1 = 1;
|
||||||
|
$mm2 = 1;
|
||||||
|
$mm3 = 1;
|
||||||
|
$mm4 = 1;
|
||||||
|
$mm5 = 1;
|
||||||
|
$mm6 = 1;
|
||||||
|
$mm7 = 1;
|
||||||
|
$mxcsr = 1;
|
||||||
|
$xmm0 = 1;
|
||||||
|
$xmm1 = 1;
|
||||||
|
$xmm2 = 1;
|
||||||
|
$xmm3 = 1;
|
||||||
|
$xmm4 = 1;
|
||||||
|
$xmm5 = 1;
|
||||||
|
$xmm6 = 1;
|
||||||
|
$xmm7 = 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C11C1D150B27CD6D00979D81 /* Source Control */ = {
|
||||||
|
isa = PBXSourceControlManager;
|
||||||
|
fallbackIsa = XCSourceControlManager;
|
||||||
|
isSCMEnabled = 1;
|
||||||
|
scmConfiguration = {
|
||||||
|
SubversionToolPath = /opt/local/bin/svn;
|
||||||
|
};
|
||||||
|
scmType = scm.subversion;
|
||||||
|
};
|
||||||
|
C11C1D160B27CD6D00979D81 /* Code sense */ = {
|
||||||
|
isa = PBXCodeSenseManager;
|
||||||
|
indexTemplatePath = "";
|
||||||
|
};
|
||||||
|
C11C1D190B27CD8C00979D81 /* ConnectionGene.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {704, 912}}";
|
||||||
|
sepNavSelRange = "{1080, 0}";
|
||||||
|
sepNavVisRect = "{{0, 242}, {704, 670}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C11C1D1B0B27CD8C00979D81 /* Gene.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {704, 670}}";
|
||||||
|
sepNavSelRange = "{221, 0}";
|
||||||
|
sepNavVisRect = "{{0, 0}, {704, 670}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C11C1D1D0B27CD8C00979D81 /* Genotype.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {993, 3684}}";
|
||||||
|
sepNavSelRange = "{6836, 0}";
|
||||||
|
sepNavVisRect = "{{0, 2835}, {993, 319}}";
|
||||||
|
sepNavWindowFrame = "{{130, 74}, {1040, 694}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C11C1D230B27CD8C00979D81 /* NEAT.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {993, 2916}}";
|
||||||
|
sepNavSelRange = "{1154, 0}";
|
||||||
|
sepNavVisRect = "{{0, 495}, {993, 319}}";
|
||||||
|
sepNavWindowFrame = "{{107, 95}, {1040, 694}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C1230D040B7466E9005F79C9 /* Species.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {545, 768}}";
|
||||||
|
sepNavSelRange = "{1010, 0}";
|
||||||
|
sepNavVisRect = "{{0, 98}, {545, 670}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C123DD060B79A5CC00FB4F9C /* Roulette */ = {
|
||||||
|
isa = PBXSymbolicBreakpoint;
|
||||||
|
actions = (
|
||||||
|
);
|
||||||
|
breakpointStyle = 1;
|
||||||
|
continueAfterActions = 0;
|
||||||
|
delayBeforeContinue = 0;
|
||||||
|
hitCount = 1;
|
||||||
|
location = Random.ob;
|
||||||
|
modificationTime = 192521771.390046;
|
||||||
|
state = 1;
|
||||||
|
symbolName = Roulette;
|
||||||
|
};
|
||||||
|
C18013EC0B2E60C500943E57 /* Innovator.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {827, 696}}";
|
||||||
|
sepNavSelRange = "{135, 0}";
|
||||||
|
sepNavVisRect = "{{0, 80}, {827, 305}}";
|
||||||
|
sepNavWindowFrame = "{{15, 179}, {1040, 694}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C18013ED0B2E60C500943E57 /* Innovator.h */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {827, 468}}";
|
||||||
|
sepNavSelRange = "{537, 0}";
|
||||||
|
sepNavVisRect = "{{0, 163}, {827, 305}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C18013EE0B2E60C500943E57 /* Random.cpp */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {827, 303}}";
|
||||||
|
sepNavSelRange = "{314, 0}";
|
||||||
|
sepNavVisRect = "{{0, 0}, {827, 303}}";
|
||||||
|
sepNavWindowFrame = "{{153, 53}, {1040, 694}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
C187705C0B27D8F70060D99F /* XCBreakpointsBucket */ = {
|
||||||
|
isa = XCBreakpointsBucket;
|
||||||
|
name = "Project Breakpoints";
|
||||||
|
objects = (
|
||||||
|
C123DD060B79A5CC00FB4F9C /* Roulette */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
C6859E8B029090EE04C91782 /* neat.1 */ = {
|
||||||
|
uiCtxt = {
|
||||||
|
sepNavIntBoundsRect = "{{0, 0}, {711, 1106}}";
|
||||||
|
sepNavSelRange = "{0, 0}";
|
||||||
|
sepNavVisRect = "{{0, 0}, {711, 429}}";
|
||||||
|
sepNavWindowFrame = "{{15, 315}, {750, 558}}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Executable
+142
@@ -0,0 +1,142 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require 'pp'
|
||||||
|
|
||||||
|
# a single neuron
|
||||||
|
class Node
|
||||||
|
attr_accessor :activation, :input_nodes
|
||||||
|
attr_reader :id
|
||||||
|
|
||||||
|
def initialize(id)
|
||||||
|
@id = id
|
||||||
|
@input_nodes = Array.new
|
||||||
|
@activation = 0.0
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
# activate unless this is an input node
|
||||||
|
@activation = activate(sum_input) unless /i[0-9]+/.match(@id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def <=>(other)
|
||||||
|
@id <=> other.id
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def sum_input
|
||||||
|
@input_nodes.inject(0.0) { |sum,node| sum + node.activation }
|
||||||
|
end
|
||||||
|
|
||||||
|
def activate(x)
|
||||||
|
Math.tanh(x)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# a basic ANN (assumes all weights are 1.0)
|
||||||
|
class Network
|
||||||
|
attr_accessor :nodes
|
||||||
|
|
||||||
|
def initialize(n_in, n_hidden, n_out)
|
||||||
|
@nodes = Hash.new
|
||||||
|
n_in.times { |i| @nodes["i#{i}"] = Node.new("i#{i}") }
|
||||||
|
n_hidden.times { |i| @nodes["h#{i}"] = Node.new("h#{i}") }
|
||||||
|
n_out.times { |i| @nodes["o#{i}"] = Node.new("o#{i}") }
|
||||||
|
end
|
||||||
|
|
||||||
|
def connect(from_id, to_id)
|
||||||
|
@nodes[to_id].input_nodes << @nodes[from_id]
|
||||||
|
@order = nil # mark activation order as being dirty
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
# calculate activation order if it's 'nil'
|
||||||
|
@order ||= activation_order
|
||||||
|
|
||||||
|
# simply update each node in order
|
||||||
|
@order.each do |layer|
|
||||||
|
puts "Layer"
|
||||||
|
layer.each { |node| puts "updating node #{node.id}"; node.update }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def activation_order
|
||||||
|
# do the recursive search, starting with the output layer
|
||||||
|
# then, add the input nodes to the front
|
||||||
|
[input_nodes] + a_o_bfs(output_nodes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_nodes(re)
|
||||||
|
# collect all of the output node ids, this is the end layer of the ANN
|
||||||
|
node_ids = @nodes.keys.select { |k,v| re.match(k) }
|
||||||
|
|
||||||
|
# use id's to get array of nodes, then sort
|
||||||
|
node_ids.collect { |id| @nodes[id] }.sort
|
||||||
|
end
|
||||||
|
|
||||||
|
def input_nodes
|
||||||
|
find_nodes(/i[0-9]+/)
|
||||||
|
end
|
||||||
|
|
||||||
|
def hidden_nodes
|
||||||
|
find_nodes(/h[0-9]+/)
|
||||||
|
end
|
||||||
|
|
||||||
|
def output_nodes
|
||||||
|
find_nodes(/o[0-9]+/)
|
||||||
|
end
|
||||||
|
|
||||||
|
def a_o_bfs(current_layer, seen=nil, order=nil)
|
||||||
|
# setup some state for this recursion
|
||||||
|
seen ||= Hash.new
|
||||||
|
order ||= Array.new
|
||||||
|
|
||||||
|
# mark current nodes as seen
|
||||||
|
current_layer.each { |n| seen[n] = true }
|
||||||
|
|
||||||
|
# prepend current layer to final order
|
||||||
|
order = [current_layer.sort] + order
|
||||||
|
|
||||||
|
# get next layer
|
||||||
|
next_layer = current_layer.collect { |n| n.input_nodes }
|
||||||
|
next_layer = next_layer.flatten.select { |n| not seen[n] and not /i[0-9]+/.match(n.id) }
|
||||||
|
|
||||||
|
if not next_layer.empty?
|
||||||
|
# recurse into next layer if it exists
|
||||||
|
a_o_bfs(next_layer, seen, order)
|
||||||
|
else
|
||||||
|
# finished
|
||||||
|
order
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# create a network
|
||||||
|
n = Network.new(3,4,3)
|
||||||
|
n.connect('i0','h0')
|
||||||
|
n.connect('h0','o0')
|
||||||
|
n.connect('i1','h2')
|
||||||
|
n.connect('i2','h1')
|
||||||
|
n.connect('h1','h0')
|
||||||
|
n.connect('h2','h0')
|
||||||
|
n.connect('h2','h3')
|
||||||
|
n.connect('h3','o2')
|
||||||
|
|
||||||
|
# run some data through the network
|
||||||
|
10.times do
|
||||||
|
# give network some data
|
||||||
|
n.nodes['i0'].activation = (2.0 * Kernel.rand) - 1.0
|
||||||
|
n.nodes['i1'].activation = (2.0 * Kernel.rand) - 1.0
|
||||||
|
|
||||||
|
# update network
|
||||||
|
n.update
|
||||||
|
|
||||||
|
# read outputs
|
||||||
|
puts n.nodes['o0'].activation
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
Reference in new issue
Block a user