/*!
 *  \brief Apply the oversize replacement strategy operation on a deme.
 *  \param ioDeme Reference to the deme on which the operation takes place.
 *  \param ioContext Evolutionary context of the operation.
 */
void OversizeOp::operate(Deme& ioDeme, Context& ioContext)
{
	Beagle_StackTraceBeginM();
	Beagle_NonNullPointerAssertM(getRootNode());
	Beagle_ValidateParameterM
	(mOversizeRatio->getWrappedValue() >= 1.0
	 || mOversizeRatio->getWrappedValue() == -1.0,
	 mOversizeRatioName,
	 "The oversize ratio must be greater than or equal to 1.0, or equal to -1.0.");
	
	Beagle_LogTraceM(
					 ioContext.getSystem().getLogger(),
					 "replacement-strategy", "Beagle::OversizeOp",
					 string("Using oversize replacement strategy to process the ")+
					 uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
					 );
	Beagle_LogObjectM(
					  ioContext.getSystem().getLogger(),
					  Logger::eTrace,
					  "replacement-strategy", "Beagle::OversizeOp",
					  (*this)
					  );
	
	RouletteT<unsigned int> lRoulette;
	buildRoulette(lRoulette, ioContext);
	
	// Calculate the increase in size (lambda)
	float lRatio = mOversizeRatio->getWrappedValue();
	unsigned int lLambda;
	if (lRatio == -1.0) {
		// Using special ratio of -1.0 ensures deme grows to size specified in 'ec.pop.size'
		if (!ioContext.getSystem().getRegister().isRegistered("ec.pop.size")) {
			throw Beagle_RunTimeExceptionM(getName()+" requires register variable 'ec.pop.size'");
		}
		UIntArray::Handle lPopSize = castHandleT<UIntArray>
		(ioContext.getSystem().getRegister().getEntry("ec.pop.size"));
		unsigned int lSpecifiedDemeSize = (*lPopSize)[ioContext.getDemeIndex()];
		unsigned int lCurrentDemeSize = ioDeme.size();
		if (lSpecifiedDemeSize < lCurrentDemeSize) {
			throw Beagle_RunTimeExceptionM
			(std::string("For the ")+uint2ordinal(ioContext.getDemeIndex()+1)+
			 " deme, the size specified in 'ec.pop.size' ("+uint2str(lSpecifiedDemeSize)+
			 ") is less than the current deme size ("+uint2str(lCurrentDemeSize)+
			 ").  "+getName()+" can only increase the size of the deme.  Consider using DecimateOp "+
			 "if you wish to decrease the size of the deme");
		}
		lLambda = lSpecifiedDemeSize - lCurrentDemeSize;
	} else {
		// Using ratio to scale the deme's population
		lLambda = (unsigned int)ceil((lRatio-1.0)*float(ioDeme.size()));
	}
	Beagle_LogTraceM(
					 ioContext.getSystem().getLogger(),
					 "replacement-strategy", "Beagle::OversizeOp",
					 string("Population will be increased in size by ")+uint2str(lLambda)+" individuals"
					 );
	
	// Create the new individuals.
	Individual::Bag lOffsprings;
	for(unsigned int i=0; i<lLambda; ++i) {
		unsigned int lIndexBreeder = lRoulette.select(ioContext.getSystem().getRandomizer());
		BreederNode::Handle lSelectedBreeder=getRootNode();
		for(unsigned int j=0; j<lIndexBreeder; ++j)
			lSelectedBreeder=lSelectedBreeder->getNextSibling();
		Beagle_NonNullPointerAssertM(lSelectedBreeder);
		Beagle_NonNullPointerAssertM(lSelectedBreeder->getBreederOp());
		Individual::Handle lBredIndiv =
		lSelectedBreeder->getBreederOp()->breed(ioDeme, lSelectedBreeder->getFirstChild(), ioContext);
		Beagle_NonNullPointerAssertM(lBredIndiv);
		lOffsprings.push_back(lBredIndiv);
	}
	
	// Add the new individuals into the deme.
	ioDeme.insert(ioDeme.end(), lOffsprings.begin(), lOffsprings.end());
	Beagle_LogDetailedM(
						ioContext.getSystem().getLogger(),
						"replacement-strategy", "Beagle::OversizeOp",
						string("There are now ")+uint2str(ioDeme.size())+" individuals in the "+
						uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
						);
	Beagle_StackTraceEndM("void OversizeOp::operate(Deme& ioDeme, Context& ioContext)");
}
/*!
 *  \brief Apply the decimation operation on the deme.
 *  \param ioDeme Current deme of individuals to decimate.
 *  \param ioContext Context of the evolution.
 */
