Files
neat/NeuralNetwork.cpp
2010-09-30 15:23:17 -07:00

160 lines
3.8 KiB
C++

#include "NeuralNetwork.h"
#include <algorithm>
#include <cassert>
#include <cmath>
#include "IteratorHelper.h"
NeuralNetwork::Neuron::Neuron(int id, float x, float y, bool fixed, float activation):
ID(id),
X(x),
Y(y),
Fixed(fixed),
Activation(activation)
{
// empty
}
bool NeuralNetwork::Neuron::operator< (const NeuralNetwork::Neuron& rhs) const
{
return
(Y < rhs.Y) ||
((Y == rhs.Y) && (X < rhs.X));
}
NeuralNetwork::NeuralNetwork(const Genotype& genotype)
{
// reset out input/output count
NumInputs = NumOutputs = 0;
// copy the neurons
for ( std::vector<NeuronGene>::const_iterator it = genotype.Neurons.begin(); it != genotype.Neurons.end(); ++it )
{
switch ( (*it).GetType() )
{
case NeuronGene::BIAS:
Neurons.push_back(Neuron((*it).GetInnovation(),(*it).GetX(),(*it).GetY(),true,1.0));
break;
case NeuronGene::INPUT:
++NumInputs;
Neurons.push_back(Neuron((*it).GetInnovation(),(*it).GetX(),(*it).GetY(),true,0.0));
break;
case NeuronGene::OUTPUT:
++NumOutputs;
// fall through
case NeuronGene::HIDDEN:
Neurons.push_back(Neuron((*it).GetInnovation(),(*it).GetX(),(*it).GetY()));
break;
}
}
// sort neurons by position
std::sort(Neurons.begin(), Neurons.end());
// copy the connections
for ( std::vector<ConnectionGene>::const_iterator it = genotype.Connections.begin(); it != genotype.Connections.end(); ++it )
{
if ( (*it).IsEnabled() )
{
// figure out which two neurons this thing connects
int index_a = GetNeuronIndexFromID((*it).GetInputNeuron());
int index_b = GetNeuronIndexFromID((*it).GetOutputNeuron());
assert(index_a < (int)Neurons.size() && index_b < (int)Neurons.size());
// now add to the neuron
Neurons[index_b].Inputs.push_back( Connection(index_a,(*it).GetWeight()) );
}
}
// print out this network
#if 0
int i = 0;
iterate_each ( std::vector<Neuron>::iterator, it_neuron, Neurons )
{
printf("Neuron %2d (%2d) %0.2f %0.2f\n",i,(*it_neuron).ID,(*it_neuron).X,(*it_neuron).Y);
iterate_each ( std::vector<Connection>::iterator, it_connection, (*it_neuron).Inputs )
{
printf(" %d %0.5f\n",(*it_connection).id,(*it_connection).weight);
}
++i;
}
#endif
}
NeuralNetwork::~NeuralNetwork()
{
}
void NeuralNetwork::Reset()
{
iterate_each ( std::vector<Neuron>::iterator, it_neuron, Neurons )
{
if ( !(*it_neuron).Fixed )
{
(*it_neuron).Activation = 0.0;
}
}
}
void NeuralNetwork::Update(const std::vector<float>& inputs, std::vector<float>& outputs) // TODO make input STL-like, begin(), end() & array compatible
{
// assign inputs
for ( int i=0;i<NumInputs;++i )
{
// TODO range check this!!!
Neurons[i+1].Activation = inputs[i]; // +1 is because Bias is #0 - this is messy TODO: clean up, make safer
// TODO make sure this is really an input Neuron!!! and its ID matches up, etc.
}
// update each neuron
iterate_each ( std::vector<Neuron>::iterator, it_neuron, Neurons )
{
// if this is a fixed neuron, skip
if ( (*it_neuron).Fixed )
{
continue;
}
// sum the inputs into this neuron
float sum = 0.0f;
iterate_each ( std::vector<Connection>::iterator, it_connection, (*it_neuron).Inputs )
{
sum += Neurons[(*it_connection).id].Activation * (*it_connection).weight;
}
// activate
(*it_neuron).Activation = 1.0f / (1.0f + (expf(-4.9f * sum)));
}
// clear outputs
outputs.clear();
// copy outputs
for ( int i=0;i<NumOutputs;++i )
{
size_t index = Neurons.size() - NumOutputs + i;
outputs.push_back( Neurons[index].Activation );
}
}
int NeuralNetwork::GetNeuronIndexFromID(int id)
{
for ( int i=0;i<(int)Neurons.size();++i )
{
if ( Neurons[i].ID == id )
{
return i;
}
}
assert(0);
return 0;
}