/*! * \brief Validate the GP individual. * \param ioContext Evolutionary context. * \return True if the GP individual is valid, false if not. */ bool GP::Individual::validate(GP::Context& ioContext) { Beagle_StackTraceBeginM(); bool lResult = true; Beagle_LogDetailedM( ioContext.getSystem().getLogger(), std::string("Validating ")+uint2ordinal(ioContext.getIndividualIndex()+1)+ std::string(" individual") ); // Store original values. GP::Tree::Handle lOldTreeHandle = ioContext.getGenotypeHandle(); unsigned int lOldTreeIndex = ioContext.getGenotypeIndex(); // Loop through each of the trees in the individual for (unsigned int i=0; i<size(); i++) { GP::Tree::Handle lTree = (*this)[i]; if (lTree == NULL) { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), std::string("Skipping ")+uint2ordinal(i+1)+std::string(" tree because it's NULL-valued") ); continue; } Beagle_LogVerboseM( ioContext.getSystem().getLogger(), std::string("Validating ")+uint2ordinal(i+1)+std::string(" tree") ); // Store the new values ioContext.setGenotypeHandle(lTree); ioContext.setGenotypeIndex(i); lTree->setContextToNode(0, ioContext); if(!lTree->validateSubTree(0, ioContext)) { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), std::string("Validation of ")+uint2ordinal(i+1)+std::string(" tree failed.") ); lResult = false; break; } } if(lResult) { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), std::string("Individual passed validation testing.") ); } // Restore the original values. ioContext.setGenotypeHandle(lOldTreeHandle); ioContext.setGenotypeIndex(lOldTreeIndex); return lResult; Beagle_StackTraceEndM(); }
/*! * \brief Generate a new ADF primitive from the given specifications. * \param inIndex Tree index for which the primitive is created. * \param inName Name of the primitive generated. * \param inArgsName Name of the arguments associated to the invoker created. * \param ioContext Evolutionary context. */ GP::Invoker::Handle GP::ADF::generateInvoker(unsigned int inIndex, std::string inName, std::string inArgsName, GP::Context& ioContext) const { Beagle_StackTraceBeginM(); if(inIndex == UINT_MAX) { Beagle_LogDebugM( ioContext.getSystem().getLogger(), "primitive selection","Beagle::GP::ADF::generateInvoker", "Generated ADF with UINT_MAX" ); return new GP::ADF(UINT_MAX, UINT_MAX, inName, inArgsName); } else { GP::Tree::Handle lTree = ioContext.getIndividual()[inIndex]; Beagle_LogDebugM( ioContext.getSystem().getLogger(), "primitive selection","Beagle::GP::ADF::generateInvoker", std::string("Generated ADF with index ")+uint2str(inIndex)+" ("+uint2str(lTree->getNumberArguments())+" args)" ); return new GP::ADF(inIndex, lTree->getNumberArguments(), inName, inArgsName); } Beagle_StackTraceEndM("GP::Invoker::Handle GP::ADF::generateInvoker(unsigned int inIndex, string inName, string inArgsName, GP::Context& ioContext) const"); }
/*! * \brief Execute the call to the associated tree with the given parameters. * \param outResult Result of the invocation. * \param ioContext Evolutionary context. */ void GP::Invoker::execute(GP::Datum& outResult, GP::Context& ioContext) { Beagle_StackTraceBeginM(); GP::Tree::Handle lTree = getInvokedTree(ioContext); Beagle_AssertM(lTree->getNumberArguments() == getNumberArguments()); if(getNumberArguments() == 0) { invoke(outResult, lTree, ioContext); } else { GP::Argument::Handle lArg = castHandleT<GP::Argument>(lTree->getPrimitiveSet(ioContext).getPrimitiveByName(mArgsName)); if(lArg==NULL) { std::string lMessage = "The argument named '"; lMessage += mArgsName; lMessage += " associated to the invoker named '"; lMessage += getName(); lMessage += "' does not refer to a valid primitive in the set"; lMessage += " of the tree associated to the invoker."; throw Beagle_RunTimeExceptionM(lMessage); } lArg->pushExecutionContext(getNumberArguments(), ioContext); invoke(outResult, lTree, ioContext); lArg->popExecutionContext(); } Beagle_StackTraceEndM("void GP::Invoker::execute(GP::Datum& outResult, GP::Context& ioContext)"); }
/*! * \brief Return the string tagging the type of data returned by the primitive. * \param ioContext Evolutionary context. * \return String tagging the type of data returned. * \throw InternalException If RTTI is disabled and the method is not properly overdefined. */ const std::type_info* GP::Invoker::getReturnType(GP::Context& ioContext) const { Beagle_StackTraceBeginM(); if(mIndex == eGenerator) return NULL; GP::Tree::Handle lTree = getInvokedTree(ioContext); GP::Tree::Handle lOldTreeHandle = ioContext.getGenotypeHandle(); const unsigned int lOldTreeIndex = ioContext.getGenotypeIndex(); ioContext.setGenotypeHandle(lTree); ioContext.setGenotypeIndex(mIndex); const std::type_info* lReturnType = lTree->getRootType(ioContext); ioContext.setGenotypeIndex(lOldTreeIndex); ioContext.setGenotypeHandle(lOldTreeHandle); return lReturnType; Beagle_StackTraceEndM("const std::type_info* GP::Invoker::getArgType(unsigned int inN, GP::Context& ioContext) const"); }
/*! * \brief Return indices of the trees that can be invoked by the ADF. * \param outCandidates Indices of tree that can be selected as invokable in the actual context. * \param inNumberArguments Number of arguments for which the selection is desired. * \param ioContext Evolutionary context. */ void GP::ADF::getCandidatesToInvoke(std::vector<unsigned int>& outCandidates, unsigned int inNumberArguments, GP::Context& ioContext) const { Beagle_StackTraceBeginM(); outCandidates.clear(); for(unsigned int i=(ioContext.getGenotypeIndex()+1); i<ioContext.getIndividual().size(); ++i) { GP::Tree::Handle lTree = castHandleT<GP::Tree>(ioContext.getIndividual()[i]); const unsigned int lNbArgsTree = lTree->getNumberArguments(); if(inNumberArguments == GP::Primitive::eAny) outCandidates.push_back(i); else if((inNumberArguments == GP::Primitive::eBranch) && (lNbArgsTree>0)) outCandidates.push_back(i); else if(inNumberArguments == lNbArgsTree) outCandidates.push_back(i); } Beagle_StackTraceEndM("void GP::ADF::getCandidatesToInvoke(std::vector<unsigned int>& outCandidates, unsigned int inNumberArguments, GP::Context& ioContext) const"); }
/*! * \brief Generate a new Module primitive from the given specifications. * \param inIndex Tree index for which the primitive is created. * \param inName Name of the primitive generated. * \param inArgsName Name of the arguments associated to the invoker created. * \param ioContext Evolutionary context. */ GP::Invoker::Handle GP::Module::generateInvoker(unsigned int inIndex, std::string inName, std::string inArgsName, GP::Context& ioContext) const { Beagle_StackTraceBeginM(); Component::Handle lComponent = ioContext.getSystem().getComponent("ModuleVector"); GP::ModuleVectorComponent::Handle lModVector = castHandleT<GP::ModuleVectorComponent>(lComponent); if(lModVector==NULL) { throw Beagle_RunTimeExceptionM(std::string("GP system is not configured with a module vector. ")+ std::string("Consider adding a GP::ModuleVectorComponent object to the system.")); } GP::Tree::Handle lTree = (*lModVector)[inIndex]; Beagle_AssertM(lTree != NULL); return new GP::Module(inIndex, lTree->getNumberArguments(), inName, inArgsName); Beagle_StackTraceEndM(); }
/*! * \brief Return the tag of the type of data needed as input for the primitive. * \param inN Index of the argument to get the type tag. * \param ioContext Evolutionary context. * \return String tagging the data type needed. * \throw AssertException If the index inN given is > to 1. * \throw InternalException If RTTI is disabled and the method is not properly overdefined. */ const std::type_info* GP::Invoker::getArgType(unsigned int inN, GP::Context& ioContext) const { Beagle_StackTraceBeginM(); Beagle_AssertM(inN < getNumberArguments()); if(mIndex == eGenerator) { std::ostringstream lOSS; lOSS << "Could not get the arguments typing of the '" << getName() << "' invoker primitive. "; lOSS << "The primitive is actually in a generator state, so the index of the tree "; lOSS << "refered by the primitive is not specified. It is likely that there is a problem "; lOSS << "in the setting of your system, as the argument typing is called only when the "; lOSS << "primitive is completely instantiated, that is used as the part of a GP tree, "; lOSS << "with an index value refering to another GP tree to invoke."; throw Beagle_RunTimeExceptionM(lOSS.str()); } GP::Tree::Handle lTree = getInvokedTree(ioContext); GP::Tree::Handle lOldTreeHandle = ioContext.getGenotypeHandle(); ioContext.setGenotypeHandle(lTree); GP::Argument::Handle lArg = castHandleT<GP::Argument>(lTree->getPrimitiveSet(ioContext).getPrimitiveByName(mArgsName)); const std::type_info* lArgType = lArg->getReturnType(ioContext); ioContext.setGenotypeHandle(lOldTreeHandle); return lArgType; Beagle_StackTraceEndM("const std::type_info* GP::Invoker::getArgType(unsigned int inN, GP::Context& ioContext) const"); }
/*! * \brief Expand given module of a GP tree. * \param inNodeToExpand Index of node to expand in GP tree. * \param ioTree Tree from which module will be expanded. * \param ioContext Evolutionary context. */ void GP::ModuleExpandOp::expand(unsigned int inNodeToExpand, GP::Tree& ioTree, GP::Context& ioContext) { Beagle_StackTraceBeginM(); // Log tree before expansion. Beagle_LogDebugM( ioContext.getSystem().getLogger(), "Tree before expansion" ); Beagle_LogDebugM( ioContext.getSystem().getLogger(), ioTree ); // Get the module index and reference. Module::Handle lModuleInstance = castHandleT<Module>(ioTree[inNodeToExpand].mPrimitive); unsigned int lModuleIndex = lModuleInstance->getIndex(); Beagle_LogVerboseM( ioContext.getSystem().getLogger(), std::string("Expanding ")+uint2ordinal(lModuleIndex+1)+ std::string(" module (called from ")+uint2ordinal(inNodeToExpand+1)+ std::string(" node of the tree)") ); ModuleVectorComponent::Handle lModuleVectorComponent = castHandleT<ModuleVectorComponent>(ioContext.getSystem().getComponent("ModuleVector")); if(lModuleVectorComponent==NULL) { throw Beagle_RunTimeExceptionM(std::string("GP system is not configured with a module vector. ")+ std::string("Consider adding a GP::ModuleVectorComponent object to the system.")); } Beagle::GP::Tree::Handle lModule = (*lModuleVectorComponent)[lModuleIndex]; Beagle_LogDebugM( ioContext.getSystem().getLogger(), *lModule ); // Generate new tree. const Factory& lFactory = ioContext.getSystem().getFactory(); GP::Tree::Alloc::Handle lTreeAlloc = castHandleT<GP::Tree::Alloc>(lFactory.getConceptAllocator("Genotype")); GP::Tree::Handle lNewTree = castHandleT<GP::Tree>(lTreeAlloc->allocate()); std::string lArgName = lModuleInstance->getArgsName(); ioTree.setContextToNode(inNodeToExpand, ioContext); for(unsigned int i=0; i<lModule->size(); ++i) { if((*lModule)[i].mPrimitive->getName() != lArgName) { lNewTree->push_back(GP::Node((*lModule)[i].mPrimitive)); } else { GP::Argument::Handle lArg = castHandleT<GP::Argument>((*lModule)[i].mPrimitive); const unsigned int lChildIndex = ioTree[inNodeToExpand].mPrimitive->getChildrenNodeIndex(lArg->getIndex(), ioContext); lNewTree->insert(lNewTree->end(), ioTree.begin()+lChildIndex, ioTree.begin()+lChildIndex+ioTree[lChildIndex].mSubTreeSize); } } ioTree.erase(ioTree.begin()+inNodeToExpand, ioTree.begin()+inNodeToExpand+ioTree[inNodeToExpand].mSubTreeSize); ioTree.insert(ioTree.begin()+inNodeToExpand, lNewTree->begin(), lNewTree->end()); ioTree.fixSubTreeSize(); // Log results. Beagle_LogDebugM( ioContext.getSystem().getLogger(), "Tree after expansion" ); Beagle_LogDebugM( ioContext.getSystem().getLogger(), ioTree ); Beagle_StackTraceEndM(); }
/*! * \brief Standard mutate a constrained GP individual. * \param ioIndividual GP individual to standard mutate. * \param ioContext Context of the evolution. * \return True if the individual is effectively mutated, false if not. */ bool GP::MutationStandardSelectiveConstrainedOp::mutate(Beagle::Individual& ioIndividual, Beagle::Context& ioContext) { Beagle_StackTraceBeginM(); GP::Individual& lIndividual = castObjectT<GP::Individual&>(ioIndividual); GP::Context& lContext = castObjectT<GP::Context&>(ioContext); unsigned int lMaxTreeDepth = mMaxTreeDepth->getWrappedValue(); unsigned int lMaxRegenerationDepth = mMaxRegenerationDepth->getWrappedValue(); //Select node to mutate unsigned int lChoosenTree = 0; unsigned int lChoosenNode = 0; bool lDoParameterSearch = (lContext.getSystem().getRandomizer().rollUniform(0.0, 1.0) <= mMutParameterPb->getWrappedValue()); //Select primitive based on type for(unsigned int lTry = 0; lTry < 2; ++lTry) { //Do only twice std::vector<const std::type_info*> lDesiredTypes(1, ArgEph); RouletteT< std::pair<unsigned int,unsigned int> > lRoulette; SelectiveConstrainedSelectionOp::buildRoulette(lRoulette, lDesiredTypes, lIndividual, lContext,!lDoParameterSearch,lDoParameterSearch); if(lRoulette.size() == 0) { if(lDoParameterSearch) { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", string("No EphemeralDouble node found.") ); } else { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", string("No non EphemeralDouble node found.") ); } lDoParameterSearch = !lDoParameterSearch; if(lTry >= 1) { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", "Unable to GP standard mutate the individual" ); return false; } } else { std::pair<unsigned int,unsigned int> lSelectedNode = lRoulette.select(ioContext.getSystem().getRandomizer()); lChoosenTree = lSelectedNode.first; lChoosenNode = lSelectedNode.second; break; } } if(lDoParameterSearch) { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", string("Mutation applied only on EphemeralDouble node.") ); } else { Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", string("Mutation applied on node that are not EphemeralDouble.") ); } unsigned int lOldGenotypeIndex = lContext.getGenotypeIndex(); GP::Tree::Handle lOldGenotypeHandle = lContext.getGenotypeHandle(); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", std::string("Individual before GP standard mutation: ")+ ioIndividual.serialize() ); GP::Tree::Handle lActualTree = lIndividual[lChoosenTree]; GP::Tree::Handle lNewTree = castHandleT<GP::Tree>(lIndividual.getTypeAlloc()->allocate()); lNewTree->setPrimitiveSetIndex(lActualTree->getPrimitiveSetIndex()); lNewTree->setNumberArguments(lActualTree->getNumberArguments()); unsigned int lChoosenNodeSubTreeSize = (*lActualTree)[lChoosenNode].mSubTreeSize; lNewTree->insert(lNewTree->end(), lActualTree->begin(), lActualTree->begin()+lChoosenNode); lContext.setGenotypeIndex(lChoosenTree); lContext.setGenotypeHandle(lActualTree); lContext.emptyCallStack(); lActualTree->setContextToNode(lChoosenNode, lContext); lContext.popCallStack(); const unsigned int lMaxSubTreeDepth = minOf<unsigned int>(lMaxTreeDepth - lContext.getCallStackSize(), lMaxRegenerationDepth); lIndividual[lChoosenTree] = lNewTree; lContext.setGenotypeHandle(lNewTree); unsigned int lAttempt=0; if(lMaxSubTreeDepth >= 1) { for(; lAttempt < mNumberAttempts->getWrappedValue(); lAttempt++) { if(mInitOp->initTree(*lNewTree, 1, lMaxSubTreeDepth, lContext) != 0) break; } } else { lAttempt = mNumberAttempts->getWrappedValue(); } if(lAttempt == mNumberAttempts->getWrappedValue()) { lIndividual[lChoosenTree] = lActualTree; lContext.setGenotypeIndex(lOldGenotypeIndex); lContext.setGenotypeHandle(lOldGenotypeHandle); Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", "Unable to GP standard mutate the individual" ); return false; } if( !lDoParameterSearch ) { //Set structure id invalid castHandleT<TreeSTag>((lIndividual)[0])->setStructureIDInvalid(); Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", std::string("Set structure id invalid") ); } Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", std::string("GP standard mutate the ")+uint2ordinal(lChoosenNode+1)+ std::string(" node, ")+ (*lActualTree)[lChoosenNode].mPrimitive->getName() +std::string(", of the ")+uint2ordinal(lChoosenTree+1)+ std::string(" tree with max depth ")+uint2str(lMaxSubTreeDepth) ); lNewTree->insert(lNewTree->end(), lActualTree->begin()+lChoosenNode+lChoosenNodeSubTreeSize, lActualTree->end()); unsigned int lDiffSize = (*lActualTree)[lChoosenNode].mSubTreeSize - (*lNewTree)[lChoosenNode].mSubTreeSize; for(unsigned int l=0; l<lContext.getCallStackSize(); l++) { (*lNewTree)[lContext.getCallStackElement(l)].mSubTreeSize -= lDiffSize; } lContext.setGenotypeIndex(lOldGenotypeIndex); lContext.setGenotypeHandle(lOldGenotypeHandle); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationStandardSelectiveConstrainedOp", std::string("Individual after GP standard mutation: ")+ ioIndividual.serialize() ); return true; Beagle_StackTraceEndM("bool GP::MutationStandardSelectiveConstrainedOp::mutate(Beagle::Individual& ioIndividual, Beagle::Context& ioContext)"); }
/*! * \brief Standard mutate a constrained GP individual. * \param ioIndividual GP individual to standard mutate. * \param ioContext Context of the evolution. * \return True if the individual is effectively mutated, false if not. */ bool STGP::MutationStandardConstrainedOp::mutate(Beagle::Individual& ioIndividual, Beagle::Context& ioContext) { Beagle_StackTraceBeginM(); GP::Individual& lIndividual = castObjectT<GP::Individual&>(ioIndividual); GP::Context& lContext = castObjectT<GP::Context&>(ioContext); unsigned int lMaxTreeDepth = mMaxTreeDepth->getWrappedValue(); unsigned int lMaxRegenerationDepth = mMaxRegenerationDepth->getWrappedValue(); unsigned int lNbNodes = 0; for(unsigned int i=0; i<lIndividual.size(); i++) lNbNodes += lIndividual[i]->size(); if(lNbNodes == 0) return false; unsigned int lChoosenNode = lContext.getSystem().getRandomizer().rollInteger(0, lNbNodes-1); unsigned int lChoosenTree = 0; for(; (lChoosenTree+1)<lIndividual.size(); lChoosenTree++) { if(lChoosenNode < lIndividual[lChoosenTree]->size()) break; else lChoosenNode -= lIndividual[lChoosenTree]->size(); } const Factory& lFactory = ioContext.getSystem().getFactory(); GP::Tree::Alloc::Handle lTreeAlloc = castHandleT<GP::Tree::Alloc>(lFactory.getConceptAllocator("Genotype")); unsigned int lOldGenotypeIndex = lContext.getGenotypeIndex(); GP::Tree::Handle lOldGenotypeHandle = lContext.getGenotypeHandle(); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "Individual before GP standard mutation" ); Beagle_LogDebugM( ioContext.getSystem().getLogger(), ioIndividual ); GP::Tree::Handle lActualTree = lIndividual[lChoosenTree]; GP::Tree::Handle lNewTree = castHandleT<GP::Tree>(lTreeAlloc->allocate()); lNewTree->setPrimitiveSetIndex(lActualTree->getPrimitiveSetIndex()); lNewTree->setNumberArguments(lActualTree->getNumberArguments()); unsigned int lChoosenNodeSubTreeSize = (*lActualTree)[lChoosenNode].mSubTreeSize; lNewTree->insert(lNewTree->end(), lActualTree->begin(), lActualTree->begin()+lChoosenNode); lContext.setGenotypeIndex(lChoosenTree); lContext.setGenotypeHandle(lActualTree); lContext.emptyCallStack(); lActualTree->setContextToNode(lChoosenNode, lContext); lContext.popCallStack(); const unsigned int lMaxSubTreeDepth = minOf<unsigned int>(lMaxTreeDepth - lContext.getCallStackSize(), lMaxRegenerationDepth); lIndividual[lChoosenTree] = lNewTree; lContext.setGenotypeHandle(lNewTree); unsigned int lAttempt=0; for(; lAttempt < mNumberAttempts->getWrappedValue(); lAttempt++) { if(mInitOp->initTree(*lNewTree, 1, lMaxSubTreeDepth, lContext) != 0) break; } if(lAttempt == mNumberAttempts->getWrappedValue()) { lIndividual[lChoosenTree] = lActualTree; lContext.setGenotypeIndex(lOldGenotypeIndex); lContext.setGenotypeHandle(lOldGenotypeHandle); Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "Unable to GP standard mutate the individual" ); return false; } Beagle_LogVerboseM( ioContext.getSystem().getLogger(), std::string("GP standard mutate the ")+uint2ordinal(lChoosenNode+1)+ std::string(" node of the ")+uint2ordinal(lChoosenTree+1)+ std::string(" tree with max depth ")+uint2str(lMaxSubTreeDepth) ); lNewTree->insert(lNewTree->end(), lActualTree->begin()+lChoosenNode+lChoosenNodeSubTreeSize, lActualTree->end()); unsigned int lDiffSize = (*lActualTree)[lChoosenNode].mSubTreeSize - (*lNewTree)[lChoosenNode].mSubTreeSize; for(unsigned int l=0; l<lContext.getCallStackSize(); l++) { (*lNewTree)[lContext.getCallStackElement(l)].mSubTreeSize -= lDiffSize; } lContext.setGenotypeIndex(lOldGenotypeIndex); lContext.setGenotypeHandle(lOldGenotypeHandle); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "Individual after GP standard mutation" ); Beagle_LogDebugM( ioContext.getSystem().getLogger(), ioIndividual ); return true; Beagle_StackTraceEndM(); }
/*! * \brief Insert mutate a GP individual. * \param ioIndividual GP individual to mutate. * \param ioContext Context of the evolution. * \return True if the individual is effectively mutated, false if not. */ bool GP::MutationInsertConstrainedOp::mutate(Beagle::Individual& ioIndividual, Beagle::Context& ioContext) { Beagle_StackTraceBeginM(); Beagle_LogDetailedM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Mutating individual with GP::MutationInsertConstrainedOp") ); GP::Individual& lIndividual = castObjectT<GP::Individual&>(ioIndividual); GP::Context& lContext = castObjectT<GP::Context&>(ioContext); const unsigned int lMaxAttempts = mNumberAttempts->getWrappedValue(); const unsigned int lMaxTreeDepth = mMaxTreeDepth->getWrappedValue(); const Factory& lFactory = ioContext.getSystem().getFactory(); GP::Tree::Alloc::Handle lTreeAlloc = castHandleT<GP::Tree::Alloc>(lFactory.getConceptAllocator("Genotype")); // Store original context values const unsigned int lOldGenotypeIndex = lContext.getGenotypeIndex(); const GP::Tree::Handle lOldGenotypeHandle = lContext.getGenotypeHandle(); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", "Individual before constrained GP insert mutation" ); Beagle_LogObjectDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", ioIndividual ); // Mutation attempts loop for(unsigned int i=0; i<lMaxAttempts; ++i) { // Choose tree and node to mutate const unsigned int lChosenTree = lIndividual.chooseRandomTree(lContext); const unsigned int lChosenNodeIndex = lIndividual.chooseRandomNode(lChosenTree, lContext); GP::Tree::Handle lOriginalTree = lIndividual[lChosenTree]; // Compute depth of tree generated by mutation lContext.setGenotypeIndex(lChosenTree); lContext.setGenotypeHandle(lOriginalTree); lContext.emptyCallStack(); lOriginalTree->setContextToNode(lChosenNodeIndex, lContext); const unsigned int lMutationDepth = lContext.getCallStackSize() + lOriginalTree->getTreeDepth(lChosenNodeIndex); // Check that mutation will not generate a tree deeper than the maximum allowed depth if(lMutationDepth > lMaxTreeDepth) { Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Constrained insert mutation attempt failed as the generated tree will exceed ")+ std::string("maximum allowed tree depth") ); continue; } // Create new tree Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Creating new tree") ); GP::Tree::Handle lNewTree = castHandleT<GP::Tree>(lTreeAlloc->allocate()); lNewTree->setPrimitiveSetIndex(lOriginalTree->getPrimitiveSetIndex()); lNewTree->setNumberArguments(lOriginalTree->getNumberArguments()); // Replace original tree with new tree lIndividual[lChosenTree] = lNewTree; lContext.setGenotypeHandle(lNewTree); // Copy unchanged part of original tree into new tree Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Copying unchanged part of original tree to new tree") ); lNewTree->insert(lNewTree->end(), lOriginalTree->begin(), lOriginalTree->begin()+lChosenNodeIndex); Beagle_AssertM(lNewTree->size() == lChosenNodeIndex); // Generate new branch primitive to insert. GP::PrimitiveSet& lPrimitiveSet = lNewTree->getPrimitiveSet(lContext); Primitive::Handle lBranchInserted = lPrimitiveSet.select(GP::Primitive::eBranch, lContext); if(lBranchInserted==NULL) { Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Constrained insert mutation attempt failed as it seems impossible ")+ std::string("to select a branch primitive in the actual context") ); lIndividual[lChosenTree] = lOriginalTree; lContext.setGenotypeHandle(lOriginalTree); continue; } Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Branch primitive to be inserted by mutation is primitive '")+ lBranchInserted->getName()+std::string("'") ); // Insert new branch lBranchInserted = lBranchInserted->giveReference(GP::Primitive::eBranch, lContext); lNewTree->push_back(Node(lBranchInserted,1)); if(lBranchInserted->validate(lContext) == false) { Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Constrained insert mutation attempt failed as the selected ")+ std::string("branch doesn't match the constraints") ); lIndividual[lChosenTree] = lOriginalTree; lContext.setGenotypeHandle(lOriginalTree); continue; } const unsigned int lNbArgsInsertedBranch = lBranchInserted->getNumberArguments(); Beagle_AssertM(lNbArgsInsertedBranch != 0); const unsigned int lSubtreeArgIndex = lContext.getSystem().getRandomizer().rollInteger(0, lNbArgsInsertedBranch-1); Beagle_AssertM(lSubtreeArgIndex < lNbArgsInsertedBranch); const unsigned int lSubtreeSize = (*lOriginalTree)[lChosenNodeIndex].mSubTreeSize; // Generate inserted node subtrees bool lArgsGenFailed = false; for(unsigned int j=0; j<lNbArgsInsertedBranch; ++j) { if(j == lSubtreeArgIndex) { const unsigned int lSubtreeIndex = lNewTree->size(); lNewTree->insert(lNewTree->end(), lOriginalTree->begin()+lChosenNodeIndex, lOriginalTree->begin()+lChosenNodeIndex+lSubtreeSize); lContext.pushCallStack(lSubtreeIndex); if(lNewTree->validateSubTree(lSubtreeIndex, lContext) == false) { lArgsGenFailed = true; break; } lContext.popCallStack(); (*lNewTree)[lChosenNodeIndex].mSubTreeSize += lSubtreeSize; } else { Primitive::Handle lArgInserted = lPrimitiveSet.select(GP::Primitive::eTerminal, lContext); if(lArgInserted == NULL) { lArgsGenFailed = true; break; } lArgInserted = lArgInserted->giveReference(GP::Primitive::eTerminal, lContext); const unsigned int lSubtreeIndex = lNewTree->size(); lNewTree->push_back(Node(lArgInserted,1)); lContext.pushCallStack(lSubtreeIndex); if(lArgInserted->validate(lContext) == false) { lArgsGenFailed = true; break; } lContext.popCallStack(); ++(*lNewTree)[lChosenNodeIndex].mSubTreeSize; } } if(lArgsGenFailed) { Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Constrained insert mutation attempt failed as it seems impossible ")+ std::string("to select a terminal primitive under the inserted branch in the actual context") ); lIndividual[lChosenTree] = lOriginalTree; lContext.setGenotypeHandle(lOriginalTree); continue; } // Complete new tree with rest of original tree Beagle_AssertM(lOriginalTree->size() >= (lChosenNodeIndex+lSubtreeSize)); lNewTree->insert(lNewTree->end(), lOriginalTree->begin()+lChosenNodeIndex+lSubtreeSize, lOriginalTree->end()); Beagle_AssertM(lNewTree->size() == (lOriginalTree->size()+lNbArgsInsertedBranch)); // Correct subtree size data and terminate mutation process Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("Correcting the 'mSubTreeSize' fields of tree") ); lContext.popCallStack(); for(unsigned int j=0; j<lContext.getCallStackSize(); ++j) { (*lNewTree)[lContext[j]].mSubTreeSize += lNbArgsInsertedBranch; } // Mutation successful, log messages and return std::ostringstream lOSS; lOSS << "Successfully inserted a new node at index " << lChosenNodeIndex; lOSS << " of the " << uint2ordinal(lChosenTree) << " tree of the actual individual"; Beagle_LogTraceM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", lOSS.str() ); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", "Individual after constrained GP insert mutation" ); Beagle_LogObjectDebugM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", ioIndividual ); lContext.emptyCallStack(); lContext.setGenotypeIndex(lOldGenotypeIndex); lContext.setGenotypeHandle(lOldGenotypeHandle); return true; } // Insert mutation failed, return without mutating the individual lContext.emptyCallStack(); lContext.setGenotypeIndex(lOldGenotypeIndex); lContext.setGenotypeHandle(lOldGenotypeHandle); Beagle_LogTraceM( ioContext.getSystem().getLogger(), "mutation", "Beagle::GP::MutationInsertConstrainedOp", std::string("All constrained insert mutation attempts failed; ")+ std::string("resuming from mutation without modifying the individual") ); return false; Beagle_StackTraceEndM("bool GP::MutationInsertConstrainedOp::mutate(Beagle::Individual& ioIndividual, Beagle::Context& ioContext)"); }