void DecimateOp::operate(Deme& ioDeme, Context& ioContext)
{
	Beagle_StackTraceBeginM();
	Beagle_ValidateParameterM((mDecimationRatio->getWrappedValue()<=1.0),
	                          mDecimationRatioName,
	                          "The decimation ratio must be less than or equal to 1.0.");

	Beagle_LogTraceM(
	    ioContext.getSystem().getLogger(),
	    "decimation", "Beagle::DecimateOp",
	    std::string("Applying decimation operation on the ")+
	    uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
	);

	// Calculate the number of individuals to keep from the deme
	unsigned int lMu = 0;
	if(mDecimationRatio->getWrappedValue() == -1.0) {
		Beagle_AssertM(ioContext.getDemeIndex() < mPopSize->size());
		lMu = (*mPopSize)[ioContext.getDemeIndex()];
	} else {
		lMu = (unsigned int)std::ceil(mDecimationRatio->getWrappedValue()*float(ioDeme.size()));
		Beagle_AssertM(ioContext.getDemeIndex() < mPopSize->size());
		int lDiffSize = (*mPopSize)[ioContext.getDemeIndex()] - lMu;
		if((lDiffSize >= -1) && (lDiffSize <= 1)) lMu = (*mPopSize)[ioContext.getDemeIndex()];
	}
	Beagle_LogTraceM(
	    ioContext.getSystem().getLogger(),
	    "decimation", "Beagle::DecimateOp",
	    std::string("Keeping ")+uint2str(lMu)+" of the "+uint2str(ioDeme.size())+
	    " individuals from the "+uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
	);

	// Check that the number of individuals to keep (mu) isn't greater than the deme size
	if(lMu > ioDeme.size()) {
		std::ostringstream lOSS;
		lOSS << "Warning: the actual population size (" << ioDeme.size();
		lOSS << ") is less than the desired decimation size (" << lMu;
		lOSS << "). Decimation is thus not applied.";
		Beagle_LogBasicM(
		    ioContext.getSystem().getLogger(),
		    "decimation", "Beagle::DecimateOp",
		    lOSS.str()
		);
		return;
	}

	// Copy the individuals to be kept into the deme
	std::make_heap(ioDeme.begin(), ioDeme.end(), IsLessPointerPredicate());
	Individual::Bag lSurvivors;
	for(unsigned int i=0; i<lMu; ++i) {
		lSurvivors.push_back(ioDeme.front());
		std::pop_heap(ioDeme.begin(), (ioDeme.end()-i), IsLessPointerPredicate());
	}
	ioDeme.clear();
	ioDeme.insert(ioDeme.begin(), lSurvivors.begin(), lSurvivors.end());
	Beagle_LogDetailedM(
	    ioContext.getSystem().getLogger(),
	    "decimation", "Beagle::DecimateOp",
	    std::string("There are now ")+uint2str(ioDeme.size())+" individuals in the "+
	    uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
	);
	Beagle_StackTraceEndM("void DecimateOp::operate(Deme& ioDeme, Context& ioContext)");
}
/*!
 *  \brief Generate children from the breeder tree.
 *  \param ioDeme Deme to generate children from.
 *  \param ioContext Evolutionary context.
 *  \param lNbChildren Number of children to generate.
 *  \param inN Dimensionality of the problem.
 *  \param ioCMAValues CMA values to use to generate new individual.
 *  \param inSelectionWeights Selection weights used to generate children.
 */
