1 /*
2  *  Open BEAGLE
3  *  Copyright (C) 2001-2007 by Christian Gagne and Marc Parizeau
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Contact:
20  *  Laboratoire de Vision et Systemes Numeriques
21  *  Departement de genie electrique et de genie informatique
22  *  Universite Laval, Quebec, Canada, G1K 7P4
23  *  http://vision.gel.ulaval.ca
24  *
25  */
26 
27 /*!
28  *  \file   beagle/src/EvaluationMultipleOp.cpp
29  *  \brief  Source code of class EvaluationMultipleOp.
30  *  \author Matthew Walker
31  *  $Revision: 1.12.2.1 $
32  *  $Date: 2007/05/09 01:51:18 $
33  */
34 
35 #include "beagle/Beagle.hpp"
36 
37 #include <algorithm>
38 #include <string>
39 #include <deque>
40 
41 
42 using namespace Beagle;
43 
44 /*!
45  *  \brief Construct a new multiple-individual evaluation operator.
46  *  \param inIndisPerCaseAndGroup Number of individuals per test cases and group.
47  *  \param inName Name of the operator.
48  */
EvaluationMultipleOp(unsigned int inIndisPerCaseAndGroup,Beagle::string inName)49 EvaluationMultipleOp::EvaluationMultipleOp(unsigned int inIndisPerCaseAndGroup,
50                                            Beagle::string inName) :
51   EvaluationOp(inName),
52   mIndisPerCase(inIndisPerCaseAndGroup),
53   mIndisPerGroup(inIndisPerCaseAndGroup)
54 { }
55 
56 
57 /*!
58  *  \brief Construct a new multiple-individual evaluation operator.
59  *  \param inIndisPerCase Number of individuals per test cases.
60  *  \param inIndisPerGroup Number of individuals per group.
61  *  \param inName Name of the operator.
62  */
EvaluationMultipleOp(unsigned int inIndisPerCase,unsigned int inIndisPerGroup,Beagle::string inName)63 EvaluationMultipleOp::EvaluationMultipleOp(unsigned int inIndisPerCase,
64                                            unsigned int inIndisPerGroup,
65                                            Beagle::string inName) :
66   EvaluationOp(inName),
67   mIndisPerCase(inIndisPerCase),
68   mIndisPerGroup(inIndisPerGroup)
69 { }
70 
71 
72 /*!
73  *  \brief Apply the evaluation operation on a breeding pool, returning a evaluated bred individual.
74  *  \param inBreedingPool Breeding pool to use for the breeding operation.
75  *  \param inChild Node handle associated to child node in the breeder tree.
76  *  \param ioContext Evolutionary context of the breeding operation.
77  *  \return Evaluated bred individual.
78  */
breed(Individual::Bag & inBreedingPool,BreederNode::Handle inChild,Context & ioContext)79 Individual::Handle EvaluationMultipleOp::breed(Individual::Bag& inBreedingPool,
80                                                BreederNode::Handle inChild,
81                                                Context& ioContext)
82 {
83   Beagle_StackTraceBeginM();
84   throw Beagle_UndefinedMethodInternalExceptionM("EvaluationMultipleOp", "breed", getName());
85   return Individual::Handle(NULL);
86   Beagle_StackTraceEndM("Individual::Handle EvaluationMultipleOp::breed(Individual::Bag& inBreedingPool, BreederNode::Handle inChild, Context& ioContext)");
87 }
88 
89 
90 /*!
91  *  \brief Add individuals to the bag such that the total equals getIndisPerGroup().
92  *  \param ioIndividuals Bag of individuals to evaluate.
93  *  \param ioContexts Bag of evolutionary context.
94  *  \return The number of individuals added to the bag.
95  *
96  *  The new individuals are chosen from the current deme.
97  */
enlargeGroup(Individual::Bag & ioIndividuals,Context::Bag & ioContexts)98 unsigned int EvaluationMultipleOp::enlargeGroup(Individual::Bag& ioIndividuals,
99                                                 Context::Bag& ioContexts)
100 {
101   Beagle_StackTraceBeginM();
102   Context& lContext = castObjectT<Context&>(*(ioContexts[0]));
103 
104   // Calculate the number of individuals to add
105   unsigned int lNumToAdd = mIndisPerGroup - ioIndividuals.size();
106   Beagle_LogVerboseM(
107     lContext.getSystem().getLogger(),
108     "evaluation", "Beagle::EvaluationMultipleOp",
109     string("Adding ")+uint2str(lNumToAdd)+string(" individuals to the group (for padding)")
110   );
111 
112   // Resize the bags
113   unsigned int lIndisCounter = ioIndividuals.size();
114   ioIndividuals.resize(mIndisPerGroup);
115   ioContexts.resize(mIndisPerGroup);
116 
117   // Loop through all the individuals in the deme
118   Deme& lDeme = lContext.getDeme();
119   std::vector< unsigned int,BEAGLE_STLALLOCATOR<unsigned int> > lSelectableIndis;
120   lSelectableIndis.resize(lDeme.size());
121   unsigned int lSelectableIndisCounter = 0;
122   for (unsigned int i=0; i<lDeme.size(); i++) {
123     // Loop through all the individuals in the bag
124     bool lAdd = true;
125     for(unsigned int j=0; j<ioIndividuals.size(); j++) {
126       if(lDeme[i] == ioIndividuals[j]) {
127         lAdd = false;
128         break;
129       }
130     }
131     // If the individual is not already in the bag, add it as an option
132     if(lAdd) {
133       lSelectableIndis[lSelectableIndisCounter] = i;
134       lSelectableIndisCounter++;
135     }
136   }
137 
138   // Check there are sufficient individuals to choose
139   if(lSelectableIndis.size() < lNumToAdd) {
140     throw Beagle_RunTimeExceptionM("There are insufficient individuals in the deme to perform evaluation");
141   }
142 
143   // Add individuals
144   for(unsigned int i=0; i<lNumToAdd; i++) {
145     unsigned int lIndex =
146       lContext.getSystem().getRandomizer().rollInteger(0,lSelectableIndisCounter-1);
147     unsigned int lIndiIndex = lSelectableIndis[lIndex];
148     Beagle_LogVerboseM(
149       lContext.getSystem().getLogger(),
150       "evaluation", "Beagle::EvaluationMultipleOp",
151       string("Adding ")+uint2ordinal(lIndiIndex+1)+
152       string(" individual to the group (for padding)")
153     );
154     Beagle_AssertM(lIndiIndex < lDeme.size());
155     ioIndividuals[lIndisCounter] = lDeme[ lIndiIndex ];
156     ioContexts[lIndisCounter]
157       = castHandleT<Context>(lContext.getSystem().getContextAllocator().clone( *(ioContexts[0]) ));
158     ioContexts[lIndisCounter]->setIndividualHandle( ioIndividuals[lIndisCounter] );
159     ioContexts[lIndisCounter]->setIndividualIndex( lIndiIndex );
160     lIndisCounter++;
161   }
162   Beagle_AssertM( lIndisCounter==ioIndividuals.size() );
163 
164   return lNumToAdd;
165   Beagle_StackTraceEndM("unsigned int EvaluationMultipleOp::enlargeGroup(Individual::Bag&,Context::Bag&)");
166 }
167 
168 
169 
170 /*!
171  *  \brief Evaluate the fitness of the given individual.
172  *  \param inIndividual Current individual to evaluate.
173  *  \param ioContext Evolutionary context.
174  *  \return Handle to the fitness value of the individual.
175  *
176  *  This method evaluates only a single individual.  For this
177  *  operator, it is much better to group individuals into a bag and
178  *  pass the bag to evaluate(Individual::Bag& ioIndividuals, Context::Bag& ioContexts).
179  */
evaluate(Individual & inIndividual,Context & ioContext)180 Fitness::Handle EvaluationMultipleOp::evaluate(Individual& inIndividual, Context& ioContext)
181 {
182   Beagle_StackTraceBeginM();
183   // Create a bag for the individual
184   Individual::Bag lIndividuals;
185   lIndividuals.resize(1);
186   Beagle_AssertM(inIndividual == ioContext.getIndividual());
187   lIndividuals[0] = ioContext.getIndividualHandle();
188 
189   // Create a context for the individual
190   Context::Bag lContexts;
191   lContexts.resize(1);
192   lContexts[0] =
193     castHandleT<Context>(ioContext.getSystem().getContextAllocator().clone( ioContext));
194 
195   // Call evalutate()
196   Fitness::Bag::Handle lFitnessBag = evaluateIndividuals(lIndividuals,lContexts);
197 
198   // Return fitness
199   Beagle_AssertM( !lFitnessBag->empty() );
200   return lFitnessBag->at(0);
201   Beagle_StackTraceEndM("Fitness::Handle EvaluationMultipleOp::evaluate(Individual&,Context&)");
202 }
203 
204 
205 /*!
206  *  \brief Evaluate the fitness of the given bag of individuals.
207  *  \param ioIndividuals Bag of individuals to evaluate.
208  *  \param ioContexts Bag of evolutionary context.
209  *  \return Handle to a bag of fitness values, one for each individual.
210  */
evaluateIndividuals(Individual::Bag & ioIndividuals,Context::Bag & ioContexts)211 Fitness::Bag::Handle EvaluationMultipleOp::evaluateIndividuals(Individual::Bag& ioIndividuals,
212                                                                Context::Bag& ioContexts)
213 {
214   Beagle_StackTraceBeginM();
215   Beagle_AssertM(ioIndividuals.size()==ioContexts.size());
216   Beagle_AssertM(ioIndividuals.size()!=0);
217 
218   Context& lContext = castObjectT<Context&>(*(ioContexts[0]));
219 
220   // Check if sufficient individuals are in the bag
221   Beagle_AssertM( ioIndividuals.size() <= mIndisPerGroup );
222   unsigned int lNumToIgnore = 0;
223   if (ioIndividuals.size() != mIndisPerGroup) {
224     lNumToIgnore = enlargeGroup(ioIndividuals, ioContexts);
225   }
226 
227   // Create bag of null-fitnesses
228   Fitness::Bag::Handle lFitnessBagAll = new Fitness::Bag;
229   lFitnessBagAll->resize( ioIndividuals.size() );
230   Beagle_NonNullPointerAssertM( lFitnessBagAll );
231 
232   // Set up cases
233   if (mCases == NULL) setupCases(ioIndividuals.size(),lContext);
234   Case::Bag::Handle lCases = pruneIgnorableCases(lNumToIgnore);
235 
236   // Call evaluateCase for each case
237   for (unsigned int i=0; i<lCases->size(); i++) {
238     Beagle_LogVerboseM(
239       lContext.getSystem().getLogger(),
240       "evaluation", "Beagle::EvaluationMultipleOp",
241       string("Evaluating the ")+uint2ordinal(i+1)+string(" case")
242     );
243     Case& lCase = *(lCases->at(i));
244     Beagle_AssertM( lCase.mIndices.size() == mIndisPerCase );
245 
246     // Setup bags of individuals and contexts
247     Individual::Bag lIndividuals;
248     Context::Bag lContexts;
249     lIndividuals.resize( mIndisPerCase );
250     lContexts.resize( mIndisPerCase );
251     for (unsigned int j=0; j<mIndisPerCase; j++) {
252       unsigned int lIndex = lCase.mIndices[j];
253       lIndividuals[j] = ioIndividuals[ lIndex ];
254       lContexts[j] = ioContexts[ lIndex ];
255     }
256 
257     // Log individual's details
258     std::ostringstream lOSS;
259     for (unsigned int j=0; j<lIndividuals.size(); j++) {
260       if (j!=0) lOSS << ", ";
261       lOSS << uint2ordinal(lContexts[j]->getIndividualIndex()+1);
262     }
263     Beagle_LogDebugM(
264       lContext.getSystem().getLogger(),
265       "evaluation", "Beagle::EvaluationMultipleOp",
266       uint2ordinal(i+1)+string(" case: ")+
267       lOSS.str().c_str()
268     );
269 
270     // Call evalutateCase()
271     Fitness::Bag::Handle lFitnessBagCase =
272       evaluateCase(lIndividuals, lContexts);
273 
274     // Log resulting fitnesses
275     Beagle_NonNullPointerAssertM( lFitnessBagCase );
276     Beagle_LogDebugM(
277       lContext.getSystem().getLogger(),
278       "evaluation", "Beagle::EvaluationMultipleOp",
279       string("Evaluation of the case is complete.  The fitnesses are as follows:")
280     );
281     for (unsigned int j=0; j<mIndisPerCase; j++) {
282       Beagle_NonNullPointerAssertM( lFitnessBagCase->at(j) );
283       Beagle_LogDebugM(
284         lContext.getSystem().getLogger(),
285         "evaluation", "Beagle::EvaluationMultipleOp",
286         string("Fitness of the ")+
287         uint2ordinal(ioContexts[lCase.mIndices[j]]->getIndividualIndex()+1)+
288         string(" individual: ")+lFitnessBagCase->at(j)->serialize()
289       );
290 
291       // Need to assign fitness values from case to lFitnessBagAll
292       unsigned int lIndex = lCase.mIndices[j];
293       Beagle_LogDebugM(
294         lContext.getSystem().getLogger(),
295         "evaluation", "Beagle::EvaluationMultipleOp",
296         string("Setting fitness for lFitnessBagAll at index ")+uint2str(lIndex)
297       );
298       Beagle_AssertM(lIndex < lFitnessBagAll->size());
299       if (lFitnessBagAll->at(lIndex)==NULL) {
300         (*lFitnessBagAll)[lIndex] = lFitnessBagCase->at(j);
301       }
302       else {
303         combineFitnesses(lFitnessBagAll->at(lIndex),
304                          lFitnessBagCase->at(j) );
305         Beagle_LogDebugM(
306           lContext.getSystem().getLogger(),
307           "evaluation", "Beagle::EvaluationMultipleOp",
308           string("Fitness of the ")+uint2ordinal(ioContexts[lIndex]->getIndividualIndex()+1)+
309           string(" individual has been combined to: ")+lFitnessBagAll->at(lIndex)->serialize()
310         );
311       }
312     }
313   }
314 
315   Beagle_LogDebugM(
316     lContext.getSystem().getLogger(),
317     "evaluation", "Beagle::EvaluationMultipleOp",
318     string("Evaluation of all cases is complete.  Fitnesses are as follows:")
319   );
320   for (unsigned int i=0;
321        i<ioIndividuals.size();
322        i++) {
323     if (i>=mIndisPerGroup-lNumToIgnore) {
324       // Nullify ignorable individuals' fitness scores
325       Beagle_LogDebugM(
326         lContext.getSystem().getLogger(),
327         "evaluation", "Beagle::EvaluationMultipleOp",
328         string("Ignoring fitness of the ")+uint2ordinal(ioContexts[i]->getIndividualIndex()+1)+
329         string(" individual")
330       );
331       (*lFitnessBagAll)[i] = NULL;
332       continue;
333     }
334     Beagle_NonNullPointerAssertM( lFitnessBagAll->at(i) );
335     Beagle_LogDebugM(
336       lContext.getSystem().getLogger(),
337       "evaluation", "Beagle::EvaluationMultipleOp",
338       string("Fitness of the ")+uint2ordinal(ioContexts[i]->getIndividualIndex()+1)+
339       lFitnessBagAll->at(i)->serialize()
340     );
341   }
342 
343   return lFitnessBagAll;
344   Beagle_StackTraceEndM("Fitness::Bag::Handle EvaluationMultipleOp::evaluateIndividuals(Individual::Bag&,Context::Bag&)");
345 }
346 
347 
348 /*!
349  *  \brief Apply the evaluation process on the invalid individuals of the deme.
350  *  \param ioDeme Deme to process.
351  *  \param ioContext Context of the evolution.
352  */
operate(Deme & ioDeme,Context & ioContext)353 void EvaluationMultipleOp::operate(Deme& ioDeme, Context& ioContext)
354 {
355   Beagle_StackTraceBeginM();
356   Beagle_LogTraceM(
357     ioContext.getSystem().getLogger(),
358     "evaluation", "Beagle::EvaluationMultipleOp",
359     string("Evaluating the fitness of the individuals in the ")+
360     uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
361   );
362 
363   Beagle_AssertM( ioDeme.size()!=0 );
364 
365   // Prepare stats
366   prepareStats(ioDeme,ioContext);
367 
368   // Generate a vector of indicies into the population
369   std::vector< unsigned int,BEAGLE_STLALLOCATOR<unsigned int> > lEvalVector;
370   for(unsigned int i=0; i<ioDeme.size(); i++) {
371     if((ioDeme[i]->getFitness() == NULL) ||
372        (ioDeme[i]->getFitness()->isValid() == false)) {
373       lEvalVector.push_back(i);
374       Beagle_LogDebugM(
375         ioContext.getSystem().getLogger(),
376         "evaluation", "Beagle::EvaluationMultipleOp",
377         string("Added ")+uint2ordinal(i+1)+string(" individual for evaluation.")
378       );
379     }
380   }
381   std::random_shuffle(lEvalVector.begin(), lEvalVector.end(),
382                       ioContext.getSystem().getRandomizer());
383 
384   Beagle_LogDebugM(
385     ioContext.getSystem().getLogger(),
386     "evaluation", "Beagle::EvaluationMultipleOp",
387     string("There are ")+uint2str(lEvalVector.size())+
388     string(" individuals to be evaluated.")
389   );
390 
391   while ( !lEvalVector.empty() ) {
392     // Put individuals and context into bags.
393     Individual::Bag lIndividuals;
394     Context::Bag lContexts;
395     lIndividuals.resize( mIndisPerGroup );
396     lContexts.resize( mIndisPerGroup );
397     unsigned int lIndiCounter =0;
398 
399     for (unsigned int i=0; i<mIndisPerGroup; i++) {
400       // Set individual
401       lIndividuals[i] = ioDeme[lEvalVector.back()];
402       lIndiCounter++;
403       // Set context
404       Context::Handle lContext =
405         castHandleT<Context>(ioContext.getSystem().getContextAllocator().clone(ioContext));
406       lContext->setIndividualIndex( lEvalVector.back() );
407       lContext->setIndividualHandle( ioDeme[lEvalVector.back()] );
408       lContexts[i] = lContext;
409       // Remove this index from the evaluation vector
410       lEvalVector.pop_back();
411       if(lEvalVector.empty()) {
412         lIndividuals.resize( lIndiCounter );
413         lContexts.resize( lIndiCounter );
414         break;
415       }
416     }
417 
418     // Evaluate individuals
419     std::ostringstream lOSS;
420     for (unsigned int i=0; i<lIndiCounter; i++) {
421       // Add to message
422       if (i==lIndiCounter-1) lOSS << " and ";
423       lOSS << uint2ordinal(lContexts[i]->getIndividualIndex()+1);
424       if (i<lIndiCounter-2) lOSS << ", ";
425     }
426     Beagle_LogVerboseM(
427       ioContext.getSystem().getLogger(),
428       "evaluation", "Beagle::EvaluationMultipleOp",
429       string("Evaluating the fitness of the ")+string(lOSS.str().c_str())+
430       " individuals"
431     );
432     Fitness::Bag::Handle lFitnessBag = evaluateIndividuals(lIndividuals, lContexts);
433 
434     // Assign fitnesses
435     for (unsigned int i=0; i<lIndiCounter; i++) {
436       Beagle_LogDebugM(
437         ioContext.getSystem().getLogger(),
438         "evaluation", "Beagle::EvaluationMultipleOp",
439         string("Considering fitness of the ")+
440         uint2ordinal(lContexts[i]->getIndividualIndex()+1)+string(" individual")
441       );
442       Beagle_AssertM( i < lFitnessBag->size() );
443       Fitness::Handle lFitness = lFitnessBag->at(i);
444       Beagle_NonNullPointerAssertM( lFitness );
445       lIndividuals[i]->setFitness( lFitness );
446       lIndividuals[i]->getFitness()->setValid();
447 
448       Beagle_LogVerboseM(
449         ioContext.getSystem().getLogger(),
450         "evaluation", "Beagle::EvaluationMultipleOp",
451         string("The fitness of the ")+uint2ordinal(lContexts[i]->getIndividualIndex()+1)+
452         string(" individual is: ")+
453         lIndividuals[i]->getFitness()->serialize()
454       );
455     }
456 
457     // Update stats
458     updateStats(lIndividuals.size(),ioContext);
459   }
460 
461   updateHallOfFameWithDeme(ioDeme,ioContext);
462   Beagle_StackTraceEndM("void EvaluationMultipleOp::operate(Deme&,Context&)");
463 }
464 
465 
466 /*!
467  *  \brief Removes cases that contain only references to individuals
468  *    that are acting a padding.
469  *  \param inNumToIgnore Number of individuals that have been added as padding.
470  */
471 EvaluationMultipleOp::Case::Bag::Handle
pruneIgnorableCases(unsigned int inNumToIgnore)472 EvaluationMultipleOp::pruneIgnorableCases(unsigned int inNumToIgnore)
473 {
474   Beagle_StackTraceBeginM();
475   if (inNumToIgnore==0) return mCases;
476 
477   Case::Bag::Handle lCases = new Case::Bag;
478   lCases->resize( mCases->size() );
479   unsigned int lCaseCounter = 0;
480 
481   // Check every case
482   for (unsigned int i=0; i<mCases->size(); i++) {
483     // Check if any of the indices are not able to be ignored
484     Case& lCase = *(mCases->at(i));
485     bool lAdd = false;
486     for (unsigned int j=0; j<lCase.mIndices.size(); j++) {
487       if (lCase.mIndices[j] < mIndisPerGroup-inNumToIgnore) {
488         lAdd=true;
489         break;
490       }
491     }
492     // If it cannot be ignored, add it to the bag of "un-ignorables"
493     if (lAdd) {
494       (*lCases)[lCaseCounter] = (*mCases)[i];
495       lCaseCounter++;
496     }
497   }
498 
499   lCases->resize(lCaseCounter);
500   return lCases;
501   Beagle_StackTraceEndM("EvaluationMultipleOp::Case::Bag::Handle EvaluationMultipleOp::pruneIgnorableCases(unsigned int)");
502 }
503 
504 
505 /*!
506  *  \brief Sets up cases.
507  *  \param inSize Number of individuals in a group.
508  *  \param ioContext Context of the evolution.
509  *
510  *  A case is a vector of indices into a bag of individuals.  This
511  *  method creates cases.  The number of cases is decided by inSize.
512  *
513  *  For example, if inSize is 4 (set by setIndisPerGroup), then the
514  *  indices will range from 0 to 3.  If each case contains just two
515  *  individuals (as set by setIndisPerCase) then the cases will be:
516  *  (0,1) (0,2) (0,3)
517  *  (1,2) (1,3)
518  *  (2,3)
519  *  Where (x,y) dictates a case when individual x will compete against
520  *  indiviudal y.
521  */
setupCases(unsigned int inSize,Context & ioContext)522 void EvaluationMultipleOp::setupCases(unsigned int inSize, Context& ioContext)
523 {
524   Beagle_StackTraceBeginM();
525   Beagle_LogDebugM(
526     ioContext.getSystem().getLogger(),
527     "evaluation", "Beagle::EvaluationMultipleOp",
528     string("Creating evaluation cases")
529   );
530   Beagle_AssertM(inSize >= mIndisPerCase);
531   Beagle_AssertM(inSize == mIndisPerGroup);
532 
533   // Create cases with each case containing one individual
534   mCases = new Case::Bag;
535   Beagle_NonNullPointerAssertM( mCases );
536   for (unsigned int i=0; i<inSize; i++) {
537     Case::Handle lCase = new Case;
538     lCase->mIndices.push_back( i );
539     setupCaseRecursive(inSize,i,lCase);
540   }
541 
542   // Log cases
543   Beagle_LogDebugM(
544     ioContext.getSystem().getLogger(),
545     "evaluation", "Beagle::EvaluationMultipleOp",
546     uint2str(mCases->size())+string(" evaluation cases were created")
547   );
548   for (unsigned int i=0; i<mCases->size(); i++) {
549     std::ostringstream lOSS;
550     for (unsigned int j=0; j<mCases->at(i)->mIndices.size(); j++) {
551       if (j!=0) lOSS << ", ";
552       lOSS << mCases->at(i)->mIndices[j];
553     }
554     Beagle_LogDebugM(
555       ioContext.getSystem().getLogger(),
556       "evaluation", "Beagle::EvaluationMultipleOp",
557       uint2ordinal(i+1)+string(" case: ")+
558       lOSS.str().c_str()
559     );
560   }
561   Beagle_StackTraceEndM("void EvaluationMultipleOp::setupCases(unsigned int,Context&)");
562 }
563 
564 
565 /*!
566  *  \brief Sets up cases by adding one more individual into a clone of
567  *    inCase, and then calling this method for each one of those cases.
568  *  \param inSize Number of individuals in a group.
569  *  \param inLastIndex The index of the last individual that was
570  *    inserted into the case.
571  *  \param inCase The case on which to work.
572  */
setupCaseRecursive(unsigned int inSize,unsigned int inLastIndex,Case::Handle inCase)573 void EvaluationMultipleOp::setupCaseRecursive(unsigned int inSize,
574                                               unsigned int inLastIndex,
575                                               Case::Handle inCase)
576 {
577   using namespace std;
578   Beagle_StackTraceBeginM();
579   unsigned int lCaseSize = inCase->mIndices.size();
580 
581   // Check if the case is finished.
582   if (lCaseSize == mIndisPerCase) {
583     unsigned int lSize = mCases->size();
584     mCases->resize( lSize + 1 );
585     (*mCases)[lSize]=inCase;
586     return;
587   }
588 
589   // Case isn't finished, add another individual to it.
590   Beagle_AssertM( lCaseSize<mIndisPerCase );
591   for (unsigned int i=inLastIndex+1;
592        i<inSize;
593        i++) {
594     Case::Handle lNewCase = new Case(*(inCase));
595     lNewCase->mIndices.push_back(i);
596     setupCaseRecursive(inSize,i,lNewCase);
597   }
598   Beagle_StackTraceEndM("void EvaluationMultipleOp::setupCaseRecursive(unsigned int,unsigned int,Case::Handle");
599 }
600