//-------------------------------CreatePhenotype-------------------------- // // Creates a neural network based upon the information in the genome. // Returns a pointer to the newly created ANN //------------------------------------------------------------------------ CNeuralNet* CGenome::CreatePhenotype() { //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, m_iNetDepth); return m_pPhenotype; }
bool BContainer::DeleteChildren(BItem* currentProperty) { BItem* el; UINT parentOffset = 0; int i; i = GetElementPos(currentProperty); if(i < 0) return false; //am gasit elementul, vad daca are copii int j = i+1; parentOffset = currentProperty->offset; while(j<vElements.GetSize()) { el = (BItem*)vElements.GetPointer(j); if(el->offset > parentOffset) { el->ShowWindow(SW_HIDE); vElements.Delete(j); } else break; } el = GetElement(i); el->collapsed = ITEM_NO_COLLAPSE; return true; }
bool BContainer::MoveElement(BItem* el, unsigned int newPos) { BItem* oldParent,*newParent; BItem* nextEl; bool foundChild = false; int i = GetElementPos(el); if( i>= newPos) i+=1; if(!vElements.Insert(&el,newPos)) return false; //verifica daca vechiul parinte mai are copii oldParent = GetParent(i); if(vElements.Delete(i)==false) return false; //verific daca vechiul parinte mai are copii pentru a-i seta starea de collapse if(oldParent == NULL) return true; if( i <vElements.GetSize()) { nextEl = (BItem*)vElements.GetPointer(i); if(nextEl->offset > oldParent->offset) foundChild = true; else foundChild = false; } if(!foundChild) oldParent->collapsed = ITEM_NO_COLLAPSE; else oldParent->collapsed = ITEM_COLLAPSED; //verific daca in urma introducerii elementului a aparut un parinte pentru noul element newParent = GetParent(newPos); if(newParent != NULL) newParent->collapsed = ITEM_COLLAPSED; return true; }
bool BContainer::DeleteElement(BItem* currentProperty) { BItem* el; BItem* parent; UINT parentOffset = 0; int i; i = GetElementPos(currentProperty); if(i < 0) return false; int j = i+1; parentOffset = currentProperty->offset; while(j<vElements.GetSize()) { el = (BItem*)vElements.GetPointer(j); if(el->offset > parentOffset) { el->ShowWindow(SW_HIDE); vElements.Delete(j); } else break; } el = (BItem*)vElements.GetPointer(i); el->ShowWindow(SW_HIDE); parent = this->GetParent(i); vElements.Delete(i); if(!HasChildren(parent)) parent->collapsed = ITEM_NO_COLLAPSE; return true; }
/// \brief /// Indicates whether the passed handler is registered to this callback /// /// \param pHandler /// A handler to test /// /// \return /// \c TRUE if handler is registered in this callback; \c FALSE if not /// /// \sa VCallback::RegisterCallback /// \sa VCallback::TriggerCallbacks /// \sa class IVisCallbackHandler_cl inline BOOL IsRegistered(IVisCallbackHandler_cl *pHandler) {VASSERT(pHandler);return GetElementPos(pHandler)>=0;}
//---------------------------------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, CInnovation &innovations, int NumTrysToFindOldLink) { //just return dependent on mutation rate if (RandFloat() > MutationRate) return; //if a valid link is found into which to insert the new neuron //this value is set to true. bool bDone = false; //this will hold the index into m_vecLinks of the chosen link gene int ChosenLink = 0; //first a link is chosen to split. If the genome is small the code makes //sure one of the older links is split to ensure a chaining effect does //not occur. Here, if the genome contains less than 5 hidden neurons it //is considered to be too small to select a link at random const int SizeThreshold = m_iNumInputs + m_iNumOutPuts + 10; if (m_vecLinks.size() < SizeThreshold) { while(NumTrysToFindOldLink--) { //choose a link with a bias towards the older links in the genome ChosenLink = RandInt(0, NumGenes()-1-(int)sqrt((double)NumGenes())); //make sure the link is enabled and that it is not a recurrent link //or has a bias input int FromNeuron = m_vecLinks[ChosenLink].FromNeuron; if ( (m_vecLinks[ChosenLink].bEnabled) && (!m_vecLinks[ChosenLink].bRecurrent) && (m_vecNeurons[GetElementPos(FromNeuron)].NeuronType != bias)) { bDone = true; NumTrysToFindOldLink = 0; } } if (!bDone) { //failed to find a decent link return; } } else { //the genome is of sufficient size for any link to be acceptable while (!bDone) { ChosenLink = RandInt(0, NumGenes()-1); //make sure the link is enabled and that it is not a recurrent link //or has a BIAS input int FromNeuron = m_vecLinks[ChosenLink].FromNeuron; if ( (m_vecLinks[ChosenLink].bEnabled) && (!m_vecLinks[ChosenLink].bRecurrent) && (m_vecNeurons[GetElementPos(FromNeuron)].NeuronType != bias)) { bDone = true; } } } // Get the type of the neuron to add - hidden or modulatory neuron_type type = hidden; if (CParams::bAdaptable && RandFloat() < CParams::dModulatoryChance) { type = modulatory; } //disable this gene m_vecLinks[ChosenLink].bEnabled = false; //grab the weight from the gene (we want to use this for the weight of //one of the new links so that the split does not disturb anything the //NN may have already learned... double OriginalWeight = m_vecLinks[ChosenLink].dWeight; //identify the neurons this link connects int from = m_vecLinks[ChosenLink].FromNeuron; int to = m_vecLinks[ChosenLink].ToNeuron; //calculate the depth and width of the new neuron. We can use the depth //to see if the link feeds backwards or forwards double NewDepth = (m_vecNeurons[GetElementPos(from)].dSplitY + m_vecNeurons[GetElementPos(to)].dSplitY) /2; double NewWidth = (m_vecNeurons[GetElementPos(from)].dSplitX + m_vecNeurons[GetElementPos(to)].dSplitX) /2; //Now to see if this innovation has been created previously by //another member of the population int id = innovations.CheckInnovation(from, to, new_neuron); /*it is possible for NEAT to repeatedly do the following: 1. Find a link. Lets say we choose link 1 to 5 2. Disable the link, 3. Add a new neuron and two new links 4. The link disabled in Step 2 may be re-enabled when this genome is recombined with a genome that has that link enabled. 5 etc etc Therefore, this function must check to see if a neuron ID is already being used. If it is then the function creates a new innovation for the neuron. */ if (id >= 0) { int NeuronID = innovations.GetNeuronID(id); if (AlreadyHaveThisNeuronID(NeuronID)) { id = -1; } } if (id < 0) { //add the innovation for the new neuron int NewNeuronID = innovations.CreateNewInnovation(from, to, new_neuron, type, NewWidth, NewDepth); //create the new neuron gene and add it. m_vecNeurons.push_back(SNeuronGene(type, NewNeuronID, NewDepth, NewWidth)); //Two new link innovations are required, one for each of the //new links created when this gene is split. //-----------------------------------first link //get the next innovation ID int idLink1 = innovations.NextNumber(); //create the new innovation innovations.CreateNewInnovation(from, NewNeuronID, new_link); //create the new link gene SLinkGene link1(from, NewNeuronID, true, idLink1, 1.0); m_vecLinks.push_back(link1); //-----------------------------------second link //get the next innovation ID int idLink2 = innovations.NextNumber(); //create the new innovation innovations.CreateNewInnovation(NewNeuronID, to, new_link); //create the new gene SLinkGene link2(NewNeuronID, to, true, idLink2, OriginalWeight); m_vecLinks.push_back(link2); } else { //this innovation has already been created so grab the relevant neuron //and link info from the innovation database int NewNeuronID = innovations.GetNeuronID(id); //get the innovation IDs for the two new link genes. int idLink1 = innovations.CheckInnovation(from, NewNeuronID, new_link); int idLink2 = innovations.CheckInnovation(NewNeuronID, to, new_link); //this should never happen because the innovations *should* have already //occurred if ( (idLink1 < 0) || (idLink2 < 0) ) { MessageBox(NULL, "Error in CGenome::AddNeuron", "Problem!", MB_OK); return; } //now we need to create 2 new genes to represent the new links SLinkGene link1(from, NewNeuronID, true, idLink1, 1.0); SLinkGene link2(NewNeuronID, to, true, idLink2, OriginalWeight); m_vecLinks.push_back(link1); m_vecLinks.push_back(link2); //create the new neuron SNeuronGene NewNeuron(type, NewNeuronID, NewDepth, NewWidth); //and add it m_vecNeurons.push_back(NewNeuron); } return; }
//--------------------------------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)) { ID_neuron1 = -1; ID_neuron2 = -1; } else { NumTrysToAddLink = 0; } } } //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; }