create NEAT app repo

This commit is contained in:
swaits committed 2010-09-30 15:23:17 -07:00
commit 9cd2d19fb9
34 files changed
+4454

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
.svn\/
^tags$
^.DS_Store
+76
View File
@@ -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;
}
+37
View File
@@ -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__
+37
View File
@@ -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);
}
+23
View File
@@ -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
View File
@@ -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
View File
@@ -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__
+3
View File
@@ -0,0 +1,3 @@
#include "Innovation.h"
// deprecated
+7
View File
@@ -0,0 +1,7 @@
#ifndef __Innovation_h__
#define __Innovation_h__
// deprecated
#endif // __Innovation_h__
+132
View File
@@ -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
View File
@@ -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__
+11
View File
@@ -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__
+4
View File
@@ -0,0 +1,4 @@
#ifndef __MathHelper_h__
#define __MathHelper_h__
#endif // __MathHelper_h__
+321
View File
@@ -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);
}
+66
View File
@@ -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__
+159
View File
@@ -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;
}
+53
View File
@@ -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__
+71
View File
@@ -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;
}
+46
View File
@@ -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
View File
@@ -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;
}
+14
View File
@@ -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
View File
@@ -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
+31
View File
@@ -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__
+17
View File
@@ -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
+42
View File
@@ -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
+110
View File
@@ -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;
}
+79
View File
@@ -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
+21
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+282
View File
@@ -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
+308
View File
@@ -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}}";
};
};
}
+142
View File
@@ -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