void CMA::MuWCommaLambdaCMAFltVecOp::generateChildren(Deme& ioDeme,
        Context& ioContext,
        unsigned int inNbChildren,
        unsigned int inN,
        CMAValues& ioCMAValues,
        const Vector& inSelectionWeights) const
{
	Beagle_StackTraceBeginM();
	// Check parameters and log some information
	Beagle_NonNullPointerAssertM(mElitismKeepSize);
	Beagle_ValidateParameterM(mLMRatio->getWrappedValue() >= 1.0,
	                          mLMRatioName,
	                          "The LM ratio must be higher or equal to 1.0.");
	Beagle_ValidateParameterM(mElitismKeepSize->getWrappedValue() <= ioDeme.size(),
	                          "ec.elite.keepsize",
	                          "The elistism keepsize must be less than the deme size!");

	Beagle_LogTraceM(
	    ioContext.getSystem().getLogger(),
	    std::string("Using CMA-ES (mu_w,lambda) replacement strategy to process the ")+
	    uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
	);
	Beagle_LogTraceM(ioContext.getSystem().getLogger(), (*this));
	const Factory& lFactory = ioContext.getSystem().getFactory();

	// Create weighted mean individual.
	std::sort(ioDeme.begin(), ioDeme.end(), IsMorePointerPredicate());

	Individual::Alloc::Handle lIndividualAlloc =
		castHandleT<Individual::Alloc>(lFactory.getConceptAllocator("Individual"));
	Individual::Handle lMeanInd = castHandleT<Individual>(lIndividualAlloc->allocate());
	Genotype::Alloc::Handle lGenotypeAlloc =
		castHandleT<Genotype::Alloc>(lFactory.getConceptAllocator("Genotype"));
	FltVec::FloatVector::Handle lMeanFloatVec =
		castHandleT<FltVec::FloatVector>(lGenotypeAlloc->allocate());
	lMeanFloatVec->resize(inN);
	lMeanInd->push_back(lMeanFloatVec);
	
	for(unsigned int i=0; i<inN; ++i) (*lMeanFloatVec)[i] = 0.0;
	if(ioDeme.size()==1) {
		Beagle_AssertM(ioDeme[0]->size() == 1);
		FltVec::FloatVector::Handle lInd = castHandleT<FltVec::FloatVector>((*ioDeme[0])[0]);
		(*lMeanFloatVec) = *lInd;
	} else {
		for(unsigned int i=0; i<ioDeme.size(); ++i) {
			Beagle_AssertM(ioDeme[i]->size()==1);
			FltVec::FloatVector::Handle lVecI = castHandleT<FltVec::FloatVector>((*ioDeme[i])[0]);
			Beagle_AssertM(lVecI->size()==inN);
			for(unsigned int j=0; j<inN; ++j) (*lMeanFloatVec)[j] += (inSelectionWeights[i] * (*lVecI)[j]);
		}
	}
	ioCMAValues.mXmean.resize(inN);
	for(unsigned int i=0; i<inN; ++i) ioCMAValues.mXmean[i] = (*lMeanFloatVec)[i];

	// Generate lambda children with breeder tree, first build breeder roulette
	RouletteT<unsigned int> lRoulette;
	buildRoulette(lRoulette, ioContext);

	// Keep best individuals if elitism is used
	const unsigned int lElitismKS=mElitismKeepSize->getWrappedValue();
	if(lElitismKS > 0) {
		Individual::Bag lBestInd;
		History::Handle lHistory = castHandleT<History>(ioContext.getSystem().haveComponent("History"));
		std::make_heap(ioDeme.begin(), ioDeme.end(), IsLessPointerPredicate());
		for(unsigned int i=0; i<lElitismKS; ++i) {
			if(lHistory != NULL) {
				HistoryID::Handle lHID = castHandleT<HistoryID>(ioDeme[0]->getMember("HistoryID"));
				std::vector<HistoryID> lParent;
				if(lHID != NULL) lParent.push_back(*lHID);
				lHistory->allocateNewID(*ioDeme[0]);
				lHistory->trace(ioContext, lParent, ioDeme[0], getName(), "elitism");
			}
			lBestInd.push_back(ioDeme[0]);
			std::pop_heap(ioDeme.begin(), ioDeme.end(), IsLessPointerPredicate());
			ioDeme.pop_back();
		}
		ioDeme.clear();
		ioDeme.insert(ioDeme.end(), lBestInd.begin(), lBestInd.end());
	} else ioDeme.clear();

	// Generate the children
	Individual::Bag lBagWithMeanInd;
	lBagWithMeanInd.push_back(lMeanInd);
	for(unsigned int i=0; i<inNbChildren; ++i) {
		unsigned int lIndexBreeder = lRoulette.select(ioContext.getSystem().getRandomizer());
		BreederNode::Handle lSelectedBreeder=getRootNode();
		for(unsigned int j=0; j<lIndexBreeder; ++j)
			lSelectedBreeder=lSelectedBreeder->getNextSibling();
		Beagle_NonNullPointerAssertM(lSelectedBreeder);
		Beagle_NonNullPointerAssertM(lSelectedBreeder->getBreederOp());
		Individual::Handle lBredIndiv =
		    lSelectedBreeder->getBreederOp()->breed(lBagWithMeanInd,
		                                            lSelectedBreeder->getFirstChild(),
		                                            ioContext);
		Beagle_NonNullPointerAssertM(lBredIndiv);
		ioDeme.push_back(lBredIndiv);
	}

	Beagle_StackTraceEndM();
}