bool TreeMutShrink::mutate(GenotypeP gene)
{
	Tree* tree = (Tree*) (gene.get());

	// try to select random node in tree which is not a terminal
	// (it is silly to shrink just a terminal :))
	uint chosenNode;
	uint chosenNodeSubtreeSize;
	uint tries = 0;
	do {
		chosenNode = state_->getRandomizer()->getRandomInteger((int) tree->size());
		chosenNodeSubtreeSize = tree->at(chosenNode)->size_;
		tries++;
	} while(chosenNodeSubtreeSize == 1 && tries < 4);

	if(chosenNodeSubtreeSize == 1) {
		ECF_LOG(state_, 5, "TreeMutShrink not successful.");
		return false;
	}

	// first of all, make a copy and clear the original
	Tree* copyTree = tree->copy();
	tree->clear();

	std::stringstream log;
	log << "TreeMutShrink successful (";

	uint i = 0;

	// copy all nodes before chosen subtree to original
	for( ; i < chosenNode; i++) {
		NodeP node = static_cast<NodeP> (new Node(copyTree->at(i)->primitive_));
		tree->addNode(node);
	}

	log << "shrinkedSubtree = ";
	for( ; i < chosenNode + chosenNodeSubtreeSize; i++) {
		// these nodes are skipped because they are elements of the chosen subtree
		log << copyTree->at(i)->primitive_->getName() << " ";
	}

	// chosen subtree is shrinked to a random terminal
	Node* node = new Node;
	node->setPrimitive(copyTree->primitiveSet_->getRandomTerminal());
	tree->addNode(node);
	log << ", shrinkedTo = " << node->primitive_->getName() << ")";

	// copy all nodes after chosen subtree to original
	for( ; i < copyTree->size(); i++) {
		NodeP node = static_cast<NodeP> (new Node(copyTree->at(i)->primitive_));
		tree->addNode(node);
	}

	tree->update();
	delete copyTree;

	ECF_LOG(state_, 5, log.str());

	return true;
}
		bool initialize(StateP state)
		{		
			voidP lBound = state->getGenotypes()[0]->getParameterValue(state, "lbound");
			lbound = *((double*) lBound.get());

			voidP uBound = state->getGenotypes()[0]->getParameterValue(state, "ubound");
			ubound = *((double*) uBound.get());

			voidP dimension_ = state->getGenotypes()[0]->getParameterValue(state, "dimension");
			dimension = *((uint*) dimension_.get());

			voidP dup_ = getParameterValue(state, "dup");
			dup = *((uint*) dup_.get());
			if( *((int*) dup_.get()) <= 0 ) {
				ECF_LOG(state, 1, "Error: opt-IA requires parameter 'dup' to be an integer greater than 0");
				throw "";}

			voidP c_ = getParameterValue(state, "c");
			c = *((double*) c_.get());
			if( c <= 0 ) {
				ECF_LOG(state, 1, "Error: opt-IA requires parameter 'c' to be a double greater than 0");
				throw "";}

			voidP tauB_ = getParameterValue(state, "tauB");
			tauB = *((double*) tauB_.get());
			if( tauB < 0 ) {
				ECF_LOG(state, 1, "Error: opt-IA requires parameter 'tauB' to be a nonnegative double value");
				throw "";}

			voidP elitism_ = getParameterValue(state, "elitism");
			elitism = *((string*) elitism_.get());
			if( elitism != "true" && elitism != "false"  ) {
				ECF_LOG(state, 1,  "Error: opt-IA requires parameter 'elitism' to be either 'true' or 'false'");
				throw "";}


			// algorithm accepts a single FloatingPoint Genotype
			FloatingPointP flp (new FloatingPoint::FloatingPoint);
			if(state->getGenotypes()[0]->getName() != flp->getName()) {
				ECF_LOG_ERROR(state, "Error: opt-IA algorithm accepts only a FloatingPoint genotype!");
				throw ("");}

			// algorithm adds another FloatingPoint genotype (age)
			FloatingPointP flpoint[2];
			for(uint iGen = 1; iGen < 2; iGen++) {
				flpoint[iGen] = (FloatingPointP) new FloatingPoint::FloatingPoint;
				state->setGenotype(flpoint[iGen]);

				flpoint[iGen]->setParameterValue(state, "dimension", (voidP) new uint(1));					

				// initial value of age parameter should be (or as close as possible to) 0				
				flpoint[iGen]->setParameterValue(state, "lbound", (voidP) new double(0));
				flpoint[iGen]->setParameterValue(state, "ubound", (voidP) new double(0.01));
				
			}
			ECF_LOG(state, 1, "opt-IA algorithm: added 1 FloatingPoint genotype (antibody age)");
			
            return true;
		}
