commit 9cd2d19fb9f10a7c01d44cc3a1b632e4ee122151 Author: Stephen Waits Date: Thu Sep 30 15:23:17 2010 -0700 create NEAT app repo diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..e59d8cc --- /dev/null +++ b/.hgignore @@ -0,0 +1,3 @@ +.svn\/ +^tags$ +^.DS_Store diff --git a/ConnectionGene.cpp b/ConnectionGene.cpp new file mode 100644 index 0000000..0777295 --- /dev/null +++ b/ConnectionGene.cpp @@ -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(*this) < rhs; +} + +bool ConnectionGene::operator== (const ConnectionGene& rhs) const +{ + return static_cast(*this) == rhs; +} + +float ConnectionGene::GetWeight() const +{ + return m_weight; +} + diff --git a/ConnectionGene.h b/ConnectionGene.h new file mode 100644 index 0000000..6c33a10 --- /dev/null +++ b/ConnectionGene.h @@ -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__ + diff --git a/Gene.cpp b/Gene.cpp new file mode 100644 index 0000000..2638a92 --- /dev/null +++ b/Gene.cpp @@ -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); +} + diff --git a/Gene.h b/Gene.h new file mode 100644 index 0000000..572b713 --- /dev/null +++ b/Gene.h @@ -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__ + diff --git a/Genotype.cpp b/Genotype.cpp new file mode 100644 index 0000000..d65793c --- /dev/null +++ b/Genotype.cpp @@ -0,0 +1,330 @@ +#include "Genotype.h" + +#include +#include + +#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::const_iterator, it_dad, dad.Connections ) + { + // see if mom has matching gene, via brute force search + iterate_each( std::vector::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::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= 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::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::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::const_iterator, it_lhs, Connections ) + { + bool match = false; + iterate_each ( std::vector::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; + } +} + diff --git a/Genotype.h b/Genotype.h new file mode 100644 index 0000000..d990cae --- /dev/null +++ b/Genotype.h @@ -0,0 +1,63 @@ +#ifndef __Genotype_h__ +#define __Genotype_h__ + +#include + +#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 Neurons; + std::vector Connections; + + float Fitness; +}; + +#endif // __Genotype_h__ + diff --git a/Innovation.cpp b/Innovation.cpp new file mode 100644 index 0000000..ce41b01 --- /dev/null +++ b/Innovation.cpp @@ -0,0 +1,3 @@ +#include "Innovation.h" + +// deprecated diff --git a/Innovation.h b/Innovation.h new file mode 100644 index 0000000..8eb7864 --- /dev/null +++ b/Innovation.h @@ -0,0 +1,7 @@ +#ifndef __Innovation_h__ +#define __Innovation_h__ + +// deprecated + +#endif // __Innovation_h__ + diff --git a/Innovator.cpp b/Innovator.cpp new file mode 100644 index 0000000..0299230 --- /dev/null +++ b/Innovator.cpp @@ -0,0 +1,132 @@ +#include "Innovator.h" + +#include + +#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::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::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::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; +} + diff --git a/Innovator.h b/Innovator.h new file mode 100644 index 0000000..b0d4e60 --- /dev/null +++ b/Innovator.h @@ -0,0 +1,57 @@ +#ifndef __Innovator_h__ +#define __Innovator_h__ + +#include + +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 m_innovations; + + // temporary (smaller) list of current new innovations, rolls into master list on calls to Update + std::vector m_new_innovations; +}; + +#endif // __Innovator_h__ + diff --git a/IteratorHelper.h b/IteratorHelper.h new file mode 100644 index 0000000..3a84a4b --- /dev/null +++ b/IteratorHelper.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__ diff --git a/MathHelper.h b/MathHelper.h new file mode 100644 index 0000000..8263330 --- /dev/null +++ b/MathHelper.h @@ -0,0 +1,4 @@ +#ifndef __MathHelper_h__ +#define __MathHelper_h__ + +#endif // __MathHelper_h__ diff --git a/NEAT.cpp b/NEAT.cpp new file mode 100644 index 0000000..effca44 --- /dev/null +++ b/NEAT.cpp @@ -0,0 +1,321 @@ +#include "NEAT.h" + +#include +#include + +#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::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::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::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::iterator, it_species, m_species ) + { + float divisor = (float)((*it_species).member_ids.size()); + iterate_each( std::vector::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 old_population(m_population); + m_population.clear(); + + // get total fitness (assumes already adjusted) + float fitness_total = 0.0f; + iterate_each( std::vector::iterator, it, old_population ) + { + fitness_total += (*it).GetFitness(); + } + + // now have each species spawn amounts based on its share population average + iterate_each( std::vector::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::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 networks; + iterate_each( std::vector::iterator, it_genotype, m_population ) + { + networks.push_back( NeuralNetwork(*it_genotype) ); + } + + // test networks + std::vector 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); +} + + diff --git a/NEAT.h b/NEAT.h new file mode 100644 index 0000000..0271eb0 --- /dev/null +++ b/NEAT.h @@ -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& networks, std::vector& fitness) = 0; + +private: + + struct Species + { + Species(const Genotype& originator, int originator_id, int species_id); + + int species_id; + Genotype representative; + std::vector member_ids; + }; + + Innovator m_innovator; + std::vector m_population; + std::vector m_best; + std::vector m_species; + int m_next_species_id; + + void SortPopulation(); + void SaveBestGenomes(); + void SpeciatePopulation(); + void AdjustAndShareFitness(); + void Reproduce(); +}; + +#endif // __NEAT_h__ + + + + + diff --git a/NeuralNetwork.cpp b/NeuralNetwork.cpp new file mode 100644 index 0000000..272eb15 --- /dev/null +++ b/NeuralNetwork.cpp @@ -0,0 +1,159 @@ +#include "NeuralNetwork.h" + +#include +#include +#include + +#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::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::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::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::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::iterator, it_neuron, Neurons ) + { + if ( !(*it_neuron).Fixed ) + { + (*it_neuron).Activation = 0.0; + } + } +} + +void NeuralNetwork::Update(const std::vector& inputs, std::vector& outputs) // TODO make input STL-like, begin(), end() & array compatible +{ + // assign inputs + for ( int i=0;i::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::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& inputs, std::vector& 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 Inputs; + }; + + std::vector Neurons; + int NumInputs, NumOutputs; + + int GetNeuronIndexFromID(int id); + +}; + +#endif // __NeuralNetwork_h__ + diff --git a/NeuronGene.cpp b/NeuronGene.cpp new file mode 100644 index 0000000..9c056bc --- /dev/null +++ b/NeuronGene.cpp @@ -0,0 +1,71 @@ +#include "NeuronGene.h" + +#include + +#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(*this) < rhs; +} + +bool NeuronGene::operator== (const NeuronGene& rhs) const +{ + return static_cast(*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; +} diff --git a/NeuronGene.h b/NeuronGene.h new file mode 100644 index 0000000..0476460 --- /dev/null +++ b/NeuronGene.h @@ -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__ + diff --git a/Random.cpp b/Random.cpp new file mode 100644 index 0000000..568d277 --- /dev/null +++ b/Random.cpp @@ -0,0 +1,103 @@ +#include "Random.h" + +#include +#include +#include + +#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 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::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; +} diff --git a/Random.h b/Random.h new file mode 100644 index 0000000..871bc12 --- /dev/null +++ b/Random.h @@ -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__ + diff --git a/Species.cpp b/Species.cpp new file mode 100644 index 0000000..9182072 --- /dev/null +++ b/Species.cpp @@ -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::iterator, it, m_members ) + { + (*it).SetFitness( (*it).GetFitness() / total_members ); + } +} + +float Species::GetFitness() +{ + float total = 0.0f; + iterate_each( std::vector::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 + diff --git a/Species.h b/Species.h new file mode 100644 index 0000000..d66ec68 --- /dev/null +++ b/Species.h @@ -0,0 +1,31 @@ +#ifndef __Species_h__ +#define __Species_h__ + +#include "Genotype.h" +#include + +#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 m_members; + float m_spawn_amount; +}; +#endif + +#endif // __Species_h__ diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..9d09311 --- /dev/null +++ b/TODO.txt @@ -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 \ No newline at end of file diff --git a/activation_order.rb b/activation_order.rb new file mode 100644 index 0000000..58fe501 --- /dev/null +++ b/activation_order.rb @@ -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 + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..465c842 --- /dev/null +++ b/main.cpp @@ -0,0 +1,110 @@ +#include +#include +#include + +#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& networks, std::vector& fitness) + { + bool solution_found = false; + iterate_each( std::vector::iterator, it_network, networks ) + { + std::vector inputs; + std::vector 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; +} diff --git a/neat.1 b/neat.1 new file mode 100644 index 0000000..e7619d7 --- /dev/null +++ b/neat.1 @@ -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 \ No newline at end of file diff --git a/neat.sln b/neat.sln new file mode 100644 index 0000000..54c9c14 --- /dev/null +++ b/neat.sln @@ -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 diff --git a/neat.tmproj b/neat.tmproj new file mode 100644 index 0000000..cf55103 --- /dev/null +++ b/neat.tmproj @@ -0,0 +1,153 @@ + + + + + documents + + + children + + + children + + + filename + BiasNeuron.cpp + + + filename + BiasNeuron.h + + + filename + ConnectionGene.cpp + + + filename + ConnectionGene.h + + + filename + Gene.cpp + + + filename + Gene.h + + + filename + Genotype.cpp + + + filename + Genotype.h + + + filename + Innovation.cpp + + + filename + Innovation.h + + + filename + InputNeuron.cpp + + + filename + InputNeuron.h + + + filename + NEAT.cpp + + + filename + NEAT.h + + + filename + NeuralNetwork.cpp + + + filename + NeuralNetwork.h + + + filename + Neuron.cpp + + + filename + Neuron.h + + + filename + NeuronGene.cpp + + + filename + NeuronGene.h + + + filename + SigmoidNeuron.cpp + + + filename + SigmoidNeuron.h + + + filename + main.cpp + + + expanded + + name + Source + + + children + + + filename + neat.1 + + + expanded + + name + Documentation + + + children + + + filename + neat + + + expanded + + name + Products + + + expanded + + name + neat + + + fileHierarchyDrawerWidth + 200 + metaData + + showFileHierarchyDrawer + + windowFrame + {{142, 116}, {851, 661}} + + diff --git a/neat.vcproj b/neat.vcproj new file mode 100644 index 0000000..1459bf4 --- /dev/null +++ b/neat.vcproj @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/neat.xcodeproj/project.pbxproj b/neat.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f2640ae --- /dev/null +++ b/neat.xcodeproj/project.pbxproj @@ -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 = ""; }; + 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 = ""; }; + C11C1D1A0B27CD8C00979D81 /* ConnectionGene.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ConnectionGene.h; sourceTree = ""; }; + C11C1D1B0B27CD8C00979D81 /* Gene.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Gene.cpp; sourceTree = ""; }; + C11C1D1C0B27CD8C00979D81 /* Gene.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Gene.h; sourceTree = ""; }; + C11C1D1D0B27CD8C00979D81 /* Genotype.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Genotype.cpp; sourceTree = ""; }; + C11C1D1E0B27CD8C00979D81 /* Genotype.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Genotype.h; sourceTree = ""; }; + C11C1D1F0B27CD8C00979D81 /* Innovation.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Innovation.cpp; sourceTree = ""; }; + C11C1D200B27CD8C00979D81 /* Innovation.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Innovation.h; sourceTree = ""; }; + C11C1D230B27CD8C00979D81 /* NEAT.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = NEAT.cpp; sourceTree = ""; }; + C11C1D240B27CD8C00979D81 /* NEAT.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NEAT.h; sourceTree = ""; }; + C11C1D250B27CD8C00979D81 /* NeuralNetwork.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = NeuralNetwork.cpp; sourceTree = ""; }; + C11C1D260B27CD8C00979D81 /* NeuralNetwork.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NeuralNetwork.h; sourceTree = ""; }; + C11C1D290B27CD8C00979D81 /* NeuronGene.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = NeuronGene.cpp; sourceTree = ""; }; + C11C1D2A0B27CD8C00979D81 /* NeuronGene.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NeuronGene.h; sourceTree = ""; }; + C1230D040B7466E9005F79C9 /* Species.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Species.cpp; sourceTree = ""; }; + C1230D050B7466E9005F79C9 /* Species.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Species.h; sourceTree = ""; }; + C18013EC0B2E60C500943E57 /* Innovator.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Innovator.cpp; sourceTree = ""; }; + C18013ED0B2E60C500943E57 /* Innovator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Innovator.h; sourceTree = ""; }; + C18013EE0B2E60C500943E57 /* Random.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Random.cpp; sourceTree = ""; }; + C18013EF0B2E60C500943E57 /* Random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Random.h; sourceTree = ""; }; + C6859E8B029090EE04C91782 /* neat.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = neat.1; sourceTree = ""; }; +/* 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 = ""; + }; + 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 = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76F6C0486A84900D96B5E /* neat */, + ); + name = Products; + sourceTree = ""; + }; + C6859E8C029090F304C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6859E8B029090EE04C91782 /* neat.1 */, + ); + name = Documentation; + sourceTree = ""; + }; +/* 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 */; +} diff --git a/neat.xcodeproj/swaits.mode1 b/neat.xcodeproj/swaits.mode1 new file mode 100644 index 0000000..ad27e93 --- /dev/null +++ b/neat.xcodeproj/swaits.mode1 @@ -0,0 +1,1370 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXRunSessionModule + Name + Run Log + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1 + FavBarConfig + + PBXProjectModuleGUID + C11C1D480B27CDCF00979D81 + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1 + MajorVersion + 31 + MinorVersion + 1 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-target-popup + active-buildstyle-popup + action + NSToolbarFlexibleSpaceItem + buildOrClean + build-and-runOrDebug + com.apple.ide.PBXToolbarStopButton + get-info + toggle-editor + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 08FB7794FE84155DC02AAC07 + 08FB7795FE84155DC02AAC07 + C6859E8C029090F304C91782 + 1AB674ADFE9D54B511CA2CBB + 1C77FABC04509CD000000102 + 1C3E0DCA080725EA00A55177 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 37 + 36 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 13}, {186, 650}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 668}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 214 90 813 709 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {605, 0}} + RubberWindowFrame + 214 90 813 709 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 5}, {605, 663}} + RubberWindowFrame + 214 90 813 709 0 0 1440 878 + + Module + XCDetailModule + Proportion + 663pt + + + Proportion + 605pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + C123DD070B79A5E700FB4F9C + 1CE0B1FE06471DED0097A5F4 + C123DD080B79A5E700FB4F9C + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.short + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/System/Library/PrivateFrameworks/DevToolsInterface.framework/Versions/A/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + C123DD130B79A5E700FB4F9C + C123DD140B79A5E700FB4F9C + C18770670B27D90E0060D99F + C123DD100B79A5E700FB4F9C + C11C1D490B27CDCF00979D81 + /Users/swaits/SVN/code/apps/neat/neat.xcodeproj + 1CD10A99069EF8BA00B06720 + + WindowString + 214 90 813 709 0 0 1440 878 + WindowTools + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {500, 218}} + RubberWindowFrame + 396 289 500 500 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 223}, {500, 236}} + RubberWindowFrame + 396 289 500 500 0 0 1440 878 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 459pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + C11C1D490B27CDCF00979D81 + C123DD090B79A5E700FB4F9C + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.build + WindowString + 396 289 500 500 0 0 1440 878 + WindowToolGUID + C11C1D490B27CDCF00979D81 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {345, 285}} + {{345, 0}, {695, 285}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {1040, 285}} + {{0, 285}, {1040, 417}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleDrawerSize + {100, 120} + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{20, 418}, {500, 300}} + Frame + {{0, 0}, {1040, 702}} + RubberWindowFrame + 368 106 1040 743 0 0 1440 878 + + Module + PBXDebugSessionModule + Proportion + 702pt + + + Proportion + 702pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + C123DD0A0B79A5E700FB4F9C + 1C162984064C10D400B95A72 + C123DD0B0B79A5E700FB4F9C + C123DD0C0B79A5E700FB4F9C + C123DD0D0B79A5E700FB4F9C + C123DD0E0B79A5E700FB4F9C + C123DD0F0B79A5E700FB4F9C + C123DD100B79A5E700FB4F9C + + ToolbarConfiguration + xcode.toolbar.config.debug + WindowString + 368 106 1040 743 0 0 1440 878 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + Identifier + windowTool.find + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD0528D0623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {781, 167}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 50% + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{8, 0}, {773, 254}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXProjectFindModule + Proportion + 50% + + + Proportion + 428pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C530D57069F1CE1000CFCEE + 1C530D58069F1CE1000CFCEE + 1C530D59069F1CE1000CFCEE + 1CDD528C0622207200134675 + 1C530D5A069F1CE1000CFCEE + 1CE0B1FE06471DED0097A5F4 + 1CD0528E0623707200166675 + + WindowString + 62 385 781 470 0 0 1440 878 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + 0 + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {459, 452}} + RubberWindowFrame + 21 348 459 493 0 0 1440 878 + + Module + PBXDebugCLIModule + Proportion + 452pt + + + Proportion + 452pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + C18770670B27D90E0060D99F + C123DD110B79A5E700FB4F9C + 1C78EAAC065D492600B07095 + + WindowString + 21 348 459 493 0 0 1440 878 + WindowToolGUID + C18770670B27D90E0060D99F + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.run + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + LauncherConfigVersion + 3 + PBXProjectModuleGUID + 1CD0528B0623707200166675 + PBXProjectModuleLabel + Run + Runner + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {493, 167}} + {{0, 176}, {493, 267}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {405, 443}} + {{414, 0}, {514, 443}} + + + + + GeometryConfiguration + + Frame + {{0, 0}, {694, 644}} + RubberWindowFrame + 93 141 694 685 0 0 1440 878 + + Module + PBXRunSessionModule + Proportion + 644pt + + + Proportion + 644pt + + + Name + Run Log + ServiceClasses + + PBXRunSessionModule + + StatusbarIsVisible + + TableOfContents + + 1C0AD2B3069F1EA900FABCE6 + C1EA55810B7709B900BAEBF5 + 1CD0528B0623707200166675 + C1EA55820B7709B900BAEBF5 + + ToolbarConfiguration + xcode.toolbar.config.run + WindowString + 93 141 694 685 0 0 1440 878 + WindowToolGUID + 1C0AD2B3069F1EA900FABCE6 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.scm + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 59 482 452 308 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM Results + + GeometryConfiguration + + Frame + {{0, 5}, {452, 262}} + RubberWindowFrame + 59 482 452 308 0 0 1440 878 + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 267pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + + TableOfContents + + C11C1D590B27CF0500979D81 + C11C1D5A0B27CF0500979D81 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 59 482 452 308 0 0 1440 878 + WindowToolGUID + C11C1D590B27CF0500979D81 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.breakpoints + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 36 111 744 409 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 36 111 744 409 0 0 1440 878 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 2 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + + TableOfContents + + C1EA55830B7709B900BAEBF5 + C1EA55840B7709B900BAEBF5 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpoints + WindowString + 36 111 744 409 0 0 1440 878 + WindowToolGUID + C1EA55830B7709B900BAEBF5 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugAnimator + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + C1C8749D0B313B5A00DAF936 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {700, 459}} + RubberWindowFrame + 560 325 700 500 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 459pt + + + Proportion + 459pt + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + + TableOfContents + + C1C8749F0B313B5A00DAF936 + C1C874A00B313B5A00DAF936 + C1C8749D0B313B5A00DAF936 + + ToolbarConfiguration + xcode.toolbar.config.debugAnimator + WindowString + 560 325 700 500 0 0 1440 878 + WindowToolGUID + C1C8749F0B313B5A00DAF936 + WindowToolIsVisible + + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {374, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 331}} + MembersFrame + {{0, 105}, {374, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 97 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 385 179 630 352 0 0 1440 878 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 1C0AD2B0069F1E9B00FABCE6 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 385 179 630 352 0 0 1440 878 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + 0 + + + + diff --git a/neat.xcodeproj/swaits.pbxuser b/neat.xcodeproj/swaits.pbxuser new file mode 100644 index 0000000..e77c8fa --- /dev/null +++ b/neat.xcodeproj/swaits.pbxuser @@ -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}}"; + }; + }; +} diff --git a/network_sort.rb b/network_sort.rb new file mode 100755 index 0000000..133c21b --- /dev/null +++ b/network_sort.rb @@ -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 +