private void CrossOverParents( CandidateSolution <T, S> parent1, CandidateSolution <T, S> parent2, out CandidateSolution <T, S> child1, out CandidateSolution <T, S> child2) { // are we crossing over, or just copying a parent directly? child1 = parent1.Clone(); child2 = parent2.Clone(); // Do we use exact copies of parents, or crossover? if (Randomizer.GetDoubleFromZeroToOne() < CrossoverRate) { NodeBaseType <T, S> randomC1node, randomC2node; // pick a random node from both parents and clone the tree below it. // We don't want root nodes, since that's not really crossover, so we disallow those do { randomC1node = child1.SelectRandomNode(); } while (randomC1node == child1.Root); do { randomC2node = child2.SelectRandomNode(); } while (randomC2node == child2.Root); // make copies of them var newChild1 = randomC1node.Clone(null); var newChild2 = randomC2node.Clone(null); // create new children by swapping subtrees CandidateSolution <T, S> .SwapSubtrees(randomC1node, randomC2node, newChild1, newChild2); // and reset the pointers to the candidate child1.Root.SetCandidateRef(child1); child2.Root.SetCandidateRef(child2); } }
// Selection Routines ----------------------------------------------- private CandidateSolution <T, S> TournamentSelectParent() { CandidateSolution <T, S> result = null; float bestFitness = float.MaxValue; if (IsLowerFitnessBetter == false) { bestFitness = float.MinValue; } for (int i = 0; i < TourneySize; i++) { int index = Randomizer.IntLessThan(PopulationSize); var randomTree = currentGeneration[index]; var fitness = randomTree.Fitness; bool isFitnessBetter = false; if (IsLowerFitnessBetter) { isFitnessBetter = fitness < bestFitness; } else { isFitnessBetter = fitness > bestFitness; } if (isFitnessBetter) { result = randomTree; bestFitness = fitness; } } return(result); }
public override void SetCandidateRef(CandidateSolution <T, S> candidate) { ownerCandidate = candidate; // and get the descendants foreach (var child in Children) { child.SetCandidateRef(candidate); } }
public CandidateSolution <T, S> Clone() { // clone the tree object var newTree = new CandidateSolution <T, S>(primitiveSet, TreeMinDepth, TreeMaxDepth); // and all of the nodes in the tree newTree.Root = Root.Clone(null); return(newTree); }
public CandidateSolution <T, S> FindBestSolution() { // keep track of best overall, average fitness scores float bestFitnessScoreAllTime = (IsLowerFitnessBetter ? float.MaxValue : float.MinValue); float bestAverageFitnessScore = (IsLowerFitnessBetter ? float.MaxValue : float.MinValue); CandidateSolution <T, S> bestTreeAllTime = null; int bestSolutionGenerationNumber = 0, bestAverageFitnessGenerationNumber = 0; // elitism int numElitesToAdd = (int)(ElitismRate * PopulationSize); // depending on whether elitism is used, or the selection type, we may need to sort candidates by fitness (which is slower) bool needToSortByFitness = SelectionStyle == SelectionStyle.RouletteWheel || SelectionStyle == SelectionStyle.Ranked || ElitismRate > 0; Stopwatch timer = new Stopwatch(); // create an initial population of random trees, passing the possible functions, consts, and variables for (int p = 0; p < PopulationSize; p++) { CandidateSolution <T, S> tree = new CandidateSolution <T, S>(primitiveSet, RandomTreeMinDepth, RandomTreeMaxDepth); tree.CreateRandom(); currentGeneration.Add(tree); } // loop over generations int currentGenerationNumber = 0; while (true) { timer.Restart(); // for each tree, find and store the fitness score // multithread the fitness evaluation Parallel.ForEach(currentGeneration, (candidate) => { // calc the fitness by calling the user-supplied function via the delegate float fitness = myFitnessFunction(candidate); candidate.Fitness = fitness; }); // now check if we have a new best float bestFitnessScoreThisGeneration = (IsLowerFitnessBetter ? float.MaxValue : float.MinValue); CandidateSolution <T, S> bestTreeThisGeneration = null; float totalFitness = 0; foreach (var tree in currentGeneration) { totalFitness += tree.Fitness; // find best of this generation, update best all-time if needed bool isBestThisGeneration = false; if (IsLowerFitnessBetter) { isBestThisGeneration = tree.Fitness < bestFitnessScoreThisGeneration; } else { isBestThisGeneration = tree.Fitness > bestFitnessScoreThisGeneration; } if (isBestThisGeneration) { bestFitnessScoreThisGeneration = tree.Fitness; bestTreeThisGeneration = tree; bool isBestEver = false; if (IsLowerFitnessBetter) { isBestEver = bestFitnessScoreThisGeneration < bestFitnessScoreAllTime; } else { isBestEver = bestFitnessScoreThisGeneration > bestFitnessScoreAllTime; } if (isBestEver) { bestFitnessScoreAllTime = bestFitnessScoreThisGeneration; bestTreeAllTime = tree.Clone(); bestSolutionGenerationNumber = currentGenerationNumber; } } } // determine average fitness and store if it's all-time best float averageFitness = totalFitness / PopulationSize; if (IsLowerFitnessBetter) { if (averageFitness < bestAverageFitnessScore) { bestAverageFitnessGenerationNumber = currentGenerationNumber; bestAverageFitnessScore = averageFitness; } } else { if (averageFitness > bestAverageFitnessScore) { bestAverageFitnessGenerationNumber = currentGenerationNumber; bestAverageFitnessScore = averageFitness; } } // report progress back to the user, and allow them to terminate the loop EngineProgress progress = new EngineProgress() { GenerationNumber = currentGenerationNumber, AvgFitnessThisGen = averageFitness, BestFitnessThisGen = bestFitnessScoreThisGeneration, BestFitnessSoFar = bestFitnessScoreAllTime, TimeForGeneration = timer.Elapsed }; bool keepGoing = myProgressFunction(progress); if (!keepGoing) { break; // user signalled to end looping } // termination conditions if (currentGenerationNumber >= MinGenerations) { // exit the loop if we're not making any progress in our average fitness score if ((currentGenerationNumber - bestAverageFitnessGenerationNumber) >= StagnantGenerationLimit) { break; } // maxed out? if (currentGenerationNumber >= MaxGenerations) { break; } } // we may need to sort the current generation by fitness, depending on SelectionStyle if (needToSortByFitness) { if (IsLowerFitnessBetter) { currentGeneration = currentGeneration.OrderBy(c => c.Fitness).ToList(); } else { currentGeneration = currentGeneration.OrderByDescending(c => c.Fitness).ToList(); } } // depending on the SelectionStyle, we may need to adjust all candidate's fitness scores AdjustFitnessScores(currentGeneration); // Start building the next generation List <CandidateSolution <T, S> > nextGeneration = new List <CandidateSolution <T, S> >(); // Elitism var theBest = currentGeneration.Take(numElitesToAdd); foreach (var peakPerformer in theBest) { nextGeneration.Add(peakPerformer); } // now create a new generation using fitness scores for selection, and crossover and mutation while (nextGeneration.Count < PopulationSize) { // select parents CandidateSolution <T, S> parent1 = null, parent2 = null; switch (SelectionStyle) { case SelectionStyle.Tourney: parent1 = TournamentSelectParent(); parent2 = TournamentSelectParent(); break; case SelectionStyle.RouletteWheel: case SelectionStyle.Ranked: parent1 = RouletteSelectParent(); parent2 = RouletteSelectParent(); break; } // cross them over to generate two new children CandidateSolution <T, S> child1, child2; CrossOverParents(parent1, parent2, out child1, out child2); // Mutation if (Randomizer.GetFloatFromZeroToOne() < MutationRate) { child1.Mutate(); } if (Randomizer.GetFloatFromZeroToOne() < MutationRate) { child2.Mutate(); } // then add to the new generation nextGeneration.Add(child1); nextGeneration.Add(child2); } // move to the next generation currentGeneration = nextGeneration; currentGenerationNumber++; } bestTreeAllTime.Root.SetCandidateRef(bestTreeAllTime); return(bestTreeAllTime); }
public FunctionNode(FunctionMetaData <T> function, CandidateSolution <T, S> candidate) { functionMetadata = function; Children = new List <NodeBaseType <T, S> >(function.NumArguments); ownerCandidate = candidate; }
public TerminalFunctionNode(FunctionMetaData <T> function, CandidateSolution <T, S> candidate) { functionMetadata = function; ownerCandidate = candidate; }
public override void SetCandidateRef(CandidateSolution <T, S> candidate) { ownerCandidate = candidate; }