示例#3
0
bool TreeMutGauss::mutate(GenotypeP gene)
{
	Tree* tree = (Tree*) (gene.get());
	
	// try to select ERC node of type double
	uint iNode;
	uint tries = 0;
	std::string name;
	do {
		iNode = state_->getRandomizer()->getRandomInteger((int) tree->size());
		tries++;
	} while((name = tree->at(iNode)->primitive_->getName()).substr(0, 2) != DBL_PREFIX && tries < 4);

	if(name.substr(0, 2) != DBL_PREFIX)	{
		ECF_LOG(state_, 5, "TreeMutGauss not successful.");
		return false;
	}

	double oldValue;
	PrimitiveP oldPrim = tree->at(iNode)->primitive_;
	tree->at(iNode)->primitive_->getValue(&oldValue);
	std::string oldName = tree->at(iNode)->primitive_->getName();

	// generate Gauss noise offset and add it
	// TODO: parametrize distribution!
	boost::normal_distribution<double> N(0, 1);

	// e.g. http://www.codepedia.com/1/CppBoostRandom
	// TODO: preserve state
	//boost::lagged_fibonacci607 engine(state_->getRandomizer()->getRandomInteger(100000) + 1);

	double offset = N.operator () <boost::lagged_fibonacci607>(engine_);
	double newValue = oldValue + offset;

	// change double ERC value and name
	std::stringstream ss;
	ss << newValue;
	std::string newName;
	ss >> newName;
	newName = DBL_PREFIX + newName;

	oldPrim->setName(newName);
	oldPrim->setValue(&newValue);

	// new ERCs aren't stored in the PrimitiveSet

	std::stringstream log;
	log << "TreeMutGauss successful (oldNode = " << oldName << ", newNode = " << newName << ")";
	ECF_LOG(state_, 5, log.str());

	return true;
}
示例#4
0
/**
 * \brief Mutate an individual.
 *
 * May mutate one or more genotypes in given individual.
 * Determines which MutationOp to use on each genotype.
 */
bool Mutation::mutate(IndividualP ind)
{	
	ind->fitness->setInvalid();
	// set mutation context
	state_->getContext()->mutatedIndividual = ind;
	ECF_LOG(state_, 5, "Mutating individual: " + ind->toString());
	currentInd = ind;

	// if mutating a random genotype
	if(mutateGenotypes_ == RANDOM_GENOTYPE) {
		uint iGenotype = state_->getRandomizer()->getRandomInteger((int)ind->size());
		if(protectedGenotypes_[iGenotype])
			return false;
		// choose operator
		uint iOperator;
		if(opProb[iGenotype][0] < 0)
			iOperator = state_->getRandomizer()->getRandomInteger((int)operators[iGenotype].size());
		else {
			double random = state_->getRandomizer()->getRandomDouble();
			iOperator = 0;
			while(opProb[iGenotype][iOperator] < random)
				iOperator++;
		}
		operators[iGenotype][iOperator]->mutate(ind->at(iGenotype));
	}

	// if mutating all genotypes in the individual
	else if(mutateGenotypes_ == ALL_GENOTYPES) {
		for(uint iGenotype = 0; iGenotype < ind->size(); iGenotype++) {
			if(protectedGenotypes_[iGenotype])
				continue;
			// choose operator
			uint iOperator;
			if(opProb[iGenotype][0] < 0)
				iOperator = state_->getRandomizer()->getRandomInteger((int)operators[iGenotype].size());
			else {
				double random = state_->getRandomizer()->getRandomDouble();
				iOperator = 0;
				while(opProb[iGenotype][iOperator] < random)
					iOperator++;
			}
			operators[iGenotype][0]->mutate(ind->at(iGenotype));
		}
	}

	ECF_LOG(state_, 5, "Mutated individual: " + ind->toString());

	return true;
}
示例#5
0
// ispis tijeka min fitnesa - za potrebe mjerenja
void StatCalc::output(uint step)
{
	std::stringstream log;
	for(uint i = 0; i < min_.size(); i += step)
		log << i << "\t" << min_[i] << std::endl;
	ECF_LOG(state_, 2, log.str());
}
示例#6
0
/**
 * Log statistics.
 */
void StatCalc::log(int generation)
{
	if(generation == -1)
		generation = statNo;

	ECF_LOG(state_, 3, "Evaluations: " + uint2str(evaluations_[generation]) + 
		"\nStats: fitness\n\tmax: " + dbl2str(max_[generation]) + "\n\tmin: " +
		dbl2str(min_[generation]) + "\n\tavg: " + dbl2str(average_[generation]) + "\n\tstdev: " + dbl2str(stdDev_[generation]) + "\n");
}
示例#7
0
bool TermStagnationOp::operate(StateP state)
{
	uint currentGen = state->getGenerationNo();
	if(currentGen - state->getPopulation()->getHof()->getLastChange() > termStagnation_) {
		state->setTerminateCond();
		ECF_LOG(state, 1, "Termination: maximum number of generations without improvement ("
			+ uint2str(termStagnation_) + ") reached");
	}

	return true;
}
bool ArtificialBeeColony::initialize(StateP state)
{
	// initialize all operators
	selFitOp->initialize(state);
	selFitOp->setSelPressure(2);
	selBestOp->initialize(state);
	selWorstOp->initialize(state);
	selRandomOp->initialize(state);

	voidP sptr = state->getRegistry()->getEntry("population.size");
	uint size = *((uint*) sptr.get());
	probability_.resize(size);

	// this algorithm accepts a single FloatingPoint Genotype
	FloatingPointP flp (new FloatingPoint::FloatingPoint);
	if(state->getGenotypes()[0]->getName() != flp->getName()) {
		ECF_LOG_ERROR(state, "Error: ABC algorithm accepts only a single FloatingPoint genotype!");
		throw ("");
	}

	voidP limitp = getParameterValue(state, "limit");
	limit_ = *((uint*) limitp.get());

	voidP lBound = state->getGenotypes()[0]->getParameterValue(state, "lbound");
	lbound_ = *((double*) lBound.get());
	voidP uBound = state->getGenotypes()[0]->getParameterValue(state, "ubound");
	ubound_ = *((double*) uBound.get());

	// batch run check
	if(isTrialAdded_)
		return true;

	FloatingPointP flpoint[2];
	for(uint iGen = 1; iGen < 2; iGen++) {

		flpoint[iGen] = (FloatingPointP) new FloatingPoint::FloatingPoint;
		state->setGenotype(flpoint[iGen]);

		flpoint[iGen]->setParameterValue(state, "dimension", (voidP) new uint(1));					

		// initial value of trial parameter should be (as close as possible to) 0				
		flpoint[iGen]->setParameterValue(state, "lbound", (voidP) new double(0));
		flpoint[iGen]->setParameterValue(state, "ubound", (voidP) new double(0.01));
	}
	ECF_LOG(state, 1, "ABC algorithm: added 1 FloatingPoint genotype (trial)");

	// mark adding of trial genotype
	isTrialAdded_ = true;

    return true;
}
        bool initialize(StateP state)
		{		
			// initialize all operators
			selFitOp->initialize(state);
			selBestOp->initialize(state);
			selRandomOp->initialize(state);
			
			voidP limit_ = getParameterValue(state, "limit");
			limit = *((uint*) limit_.get());

			voidP lBound = state->getGenotypes()[0]->getParameterValue(state, "lbound");
			lbound = *((double*) lBound.get());
			voidP uBound = state->getGenotypes()[0]->getParameterValue(state, "ubound");
			ubound = *((double*) uBound.get());

		// algorithm accepts a single FloatingPoint Genotype
			FloatingPointP flp (new FloatingPoint::FloatingPoint);
			if(state->getGenotypes()[0]->getName() != flp->getName()) {
				ECF_LOG_ERROR(state, "Error: ABC algorithm accepts only a FloatingPoint genotype!");
				throw ("");
			}

			FloatingPointP flpoint[2];
			for(uint iGen = 1; iGen < 2; iGen++) {

				flpoint[iGen] = (FloatingPointP) new FloatingPoint::FloatingPoint;
				state->setGenotype(flpoint[iGen]);

				flpoint[iGen]->setParameterValue(state, "dimension", (voidP) new uint(1));					

				// initial value of trial parameter should be (as close as possible to) 0				
				flpoint[iGen]->setParameterValue(state, "lbound", (voidP) new double(0));
				flpoint[iGen]->setParameterValue(state, "ubound", (voidP) new double(0.01));
				
			}
			ECF_LOG(state, 1, "ABC algorithm: added 1 FloatingPoint genotype (trial)");
 
            return true;
        }
		bool TreeCrxProbabilistic::mate(GenotypeP gen1, GenotypeP gen2, GenotypeP ch)
		{
			Tree* male = (Tree*)(gen1.get());
			Tree* female = (Tree*)(gen2.get());
			Tree* child = (Tree*)(ch.get());

			uint mIndex, fIndex;
			uint mRange, fRange;
			uint mNodeDepth, fNodeDepth, fNodeDepthSize;

			mRange = (uint)male->size();
			fRange = (uint)female->size();

			// LD: femaleSizeIndexes[i] je vektor indeksa cvorova cija je velicina podstabla = i
			std::vector < std::vector<uint> > femaleSizeIndexes;

			femaleSizeIndexes.resize(fRange + 1);

			for (uint i = 0; i < fRange; i++)
				femaleSizeIndexes[female->at(i)->size_].push_back(i);

			uint nTries = 0;
			while (1)
			{
				//probabilisticDistancesIndices[i] contains a female index whose distance 
				//is stored in probabilisticDistancesValues[i]
				std::vector<int> probabilisticDistancesIndices;
				//probabilisticDistancesValues[i] contains probabilistic distance of 
				//probabilisticDistancesValues[i]-th node from chosen male node
				std::vector<double> probabilisticDistancesValues;

				// choose random crx point in male parent
				mIndex = state_->getRandomizer()->getRandomInteger(0, mRange - 1);

				// chose female crx point with expected size less or equal to the male's subtree
				uint subtreeSize = calculateSize(male->at(mIndex)->size_);

				double maleMax = male->at(mIndex)->primitive_->maxComputedValue;
				double maleMin = male->at(mIndex)->primitive_->minComputedValue;
				double sumOfAllDistances = 0;

				//j iterates over sizes
				for (uint j = 1; j < (1 + 2 * subtreeSize) && j < femaleSizeIndexes.size(); j++)
				{
					//index iterates over subtrees of j size
					for (uint index = 0; index < femaleSizeIndexes[j].size(); index++)
					{
						double femaleMax = female->at(femaleSizeIndexes[j].at(index))->primitive_->maxComputedValue;
						double femaleMin = female->at(femaleSizeIndexes[j].at(index))->primitive_->minComputedValue;
						double distance = 0.5 * (abs(maleMax - femaleMax) + abs(maleMin - femaleMin));
						probabilisticDistancesIndices.push_back(femaleSizeIndexes[j].at(index));
						probabilisticDistancesValues.push_back(distance);
						sumOfAllDistances += distance;
					}
				}

				if (sumOfAllDistances == 0)
				{
					nTries++;
					if (nTries > 4)
					{
						ECF_LOG(state_, 5, "TreeCrxProbabilistic not successful.");
						return false;
					}
					continue;
				}

				//calculate d'
				for (int i = 0; i < probabilisticDistancesIndices.size(); i++)
				{
					double value = probabilisticDistancesValues[i] / sumOfAllDistances;
					if (value < 0.000000000001)
						value = 0;
					probabilisticDistancesValues[i] = value;
				}

				//calculate p
				double sumOfAllInvertedDistances = 0;
				for (int i = 0; i < probabilisticDistancesIndices.size(); i++)
				{
					sumOfAllInvertedDistances += 1 - probabilisticDistancesValues[i];
				}

				for (int i = 0; i < probabilisticDistancesIndices.size(); i++)
				{
					double value = (1 - probabilisticDistancesValues[i]) / sumOfAllInvertedDistances;
					probabilisticDistancesValues[i] = value;
				}

				srand((unsigned)time(NULL));
				double p = ((double)rand() / (double)RAND_MAX);

				double minDiff = 1;
				fIndex = 0;

				for (int i = 0; i < probabilisticDistancesIndices.size(); i++)
				{
					double tempDiff = abs(probabilisticDistancesValues[i] - p);
					if (tempDiff < minDiff)
					{
						minDiff = tempDiff;
						fIndex = probabilisticDistancesIndices[i];
					}
				}

				mNodeDepth = male->at(mIndex)->depth_;
				fNodeDepth = female->at(fIndex)->depth_;

				// find max depth
				int maxDepth = fNodeDepth, depth;
				for (uint i = 0; i < female->at(fIndex)->size_; i++)
				{
					depth = female->at(fIndex + i)->depth_;
					maxDepth = depth > maxDepth ? depth : maxDepth;
				}

				fNodeDepthSize = maxDepth - fNodeDepth;
				nTries++;

				if (nTries > 4 || mNodeDepth + fNodeDepthSize <= male->maxDepth_) break;
			}

			if (nTries > 4 && mNodeDepth + fNodeDepthSize > male->maxDepth_) {
				ECF_LOG(state_, 5, "TreeCrxProbabilistic not successful.");
				return false;
			}

			child->clear();
			child->maxDepth_ = male->maxDepth_;
			child->minDepth_ = male->minDepth_;
			child->startDepth_ = male->startDepth_;

			// copy from male parent
			for (uint i = 0; i < mIndex; i++)
			{
				NodeP node = static_cast<NodeP> (new Node(male->at(i)->primitive_));
				child->push_back(node);
				child->at(i)->depth_ = male->at(i)->depth_;

			}

			// copy from female parent
			for (uint i = 0; i < female->at(fIndex)->size_; i++)
			{
				NodeP node = static_cast<NodeP> (new Node(female->at(fIndex + i)->primitive_));
				child->push_back(node);
			}

			// copy rest from male parent
			for (uint i = mIndex + male->at(mIndex)->size_; i < mRange; i++)
			{
				NodeP node = static_cast<NodeP> (new Node(male->at(i)->primitive_));
				child->push_back(node);
			}

			// update node depths and subtree sizes
			child->update();

			return true;
		}
bool TreeCrxOnePoint::mate(GenotypeP gen1, GenotypeP gen2, GenotypeP ch)
{
	Tree* male = (Tree*) (gen1.get());
	Tree* female = (Tree*) (gen2.get());
	Tree* child = (Tree*) (ch.get());

	uint mIndex, fIndex;
	uint mRange, fRange;
	uint mNodeDepth, fNodeDepth, fNodeDepthSize;

	mRange = (uint) male->size();
	fRange = (uint) female->size();

	// for common region nodes
	std::vector <uint> maleCommonRegionIndexes;	
	std::vector <uint> femaleCommonRegionIndexes;	

	for( uint iMale = 0, iFemale = 0; iMale < mRange && iFemale < fRange; iMale++, iFemale++ ) {
		// add common region nodes
		maleCommonRegionIndexes.push_back( iMale );
		femaleCommonRegionIndexes.push_back( iFemale );

		// skip nodes with different no. of arguments
		if( male->at( iMale )->primitive_->getNumberOfArguments() != female->at( iFemale )->primitive_->getNumberOfArguments() ) {
			iMale += male->at( iMale )->size_;
			iFemale += female->at( iFemale )->size_;
		}
	}

	uint nTries = 0;
	while(1) {
		// choose random node from common region
		uint randomNode = state_->getRandomizer()->getRandomInteger(0 , (uint) maleCommonRegionIndexes.size()-1 );
		mIndex = maleCommonRegionIndexes[ randomNode ];
		fIndex = femaleCommonRegionIndexes[ randomNode ];

		// LD: provjera dubine je redundantna u slucaju da sve jedinke imaju jednaki maxDepth_
		// ili kada otac ima veci ili jednak maxDepth_

		mNodeDepth = male->at( mIndex )->depth_;
		fNodeDepth = female->at( fIndex )->depth_;

		// find max depth
		int maxDepth = fNodeDepth, depth;
		for(uint i = 0; i < female->at( fIndex )->size_; i++) {
			depth = female->at( fIndex + i )->depth_;
			maxDepth = depth > maxDepth ? depth : maxDepth;
		}

		fNodeDepthSize = maxDepth - fNodeDepth;
		nTries++;

		if(nTries > 4 || mNodeDepth + fNodeDepthSize <= male->maxDepth_ ) break;
	}

	if(nTries > 4 && mNodeDepth + fNodeDepthSize > male->maxDepth_) {
		ECF_LOG(state_, 5, "TreeCrxOnePoint not successful.");
		return false;
	}

	child->clear();
	child->maxDepth_ = male->maxDepth_;
	child->minDepth_ = male->minDepth_;
	child->startDepth_ = male->startDepth_;

	// copy from male parent
	for(uint i = 0; i < mIndex; i++) {
		NodeP node = static_cast<NodeP> (new Node( male->at(i)->primitive_));
		child->push_back( node );
		child->at( i )->depth_ = male->at( i )->depth_;

	}
	// copy from female parent
	for(uint i = 0; i < female->at( fIndex )->size_; i++) {
		NodeP node = static_cast<NodeP> (new Node( female->at( fIndex + i)->primitive_));
		child->push_back( node );
	}
	// copy rest from male parent
	for(uint i = mIndex + male->at( mIndex )->size_; i < mRange; i++) {
		NodeP node = static_cast<NodeP> (new Node( male->at( i )->primitive_));
		child->push_back( node );
	}

	// update node depths and subtree sizes
	child->update();

	return true;
}
bool PSOInheritance::initialize(StateP state)
{
	// initialize all operators
	selBestOp->initialize(state);

	voidP weightType = getParameterValue(state, "weightType");
	m_weightType = *((InertiaWeightType*) weightType.get());

	voidP weight = getParameterValue(state, "weight");
	m_weight = *((double*) weight.get());

	voidP maxV = getParameterValue(state, "maxVelocity");
	m_maxV = *((double*) maxV.get());

	// test if inertia weight type is time variant and if so, check if max iterations specified
	if(m_weightType == TIME_VARIANT) {
		if(state->getRegistry()->isModified("term.maxgen")) {
			// read maxgen parameter
			m_maxIter = *(boost::static_pointer_cast<int>( state->getRegistry()->getEntry("term.maxgen") ));
		}
		else {
			ECF_LOG_ERROR(state, "Error: term.maxgen has to be specified in order to use time variant inertia eight in PSO algorithm");
			throw("");
		}
	}

	// algorithm accepts a single FloatingPoint Genotype
	FloatingPointP flp (new FloatingPoint::FloatingPoint);
	if(state->getGenotypes()[0]->getName() != flp->getName()) {
		ECF_LOG_ERROR(state, "Error: PSO algorithm accepts only a single FloatingPoint genotype!");
		throw ("");
	}

	voidP sptr = state->getGenotypes()[0]->getParameterValue(state, "dimension");
	uint numDimension = *((uint*) sptr.get());

	voidP bounded = getParameterValue(state, "bounded");
	bounded_ = *((bool*) bounded.get());

	sptr = state->getGenotypes()[0]->getParameterValue(state, "lbound");
	lbound_ = *((double*) sptr.get());

	sptr = state->getGenotypes()[0]->getParameterValue(state, "ubound");
	ubound_ = *((double*) sptr.get());

	// batch run check
	if(areGenotypesAdded_)
		return true;

	FloatingPointP flpoint[4];
	for(uint iGen = 1; iGen < 4; iGen++) {

		flpoint[iGen] = (FloatingPointP) new FloatingPoint::FloatingPoint;
		state->setGenotype(flpoint[iGen]);

		if(iGen == 3)
			flpoint[iGen]->setParameterValue(state, "dimension", (voidP) new uint(1));
		else
			flpoint[iGen]->setParameterValue(state, "dimension", (voidP) new uint(numDimension));

		// other parameters are proprietary (ignored by the algorithm)
		flpoint[iGen]->setParameterValue(state, "lbound", (voidP) new double(0));
		flpoint[iGen]->setParameterValue(state, "ubound", (voidP) new double(1));
	}
	ECF_LOG(state, 1, "PSO algorithm: added 3 FloatingPoint genotypes (particle velocity, best-so-far postition, best-so-far fitness value)");

	// mark adding of genotypes
	areGenotypesAdded_ = true;

	return true;
}
示例#13
0
bool TreeCrxSizeFair::mate(GenotypeP gen1, GenotypeP gen2, GenotypeP ch)
{
	Tree* male = (Tree*) (gen1.get());
	Tree* female = (Tree*) (gen2.get());
	Tree* child = (Tree*) (ch.get());

	uint mIndex, fIndex;
	uint mRange, fRange;
	uint mNodeDepth, fNodeDepth, fNodeDepthSize;

	mRange = (uint) male->size();
	fRange = (uint) female->size();

	// LD: femaleSizeIndexes[i] je vektor indeksa cvorova cija je velicina podstabla = i
	std::vector < std::vector<uint> > femaleSizeIndexes;

	femaleSizeIndexes.resize( fRange + 1 );	

	for(uint i = 0; i < fRange; i++) 
		femaleSizeIndexes[ female->at( i )->size_ ].push_back( i );	

	uint nTries = 0;
	while(1) {
		// choose random crx point in male parent
		mIndex = state_->getRandomizer()->getRandomInteger(0 , mRange -1 );

		// chose female crx point with expected size less or equal to the male's subtree
		uint subtreeSize = calculateSize (male->at( mIndex )->size_);
		while(1) {
			//LD: ako ne postoji podstablo trazene velicine, trazimo za jedan manje
			if( subtreeSize <= fRange && femaleSizeIndexes[ subtreeSize ].size()) break;		
			subtreeSize --;			
		}
		uint tmpRnd = state_->getRandomizer()->getRandomInteger(0 , (uint) femaleSizeIndexes[ subtreeSize ].size() - 1 );
		fIndex = femaleSizeIndexes[ subtreeSize ][ tmpRnd ];

		mNodeDepth = male->at( mIndex )->depth_;
		fNodeDepth = female->at( fIndex )->depth_;

		// find max depth
		int maxDepth = fNodeDepth, depth;
		for(uint i = 0; i < female->at( fIndex )->size_; i++) {
			depth = female->at( fIndex + i )->depth_;
			maxDepth = depth > maxDepth ? depth : maxDepth;
		}

		fNodeDepthSize = maxDepth - fNodeDepth;
		nTries++;

		if(nTries > 4 || mNodeDepth + fNodeDepthSize <= male->maxDepth_ ) break;
	}

	if(nTries > 4 && mNodeDepth + fNodeDepthSize > male->maxDepth_) {
		ECF_LOG(state_, 5, "TreeCrxSizeFair not successful.");
		return false;
	}

	child->clear();
	child->maxDepth_ = male->maxDepth_;
	child->minDepth_ = male->minDepth_;
	child->startDepth_ = male->startDepth_;

	// copy from male parent
	for(uint i = 0; i < mIndex; i++) {
		NodeP node = static_cast<NodeP> (new Node( male->at(i)->primitive_));
		child->push_back( node );
		child->at( i )->depth_ = male->at( i )->depth_;

	}
	// copy from female parent
	for(uint i = 0; i < female->at( fIndex )->size_; i++) {
		NodeP node = static_cast<NodeP> (new Node( female->at( fIndex + i)->primitive_));
		child->push_back( node );
	}
	// copy rest from male parent
	for(uint i = mIndex + male->at( mIndex )->size_; i < mRange; i++) {
		NodeP node = static_cast<NodeP> (new Node( male->at( i )->primitive_));
		child->push_back( node );
	}

	// update node depths and subtree sizes
	child->update();

	return true;
}