/* * 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/src/EvaluationMultipleOp.cpp * \brief Source code of class EvaluationMultipleOp. * \author Matthew Walker * $Revision: 1.12 $ * $Date: 2005/10/04 16:25:10 $ */ #include "beagle/Beagle.hpp" #include #include #include using namespace Beagle; /*! * \brief Construct a new multiple-individual evaluation operator. * \param inIndisPerCaseAndGroup Number of individuals per test cases and group. * \param inName Name of the operator. */ EvaluationMultipleOp::EvaluationMultipleOp(unsigned int inIndisPerCaseAndGroup, Beagle::string inName) : EvaluationOp(inName), mIndisPerCase(inIndisPerCaseAndGroup), mIndisPerGroup(inIndisPerCaseAndGroup) { } /*! * \brief Construct a new multiple-individual evaluation operator. * \param inIndisPerCase Number of individuals per test cases. * \param inIndisPerGroup Number of individuals per group. * \param inName Name of the operator. */ EvaluationMultipleOp::EvaluationMultipleOp(unsigned int inIndisPerCase, unsigned int inIndisPerGroup, Beagle::string inName) : EvaluationOp(inName), mIndisPerCase(inIndisPerCase), mIndisPerGroup(inIndisPerGroup) { } /*! * \brief Apply the evaluation operation on a breeding pool, returning a evaluated bred individual. * \param inBreedingPool Breeding pool to use for the breeding operation. * \param inChild Node handle associated to child node in the breeder tree. * \param ioContext Evolutionary context of the breeding operation. * \return Evaluated bred individual. */ Individual::Handle EvaluationMultipleOp::breed(Individual::Bag& inBreedingPool, BreederNode::Handle inChild, Context& ioContext) { Beagle_StackTraceBeginM(); throw Beagle_UndefinedMethodInternalExceptionM("EvaluationMultipleOp", "breed", getName()); return Individual::Handle(NULL); Beagle_StackTraceEndM("Individual::Handle EvaluationMultipleOp::breed(Individual::Bag& inBreedingPool, BreederNode::Handle inChild, Context& ioContext)"); } /*! * \brief Add individuals to the bag such that the total equals getIndisPerGroup(). * \param ioIndividuals Bag of individuals to evaluate. * \param ioContexts Bag of evolutionary context. * \return The number of individuals added to the bag. * * The new individuals are chosen from the current deme. */ unsigned int EvaluationMultipleOp::enlargeGroup(Individual::Bag& ioIndividuals, Context::Bag& ioContexts) { Beagle_StackTraceBeginM(); Context& lContext = castObjectT(*(ioContexts[0])); // Calculate the number of individuals to add unsigned int lNumToAdd = mIndisPerGroup - ioIndividuals.size(); Beagle_LogVerboseM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Adding ")+uint2str(lNumToAdd)+string(" individuals to the group (for padding)") ); // Resize the bags unsigned int lIndisCounter = ioIndividuals.size(); ioIndividuals.resize(mIndisPerGroup); ioContexts.resize(mIndisPerGroup); // Loop through all the individuals in the deme Deme& lDeme = lContext.getDeme(); std::vector< unsigned int,BEAGLE_STLALLOCATOR > lSelectableIndis; lSelectableIndis.resize(lDeme.size()); unsigned int lSelectableIndisCounter = 0; for (unsigned int i=0; i(lContext.getSystem().getContextAllocator().clone( *(ioContexts[0]) )); ioContexts[lIndisCounter]->setIndividualHandle( ioIndividuals[lIndisCounter] ); ioContexts[lIndisCounter]->setIndividualIndex( lIndiIndex ); lIndisCounter++; } Beagle_AssertM( lIndisCounter==ioIndividuals.size() ); return lNumToAdd; Beagle_StackTraceEndM("unsigned int EvaluationMultipleOp::enlargeGroup(Individual::Bag&,Context::Bag&)"); } /*! * \brief Evaluate the fitness of the given individual. * \param inIndividual Current individual to evaluate. * \param ioContext Evolutionary context. * \return Handle to the fitness value of the individual. * * This method evaluates only a single individual. For this * operator, it is much better to group individuals into a bag and * pass the bag to evaluate(Individual::Bag& ioIndividuals, Context::Bag& ioContexts). */ Fitness::Handle EvaluationMultipleOp::evaluate(Individual& inIndividual, Context& ioContext) { Beagle_StackTraceBeginM(); // Create a bag for the individual Individual::Bag lIndividuals; lIndividuals.resize(1); Beagle_AssertM(inIndividual == ioContext.getIndividual()); lIndividuals[0] = ioContext.getIndividualHandle(); // Create a context for the individual Context::Bag lContexts; lContexts.resize(1); lContexts[0] = castHandleT(ioContext.getSystem().getContextAllocator().clone( ioContext)); // Call evalutate() Fitness::Bag::Handle lFitnessBag = evaluateIndividuals(lIndividuals,lContexts); // Return fitness Beagle_AssertM( !lFitnessBag->empty() ); return lFitnessBag->at(0); Beagle_StackTraceEndM("Fitness::Handle EvaluationMultipleOp::evaluate(Individual&,Context&)"); } /*! * \brief Evaluate the fitness of the given bag of individuals. * \param ioIndividuals Bag of individuals to evaluate. * \param ioContexts Bag of evolutionary context. * \return Handle to a bag of fitness values, one for each individual. */ Fitness::Bag::Handle EvaluationMultipleOp::evaluateIndividuals(Individual::Bag& ioIndividuals, Context::Bag& ioContexts) { Beagle_StackTraceBeginM(); Beagle_AssertM(ioIndividuals.size()==ioContexts.size()); Beagle_AssertM(ioIndividuals.size()!=0); Context& lContext = castObjectT(*(ioContexts[0])); // Check if sufficient individuals are in the bag Beagle_AssertM( ioIndividuals.size() <= mIndisPerGroup ); unsigned int lNumToIgnore = 0; if (ioIndividuals.size() != mIndisPerGroup) { lNumToIgnore = enlargeGroup(ioIndividuals, ioContexts); } // Create bag of null-fitnesses Fitness::Bag::Handle lFitnessBagAll = new Fitness::Bag; lFitnessBagAll->resize( ioIndividuals.size() ); Beagle_NonNullPointerAssertM( lFitnessBagAll ); // Set up cases if (mCases == NULL) setupCases(ioIndividuals.size(),lContext); Case::Bag::Handle lCases = pruneIgnorableCases(lNumToIgnore); // Call evaluateCase for each case for (unsigned int i=0; isize(); i++) { Beagle_LogVerboseM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Evaluating the ")+uint2ordinal(i+1)+string(" case") ); Case& lCase = *(lCases->at(i)); Beagle_AssertM( lCase.mIndices.size() == mIndisPerCase ); // Setup bags of individuals and contexts Individual::Bag lIndividuals; Context::Bag lContexts; lIndividuals.resize( mIndisPerCase ); lContexts.resize( mIndisPerCase ); for (unsigned int j=0; jgetIndividualIndex()+1); } Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", uint2ordinal(i+1)+string(" case: ")+ lOSS.str().c_str() ); // Call evalutateCase() Fitness::Bag::Handle lFitnessBagCase = evaluateCase(lIndividuals, lContexts); // Log resulting fitnesses Beagle_NonNullPointerAssertM( lFitnessBagCase ); Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Evaluation of the case is complete. The fitnesses are as follows:") ); for (unsigned int j=0; jat(j) ); Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Fitness of the ")+ uint2ordinal(ioContexts[lCase.mIndices[j]]->getIndividualIndex()+1)+ string(" individual: ")+lFitnessBagCase->at(j)->serialize() ); // Need to assign fitness values from case to lFitnessBagAll unsigned int lIndex = lCase.mIndices[j]; Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Setting fitness for lFitnessBagAll at index ")+uint2str(lIndex) ); Beagle_AssertM(lIndex < lFitnessBagAll->size()); if (lFitnessBagAll->at(lIndex)==NULL) { (*lFitnessBagAll)[lIndex] = lFitnessBagCase->at(j); } else { combineFitnesses(lFitnessBagAll->at(lIndex), lFitnessBagCase->at(j) ); Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Fitness of the ")+uint2ordinal(ioContexts[lIndex]->getIndividualIndex()+1)+ string(" individual has been combined to: ")+lFitnessBagAll->at(lIndex)->serialize() ); } } } Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Evaluation of all cases is complete. Fitnesses are as follows:") ); for (unsigned int i=0; i=mIndisPerGroup-lNumToIgnore) { // Nullify ignorable individuals' fitness scores Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Ignoring fitness of the ")+uint2ordinal(ioContexts[i]->getIndividualIndex()+1)+ string(" individual") ); (*lFitnessBagAll)[i] = NULL; continue; } Beagle_NonNullPointerAssertM( lFitnessBagAll->at(i) ); Beagle_LogDebugM( lContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Fitness of the ")+uint2ordinal(ioContexts[i]->getIndividualIndex()+1)+ lFitnessBagAll->at(i)->serialize() ); } return lFitnessBagAll; Beagle_StackTraceEndM("Fitness::Bag::Handle EvaluationMultipleOp::evaluateIndividuals(Individual::Bag&,Context::Bag&)"); } /*! * \brief Apply the evaluation process on the invalid individuals of the deme. * \param ioDeme Deme to process. * \param ioContext Context of the evolution. */ void EvaluationMultipleOp::operate(Deme& ioDeme, Context& ioContext) { Beagle_StackTraceBeginM(); Beagle_LogTraceM( ioContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Evaluating the fitness of the individuals in the ")+ uint2ordinal(ioContext.getDemeIndex()+1)+" deme" ); Beagle_AssertM( ioDeme.size()!=0 ); // Prepare stats prepareStats(ioDeme,ioContext); // Generate a vector of indicies into the population std::vector< unsigned int,BEAGLE_STLALLOCATOR > lEvalVector; for(unsigned int i=0; igetFitness() == NULL) || (ioDeme[i]->getFitness()->isValid() == false)) { lEvalVector.push_back(i); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Added ")+uint2ordinal(i+1)+string(" individual for evaluation.") ); } } std::random_shuffle(lEvalVector.begin(), lEvalVector.end(), ioContext.getSystem().getRandomizer()); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("There are ")+uint2str(lEvalVector.size())+ string(" individuals to be evaluated.") ); while ( !lEvalVector.empty() ) { // Put individuals and context into bags. Individual::Bag lIndividuals; Context::Bag lContexts; lIndividuals.resize( mIndisPerGroup ); lContexts.resize( mIndisPerGroup ); unsigned int lIndiCounter =0; for (unsigned int i=0; i(ioContext.getSystem().getContextAllocator().clone(ioContext)); lContext->setIndividualIndex( lEvalVector.back() ); lContext->setIndividualHandle( ioDeme[lEvalVector.back()] ); lContexts[i] = lContext; // Remove this index from the evaluation vector lEvalVector.pop_back(); if(lEvalVector.empty()) { lIndividuals.resize( lIndiCounter ); lContexts.resize( lIndiCounter ); break; } } // Evaluate individuals std::ostringstream lOSS; for (unsigned int i=0; igetIndividualIndex()+1); if (igetIndividualIndex()+1)+string(" individual") ); Beagle_AssertM( i < lFitnessBag->size() ); Fitness::Handle lFitness = lFitnessBag->at(i); Beagle_NonNullPointerAssertM( lFitness ); lIndividuals[i]->setFitness( lFitness ); lIndividuals[i]->getFitness()->setValid(); Beagle_LogVerboseM( ioContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("The fitness of the ")+uint2ordinal(lContexts[i]->getIndividualIndex()+1)+ string(" individual is: ")+ lIndividuals[i]->getFitness()->serialize() ); } // Update stats updateStats(lIndividuals.size(),ioContext); } updateHallOfFameWithDeme(ioDeme,ioContext); Beagle_StackTraceEndM("void EvaluationMultipleOp::operate(Deme&,Context&)"); } /*! * \brief Removes cases that contain only references to individuals * that are acting a padding. * \param inNumToIgnore Number of individuals that have been added as padding. */ EvaluationMultipleOp::Case::Bag::Handle EvaluationMultipleOp::pruneIgnorableCases(unsigned int inNumToIgnore) { Beagle_StackTraceBeginM(); if (inNumToIgnore==0) return mCases; Case::Bag::Handle lCases = new Case::Bag; lCases->resize( mCases->size() ); unsigned int lCaseCounter = 0; // Check every case for (unsigned int i=0; isize(); i++) { // Check if any of the indices are not able to be ignored Case& lCase = *(mCases->at(i)); bool lAdd = false; for (unsigned int j=0; jresize(lCaseCounter); return lCases; Beagle_StackTraceEndM("EvaluationMultipleOp::Case::Bag::Handle EvaluationMultipleOp::pruneIgnorableCases(unsigned int)"); } /*! * \brief Sets up cases. * \param inSize Number of individuals in a group. * \param ioContext Context of the evolution. * * A case is a vector of indices into a bag of individuals. This * method creates cases. The number of cases is decided by inSize. * * For example, if inSize is 4 (set by setIndisPerGroup), then the * indices will range from 0 to 3. If each case contains just two * individuals (as set by setIndisPerCase) then the cases will be: * (0,1) (0,2) (0,3) * (1,2) (1,3) * (2,3) * Where (x,y) dictates a case when individual x will compete against * indiviudal y. */ void EvaluationMultipleOp::setupCases(unsigned int inSize, Context& ioContext) { Beagle_StackTraceBeginM(); Beagle_LogDebugM( ioContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", string("Creating evaluation cases") ); Beagle_AssertM(inSize >= mIndisPerCase); Beagle_AssertM(inSize == mIndisPerGroup); // Create cases with each case containing one individual mCases = new Case::Bag; Beagle_NonNullPointerAssertM( mCases ); for (unsigned int i=0; imIndices.push_back( i ); setupCaseRecursive(inSize,i,lCase); } // Log cases Beagle_LogDebugM( ioContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", uint2str(mCases->size())+string(" evaluation cases were created") ); for (unsigned int i=0; isize(); i++) { std::ostringstream lOSS; for (unsigned int j=0; jat(i)->mIndices.size(); j++) { if (j!=0) lOSS << ", "; lOSS << mCases->at(i)->mIndices[j]; } Beagle_LogDebugM( ioContext.getSystem().getLogger(), "evaluation", "Beagle::EvaluationMultipleOp", uint2ordinal(i+1)+string(" case: ")+ lOSS.str().c_str() ); } Beagle_StackTraceEndM("void EvaluationMultipleOp::setupCases(unsigned int,Context&)"); } /*! * \brief Sets up cases by adding one more individual into a clone of * inCase, and then calling this method for each one of those cases. * \param inSize Number of individuals in a group. * \param inLastIndex The index of the last individual that was * inserted into the case. * \param inCase The case on which to work. */ void EvaluationMultipleOp::setupCaseRecursive(unsigned int inSize, unsigned int inLastIndex, Case::Handle inCase) { using namespace std; Beagle_StackTraceBeginM(); unsigned int lCaseSize = inCase->mIndices.size(); // Check if the case is finished. if (lCaseSize == mIndisPerCase) { unsigned int lSize = mCases->size(); mCases->resize( lSize + 1 ); (*mCases)[lSize]=inCase; return; } // Case isn't finished, add another individual to it. Beagle_AssertM( lCaseSizemIndices.push_back(i); setupCaseRecursive(inSize,i,lNewCase); } Beagle_StackTraceEndM("void EvaluationMultipleOp::setupCaseRecursive(unsigned int,unsigned int,Case::Handle"); }