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