/* * Open BEAGLE * Copyright (C) 2001-2005 by Christian Gagne and Marc Parizeau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: * Laboratoire de Vision et Systemes Numeriques * Departement de genie electrique et de genie informatique * Universite Laval, Quebec, Canada, G1K 7P4 * http://vision.gel.ulaval.ca * */ /*! * \file beagle/GP/src/Invoker.cpp * \brief Implementation of GP::Invoker. * \author Christian Gagne * \author Matthew Walker * $Revision: 1.9 $ * $Date: 2005/10/04 16:25:10 $ */ #include "beagle/GP.hpp" using namespace Beagle; /*! * \brief Construct a new Invoker primitive. * \param inIndex Index of the associated tree. * \param inNumberArgs Number of arguments of the Invoker. * \param inName Name of the Invoker primitive. * \param inArgsName Name of the associated argument primitive. */ GP::Invoker::Invoker(unsigned int inIndex, unsigned int inNumberArgs, Beagle::string inName, Beagle::string inArgsName) : GP::Primitive(inNumberArgs, inName), mArgsName(inArgsName), mIndex(inIndex) { } #ifdef BEAGLE_HAVE_RTTI /*! * \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 instanciated, 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().c_str()); } GP::Tree::Handle lTree = getInvokedTree(ioContext); GP::Tree::Handle lOldTreeHandle = ioContext.getGenotypeHandle(); ioContext.setGenotypeHandle(lTree); GP::Argument::Handle lArg = castHandleT(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 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"); } #endif // BEAGLE_HAVE_RTTI /*! * \brief Return selection weight (in primitive set) of the ADF primitive. * \param inNumberArguments Number of arguments called for the selection weight. * \param ioContext Evolutionary context. * \return Selection weight. */ double GP::Invoker::getSelectionWeight(unsigned int inNumberArguments, GP::Context& ioContext) const { Beagle_StackTraceBeginM(); // If not a generator, return the default primitive weight value. if(mIndex!=eGenerator) return Beagle::GP::Primitive::getSelectionWeight(inNumberArguments, ioContext); // Get the number of possibles trees that can be invoked in the actual context. std::vector< unsigned int,BEAGLE_STLALLOCATOR > lCandidates; getCandidatesToInvoke(lCandidates, inNumberArguments, ioContext); return double(lCandidates.size()); Beagle_StackTraceEndM("double GP::Invoker::getSelectionWeight(unsigned int inNumberArguments, GP::Context& ioContext) const"); } /*! * \brief Return a reference of the ADF primitive. * \param inNumberArguments Number of arguments asked for the reference. * \param ioContext Evolutionary context. * \return Handle to the reference generated. */ GP::Primitive::Handle GP::Invoker::giveReference(unsigned int inNumberArguments, GP::Context& ioContext) { Beagle_StackTraceBeginM(); // If not an invoker, return this directly. if(mIndex!=eGenerator) return this; // Generate new invoker. std::vector< unsigned int,BEAGLE_STLALLOCATOR > lCandidates; getCandidatesToInvoke(lCandidates, inNumberArguments, ioContext); Beagle_AssertM(lCandidates.size() > 0); const unsigned int lIndex = lCandidates[ioContext.getSystem().getRandomizer().rollInteger(0,lCandidates.size()-1)]; Handle lGeneratedInvoker = generateInvoker(lIndex, getName(), mArgsName, ioContext); // Return newly generated invoker. return lGeneratedInvoker; Beagle_StackTraceEndM("GP::Primitive::Handle GP::Invoker::giveReference(unsigned int inNumberArguments, GP::Context& ioContext)"); } /*! * \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()); GP::Argument::Handle lArg = castHandleT(lTree->getPrimitiveSet(ioContext).getPrimitiveByName(mArgsName)); if(lArg==NULL) { 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 whether selection weight in primitive set is stable. * \param inNumberArguments Number of arguments for given selection weight. * \return True is selection weight stable, false if not. */ bool GP::Invoker::isSelectionWeightStable(unsigned int inNumberArguments) const { Beagle_StackTraceBeginM(); const unsigned int lNbArgsPrimit = getNumberArguments(); if((inNumberArguments == GP::Primitive::eAny) || (lNbArgsPrimit == GP::Primitive::eAny)) return false; else if(inNumberArguments == GP::Primitive::eBranch) { return (lNbArgsPrimit == 0); } return (lNbArgsPrimit == inNumberArguments); Beagle_StackTraceEndM("bool GP::Invoker::isSelectionWeightStable(unsigned int inNumberArguments) const"); } /*! * \brief Read invoker primitive from XML subtree. * \param inIter XML iterator to read the primitive from. * \param ioContext Evolutionary context. */ void GP::Invoker::readWithContext(PACC::XML::ConstIterator inIter, GP::Context& ioContext) { Beagle_StackTraceBeginM(); GP::Primitive::readWithContext(inIter, ioContext); string lIndexValue = inIter->getAttribute("id").c_str(); if(lIndexValue.empty()==false) mIndex = str2uint(lIndexValue); unsigned int lArgsCount = 0; for(PACC::XML::ConstIterator lChild=inIter->getFirstChild(); lChild; ++lChild) { if(lChild->getType()==PACC::XML::eData) ++lArgsCount; } setNumberArguments(lArgsCount); Beagle_StackTraceEndM("void GP::Invoker::readWithContext(PACC::XML::ConstIterator inIter, GP::Context& ioContext)"); } /*! * \brief Validate the invoker position in the tree. * \param ioContext Evolutionary context. * \return True if the invoker is correctly positioned, false if not. * \throw Beagle::AssertException If the context is in a bad state. */ bool GP::Invoker::validate(GP::Context& ioContext) const { Beagle_StackTraceBeginM(); std::vector > lCandidates; getCandidatesToInvoke(lCandidates, getNumberArguments(), ioContext); for(unsigned int i=0; i