📄 genotype.cpp
字号:
#include "genotype.h"
//------------------------------------------------------------------------
//
// default ctor
//------------------------------------------------------------------------
CGenome::CGenome():m_pPhenotype(NULL),
m_GenomeID(0),
m_dFitness(0),
m_dAdjustedFitness(0),
m_iNumInputs(0),
m_iNumOutPuts(0),
m_dAmountToSpawn(0)
{}
//-----------------------------constructor--------------------------------
// this constructor creates a minimal genome where there are output +
// input neurons and each input neuron is connected to each output neuron.
//------------------------------------------------------------------------
CGenome::CGenome(int id, int inputs, int outputs):m_pPhenotype(NULL),
m_GenomeID(id),
m_dFitness(0),
m_dAdjustedFitness(0),
m_iNumInputs(inputs),
m_iNumOutPuts(outputs),
m_dAmountToSpawn(0),
m_iSpecies(0)
{
//create the input neurons
double InputRowSlice = 1/(double)(inputs+2);
for (int i=0; i<inputs; i++)
{
m_vecNeurons.push_back(SNeuronGene(input, i, 0, (i+2)*InputRowSlice));
}
//create the bias
m_vecNeurons.push_back(SNeuronGene(bias, inputs, 0, InputRowSlice));
//create the output neurons
double OutputRowSlice = 1/(double)(outputs+1);
for (i=0; i<outputs; i++)
{
m_vecNeurons.push_back(SNeuronGene(output, i+inputs+1, 1, (i+1)*OutputRowSlice));
}
//create the link genes, connect each input neuron to each output neuron and
//assign a random weight -1 < w < 1
for (i=0; i<inputs+1; i++)
{
for (int j=0; j<outputs; j++)
{
m_vecLinks.push_back(SLinkGene(m_vecNeurons[i].iID,
m_vecNeurons[inputs+j+1].iID,
true,
inputs+outputs+1+NumGenes(),
RandomClamped()));
}
}
}
//------------------------------------------------------------------------
//
// this constructor creates a genome from a vector of SLinkGenes, a
// vector of SNeuronGenes and an ID number.
//------------------------------------------------------------------------
CGenome::CGenome(int id,
vector<SNeuronGene> neurons,
vector<SLinkGene> genes,
int inputs,
int outputs):m_GenomeID(id),
m_pPhenotype(NULL),
m_vecLinks(genes),
m_vecNeurons(neurons),
m_dAmountToSpawn(0),
m_dFitness(0),
m_dAdjustedFitness(0),
m_iNumInputs(inputs),
m_iNumOutPuts(outputs)
{}
//-------------------------------dtor-----------------------------------------------------
//
//----------------------------------------------------------------------------------------
CGenome::~CGenome()
{
if (m_pPhenotype)
{
delete m_pPhenotype;
m_pPhenotype = NULL;
}
}
//---------------------------------copy ctor---------------------------------------------
//
//---------------------------------------------------------------------------------------
CGenome::CGenome(const CGenome& g)
{
m_GenomeID = g.m_GenomeID;
m_vecNeurons = g.m_vecNeurons;
m_vecLinks = g.m_vecLinks;
m_pPhenotype = NULL; //no need to perform a deep copy
m_dFitness = g.m_dFitness;
m_dAdjustedFitness = g.m_dAdjustedFitness;
m_iNumInputs = g.m_iNumInputs;
m_iNumOutPuts = g.m_iNumOutPuts;
m_dAmountToSpawn = g.m_dAmountToSpawn;
}
//---------------------------------assignment operator-----------------------------------
//
//----------------------------------------------------------------------------------------
CGenome& CGenome::operator =(const CGenome& g)
{
//self assignment guard
if (this != &g)
{
m_GenomeID = g.m_GenomeID;
m_vecNeurons = g.m_vecNeurons;
m_vecLinks = g.m_vecLinks;
m_pPhenotype = NULL; //no need to perform a deep copy
m_dFitness = g.m_dFitness;
m_dAdjustedFitness = g.m_dAdjustedFitness;
m_iNumInputs = g.m_iNumInputs;
m_iNumOutPuts = g.m_iNumOutPuts;
m_dAmountToSpawn = g.m_dAmountToSpawn;
}
return *this;
}
//-------------------------------CreatePhenotype--------------------------
//
// Creates a neural network based upon the information in the genome.
// Returns a pointer to the newly created ANN
//------------------------------------------------------------------------
CNeuralNet* CGenome::CreatePhenotype(int depth)
{
//first make sure there is no existing phenotype for this genome
DeletePhenotype();
//this will hold all the neurons required for the phenotype
vector<SNeuron*> vecNeurons;
//first, create all the required neurons
for (int i=0; i<m_vecNeurons.size(); i++)
{
SNeuron* pNeuron = new SNeuron(m_vecNeurons[i].NeuronType,
m_vecNeurons[i].iID,
m_vecNeurons[i].dSplitY,
m_vecNeurons[i].dSplitX,
m_vecNeurons[i].dActivationResponse);
vecNeurons.push_back(pNeuron);
}
//now to create the links.
for (int cGene=0; cGene<m_vecLinks.size(); ++cGene)
{
//make sure the link gene is enabled before the connection is created
if (m_vecLinks[cGene].bEnabled)
{
//get the pointers to the relevant neurons
int element = GetElementPos(m_vecLinks[cGene].FromNeuron);
SNeuron* FromNeuron = vecNeurons[element];
element = GetElementPos(m_vecLinks[cGene].ToNeuron);
SNeuron* ToNeuron = vecNeurons[element];
//create a link between those two neurons and assign the weight stored
//in the gene
SLink tmpLink(m_vecLinks[cGene].dWeight,
FromNeuron,
ToNeuron,
m_vecLinks[cGene].bRecurrent);
//add new links to neuron
FromNeuron->vecLinksOut.push_back(tmpLink);
ToNeuron->vecLinksIn.push_back(tmpLink);
}
}
//now the neurons contain all the connectivity information, a neural
//network may be created from them.
m_pPhenotype = new CNeuralNet(vecNeurons, depth);
return m_pPhenotype;
}
//--------------------------- DeletePhenotype ----------------------------
//
//------------------------------------------------------------------------
void CGenome::DeletePhenotype()
{
if (m_pPhenotype)
{
delete m_pPhenotype;
}
m_pPhenotype = NULL;
}
//---------------------------- GetElementPos -----------------------------
//
// given a neuron ID this little function just finds its position in
// m_vecNeurons
//------------------------------------------------------------------------
int CGenome::GetElementPos(int neuron_id)
{
for (int i=0; i<m_vecNeurons.size(); i++)
{
if (m_vecNeurons[i].iID == neuron_id)
{
return i;
}
}
MessageBox(NULL, "Error in CGenome::GetElementPos", "Problem!", MB_OK);
return -1;
}
//------------------------------DuplicateLink-----------------------------
//
// returns true if the link is already part of the genome
//------------------------------------------------------------------------
bool CGenome::DuplicateLink(int NeuronIn, int NeuronOut)
{
for (int cGene = 0; cGene < m_vecLinks.size(); ++cGene)
{
if ((m_vecLinks[cGene].FromNeuron == NeuronIn) &&
(m_vecLinks[cGene].ToNeuron == NeuronOut))
{
//we already have this link
return true;
}
}
return false;
}
//--------------------------------AddLink---------------------------------
//
// create a new link with the probability of CParams::dChanceAddLink
//------------------------------------------------------------------------
void CGenome::AddLink(double MutationRate,
double ChanceOfLooped,
CInnovation &innovation,
int NumTrysToFindLoop,
int NumTrysToAddLink)
{
//just return dependent on the mutation rate
if (RandFloat() > MutationRate) return;
//define holders for the two neurons to be linked. If we have find two
//valid neurons to link these values will become >= 0.
int ID_neuron1 = -1;
int ID_neuron2 = -1;
//flag set if a recurrent link is selected (looped or normal)
bool bRecurrent = false;
//first test to see if an attempt shpould be made to create a
//link that loops back into the same neuron
if (RandFloat() < ChanceOfLooped)
{
//YES: try NumTrysToFindLoop times to find a neuron that is not an
//input or bias neuron and that does not already have a loopback
//connection
while(NumTrysToFindLoop--)
{
//grab a random neuron
int NeuronPos = RandInt(m_iNumInputs+1, m_vecNeurons.size()-1);
//check to make sure the neuron does not already have a loopback
//link and that it is not an input or bias neuron
if (!m_vecNeurons[NeuronPos].bRecurrent &&
(m_vecNeurons[NeuronPos].NeuronType != bias) &&
(m_vecNeurons[NeuronPos].NeuronType != input))
{
ID_neuron1 = ID_neuron2 = m_vecNeurons[NeuronPos].iID;
m_vecNeurons[NeuronPos].bRecurrent = true;
bRecurrent = true;
NumTrysToFindLoop = 0;
}
}
}
else
{
//No: try to find two unlinked neurons. Make NumTrysToAddLink
//attempts
while(NumTrysToAddLink--)
{
//choose two neurons, the second must not be an input or a bias
ID_neuron1 = m_vecNeurons[RandInt(0, m_vecNeurons.size()-1)].iID;
ID_neuron2 =
m_vecNeurons[RandInt(m_iNumInputs+1, m_vecNeurons.size()-1)].iID;
if (ID_neuron2 == 2)
{
continue;
}
//make sure these two are not already linked and that they are
//not the same neuron
if ( !( DuplicateLink(ID_neuron1, ID_neuron2) ||
(ID_neuron1 == ID_neuron2)))
{
NumTrysToAddLink = 0;
}
else
{
ID_neuron1 = -1;
ID_neuron2 = -1;
}
}
}
//return if unsuccessful in finding a link
if ( (ID_neuron1 < 0) || (ID_neuron2 < 0) )
{
return;
}
//check to see if we have already created this innovation
int id = innovation.CheckInnovation(ID_neuron1, ID_neuron2, new_link);
//is this link recurrent?
if (m_vecNeurons[GetElementPos(ID_neuron1)].dSplitY >
m_vecNeurons[GetElementPos(ID_neuron2)].dSplitY)
{
bRecurrent = true;
}
if ( id < 0)
{
//we need to create a new innovation
innovation.CreateNewInnovation(ID_neuron1, ID_neuron2, new_link);
//then create the new gene
int id = innovation.NextNumber() - 1;
SLinkGene NewGene(ID_neuron1,
ID_neuron2,
true,
id,
RandomClamped(),
bRecurrent);
m_vecLinks.push_back(NewGene);
}
else
{
//the innovation has already been created so all we need to
//do is create the new gene using the existing innovation ID
SLinkGene NewGene(ID_neuron1,
ID_neuron2,
true,
id,
RandomClamped(),
bRecurrent);
m_vecLinks.push_back(NewGene);
}
return;
}
//---------------------------------AddNeuron------------------------------
//
// this function adds a neuron to the genotype by examining the network,
// splitting one of the links and inserting the new neuron.
//------------------------------------------------------------------------
void CGenome::AddNeuron(double MutationRate,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -