resultProcessingContext = 0;
if (branchUpdateThreshold == 0)
{
	branchUpdateThreshold = 10;
}

if (autoStepFlag == 0 || (rateClassesCount == startWithRateClasses))
{
	crapAIC 		 = -sortedScores[0][0];
	fprintf (stdout, "Baseline Model Fit\nc-AIC = ", crapAIC , "\nStarting the GA now...\n");
	startTimer		 = Time (1);

	if (MPI_NODE_COUNT>1)
	{
		MPINodeState = {MPI_NODE_COUNT-1,3};
	}

	/*---------------------------------------------------------------------------------------------------------------------------------------------
	  SPAWN INITIAL POPULATION; IT IS STORED AS GENERATING MATRICES
	---------------------------------------------------------------------------------------------------------------------------------------------*/

	optimizeBLFlag = 1;

	for (individual=0; individual<(populationSize-1) && individual<Abs(predef); individual = individual + 1)
	{
		aChild = Transpose(MakeStringCanonical (predef[individual],rateClassesCount));
		aaRateMultipliers = StringToMatrix(aChild);
		sortedScores[individual+1][1] = individual+1;
		currentPopulation[individual+1] = aChild;
		cString = aChild;
		RunASample (compressedString[rateClassesCount-1],individual+1);
	}

	optimizeBLFlag = 0;
	lastBranchAIC		     = crapAIC;
	finishedGenerations		 = 0;
}
else
{
	finishedGenerations	 = finishedGenerations + generationCount;
}
/*CleanUpMPI (0);*/

hitCount = 0;
for (individual=individual+1; individual<populationSize && (autoStepFlag == 0 || individual < populationSize $ 2 || rateClassesCount == startWithRateClasses); individual=individual+1)
{
	goOn = 1;
	while (goOn)
	{
		goOn = 0;
		cString = SpawnRandomString(rateClassesCount);
		for (v=0; v<individual; v=v+1)
		{
			if (Abs(cString-currentPopulation[v])==0)
			{
				if (hitCount < 20)
				{
					goOn = 1;
					hitCount = hitCount + 1;
				}
				else
				{
					hitCount = 0;
				}
				break;
			}
		}
	}
	aaRateMultipliers = StringToMatrix(cString);
	sortedScores[individual][1] = individual;
	currentPopulation[individual] = cString;
	RunASample (compressedString[rateClassesCount-1],individual);
}

CleanUpMPI (0);

sortedScores = sortedScores%0;
sampleProbs = {populationSize,1};

doMutation = 0;

lastImprovedGeneration   = 0;
lastBestAIC		  		 = 1e100;

/*---------------------------------------------------------------------------------------------------------------------------------------------
  RUNS THE CHC;
---------------------------------------------------------------------------------------------------------------------------------------------*/

for (generation=0; generation<generationCount; generation=generation+1)
{	
	timeSoFar = Time(1)-startTimer;
	
	if (Abs (addOnLine))
	{
		fprintf (stdout, "Generation ", generation+2, addOnLine);
	}
	else
	{
		fprintf (stdout, "Generation ", generation+2);	
	}
	
	fprintf (stdout, 
						   "\nBest c-AIC found far is ", -sortedScores[populationSize-1][0], 
						   "\nThis is a ", crapAIC+sortedScores[populationSize-1][0], " improvement over the single-rate model",
						   "\nGA has considered ", Abs (MasterList), " unique models so far",
						   "\nTotal run time so far is ", timeSoFar$3600, " hrs ", timeSoFar%3600$60, " mins ", timeSoFar%60, " seconds",
						   "\nAverage cluster time per generation is ", Format(timeSoFar/(finishedGenerations+generation+1),5, 2), " seconds",
						   "\nAverage CPU time per model is ", Format (timeSoFar/Abs(MasterList), 5, 2), " seconds ",
						   "\nConvergence criterion: ", generation-lastImprovedGeneration,"/", stoppingCriterion, "\n"); 

	if ((generation+1) % annealingPhase == 0)
	{
		mutationProb = Max(0.01,mutationProb*mutationProbDecrease);
	}
	doRepop = 1;
	doLocalMutation = generation-lastImprovedGeneration;
	doLocalMutation = doLocalMutation*((doLocalMutation % localMutationInterval) == 0);
	if (doMutation || doLocalMutation)
	{
		resultProcessingContext = 0;
		if (doLocalMutation)
		{
			mutProb = localMutationRate;
		}
		else
		{
			mutProb = mutationProb;
		}
		currentPopulationTrapper = {};
		for (v=0; v<populationSize; v=v+1)
		{
			currentPopulationTrapper [currentPopulation[v]] = 1;
		}
		
		for (individual=populationSize-2; individual>=0; individual=individual-1)
		{
			goOn = 1;
			hitCount = 0;
			while (goOn)
			{
				mpos = 0;
				goOn 	= 0;
				if (!doLocalMutation)
				{
					cString = currentPopulation[individual];
				}
				else
				{
					cString = currentPopulation[populationSize-1];
				}
				
				if (verboseFlag)
				{
					cString2 = cString["Random(0,rateClassesCount)$1"]["Random(0,1)<mutProb"];
					mpos = Abs(cString-cString2);
					cString = cString2;
				}
				else
				{
					cString = cString["Random(0,rateClassesCount)$1"]["Random(0,1)<mutProb"];
				}
				
				if (currentPopulationTrapper[cString])
				{
					if (hitCount < 20)
					{
						hitCount = hitCount+1;
						goOn = 1;
					}
					else
					{
						hitCount = 0;
						goOn = 0;
					}
				}

			}
			if (verboseFlag)
			{
				fprintf (stdout, "Mutated ", Format (mpos, 4, 0), " position in individual ", individual+1, "\n");
			}
			cString 					  = IsChildViable(MakeStringCanonical (cString,rateClassesCount));
			aaRateMultipliers 			  = StringToMatrix(cString);
			sortedScores[individual][1]   = individual;
			currentPopulation[individual] = cString;
			RunASample 						(compressedString[rateClassesCount-1],individual);
			currentPopulationTrapper		[cString] = 1;
		}		
		CleanUpMPI (0);
		doMutation = 0;
		sortedScores = sortedScores%0;
	}
	/* compute selection probabilities */
	ExportAMatrix (modelFile,StringToMatrix(currentPopulation[populationSize-1]),1,1);
	resultProcessingContext = 1;
	fitnessSum = 0;
	intermediateProbs = {populationSize+produceOffspring,2};
        
    if (matingChoice == 3)
    {
		lmatingChoice = Random(0,2.9999999999999)$1;
	}
	else
	{
		lmatingChoice = matingChoice;
	}
	
	for (individual=0; individual<populationSize; individual=individual+1)
	{
		if (lmatingChoice==0)
		{
			sampleProbs[individual] = Exp((sortedScores[individual][0]-sortedScores[populationSize-1][0])/2);
		}
		else
		{
			if (lmatingChoice == 1)
			{
				sampleProbs[individual] = 1;		
			}
			else
			{
				sampleProbs[individual] = 2*(individual+1);					
			}
		}
		intermediateProbs[individual][0] = sortedScores[individual][0];
		intermediateProbs[individual][1] = sortedScores[individual][1];
		fitnessSum = fitnessSum + sampleProbs[individual];
	}
	
	genBestAIC = -sortedScores[populationSize-1][0];
	
	if (verboseFlag)
	{
    	fprintf (stdout, "\n", lastBranchAIC, "\t", genBestAIC, "\n");
	}
	
	if (genBestAIC + 0.001 < lastBestAIC)
	{
		if (lastBranchAIC-genBestAIC > branchUpdateThreshold)
		{
			UpdateBL (0);
			lastBranchAIC = -sortedScores[populationSize-1][0];
			intermediateProbs[populationSize-1][0] = -lastBranchAIC;
			genBestAIC = lastBestAIC;
		}
		lastBestAIC = -sortedScores[populationSize-1][0];
		lastImprovedGeneration = generation;
	} 
	else
	{
		if (generation-lastImprovedGeneration>=stoppingCriterion)
		{
			break;
		}
	}
	
	sampleProbs = sampleProbs*(1/fitnessSum);
	
	if (verboseFlag)
	{
		fprintf (stdout, "\nMating probabilities\n");
		for (individual=0; individual<populationSize; individual=individual+1)
		{
			if (verboseFlag)
			{
				fprintf (stdout, "Individual ", Format(individual,3,0), ", sorted ", Format(sortedScores[individual][1],3,0), ". c-AIC: ", 
								  Format (sortedScores[individual][0], 8, 3), ", mating prob ", Format (sampleProbs[individual],6,4), ".\n");
			}
		}
	}
	
	children 	   = {};
	pairwiseCounts = {populationSize,populationSize};

	for (individual=0; individual<produceOffspring; individual=individual+1)
	{
		/* pick two individuals to produce offspring */
		/* pick 1st parent */
		h 			       = Random (0,1);
		fitnessSum		   = sampleProbs[0];
		v = 0;
		while (fitnessSum < h)
		{
			v = v+1;
			fitnessSum = fitnessSum + sampleProbs[v];
		}

		p1 			   = sortedScores[v][1];
		ps1			   = currentPopulation[p1];
		goOn 		   = 1;
		
		disallowedProbs 	= sampleProbs[v];
		
		for (sampleTry = 0; (sampleTry < maxSampleTries) && goOn; sampleTry = sampleTry + 1)
		{
			goOn 		   = 0;
			if (disallowedProbs<1)
			{
				h 			   = Random (0,1-disallowedProbs);
				if (v == 0)
				{
					fitnessSum	   = 0;			
				}
				else
				{
					fitnessSum	   = sampleProbs[0];
				}
				
				v2 = 0;
				while (fitnessSum < h)
				{
					v2 = v2 + 1;
					if (v2 == populationSize)
					{
						while (v2==v)
						{
							v2 = Min(Random (0,populationSize)$1,populationSize-1);
						}
						break;
					}
					if (v2!=v)
					{
						fitnessSum = fitnessSum + sampleProbs[v2];
					}
				}	
			}
			else
			{
				v2 = v;
				while (v2==v)
				{
					v2 = Min(Random (0,populationSize)$1,populationSize-1);
				}
			}
			
			if (v2 == populationSize)
			{
				goOn = 1;
				continue;
			}
			
			while (pairwiseCounts[v][v2] > familyControlSize)
			{
				v2 =  Min(Random (0,populationSize)$1,populationSize-1);
			}
			
			p2 = sortedScores[v2][1];
			ps2			   = currentPopulation[p2];
			fitnessSum 	   = 0;
			
			for (h=0; h<stateVectorDimension; h=h+1)
			{
				if (ps1[h] != ps2[h])
				{
					fitnessSum = fitnessSum+1;
					/*if (incestDistance<fitnessSum)
					{
						break;
					}*/
				}
			}
			if (incestDistance>=fitnessSum)
			{
				goOn = 1;
			}
			else
			{
				pairwiseCounts[v][v2] = pairwiseCounts[v][v2] + 1;
				pairwiseCounts[v2][v] = pairwiseCounts[v2][v] + 1;
			}
		}
		
		if (sampleTry == maxSampleTries)
		{
			doMutation = 1;
			/*
			generation = generation - 1;
			*/
			CleanUpMPI (0);
			doRepop = 0;
			break;
		}
		else
		{
			if (verboseFlag)
			{
				fprintf (stdout, "Mating ", p1, " and ", p2, ". Difference of ", fitnessSum, " positions\n");
			}
			
			cString = {stateVectorDimension,1} ["ps1[_MATRIX_ELEMENT_ROW_]+(ps2[_MATRIX_ELEMENT_ROW_]-ps1[_MATRIX_ELEMENT_ROW_])*(Random(0,1)<0.5)"];
				/*for (h=0; h<stateVectorDimension; h=h+1)
				{
					if (ps1[h] == ps2[h])
					{
						cString[h] = ps1[h];
					}
					else
					{
						if (Random(0,1)<0.5)
						{
							cString[h] = ps1[h];
						}
						else
						{
							cString[h] = ps2[h];					
						}
					}
				}*/
				
			cString 										= IsChildViable(MakeStringCanonical (cString,rateClassesCount));
			aaRateMultipliers 								= StringToMatrix(cString);
			intermediateProbs[populationSize+individual][1] = populationSize+individual;
			children  [individual] 							= cString;
			RunASample 										  (compressedString[rateClassesCount-1],populationSize+individual);
		}
	}
	CleanUpMPI (0);
	if (doRepop)
	{
		newPop = {};
		intermediateProbs = intermediateProbs%0;
		for (h=produceOffspring; h<populationSize+produceOffspring; h=h+1)
		{
			v = intermediateProbs[h][1];
			sortedScores[h-produceOffspring][1] = h-produceOffspring;
			sortedScores[h-produceOffspring][0] = intermediateProbs[h][0];		
			if (v<populationSize)
			{
				newPop[h-produceOffspring] = currentPopulation[v];
			}
			else
			{
				newPop[h-produceOffspring] = children[v-populationSize];
			}
		}
		for (h=0; h<populationSize; h=h+1)
		{
			currentPopulation[h] = newPop[h];
		}
		
		h = Abs((sortedScores[populationSize-1][0]-sortedScores[0][0])/sortedScores[0][0]);
		if (verboseFlag)
		{
			fprintf (stdout, "Diversity level: ", h, " (hypermutation threshold: ", mutationThreshhold, ")\n");	
		}
		if (h<mutationThreshhold)
		{
			if (verboseFlag)
			{
				fprintf (stdout, "\nTriggered hypermutation...\n");
			}
			doMutation = 1;
			/*
			generation = generation - 1;
			*/
		}
	}
}
