private void CrossOverParents(CandidateSolution parent1, CandidateSolution parent2, out CandidateSolution child1, out CandidateSolution child2) { child1 = parent1.DeepClone(); child2 = parent2.DeepClone(); //use exact copies or do crossover if (Randomizer.GetDoubleFromZeroToOne() < crossoverRate) { int numItems = parent1.Meals.Count; int crossoverPoint = Randomizer.IntLessThan(numItems); for (int i = 0; i < crossoverPoint; i++) { child1.SetSelected(i, parent1.IsSelected(i)); child2.SetSelected(i, parent2.IsSelected(i)); } for (int i = crossoverPoint; i < numItems; i++) { child1.SetSelected(i, parent2.IsSelected(i)); child2.SetSelected(i, parent1.IsSelected(i)); } } }
public MealCollection FindOptimalItems(MealCollection meals, NutritionConstraints constraints) { currentGeneration = new List <CandidateSolution>(populationSize); for (int i = 0; i < populationSize; i++) { currentGeneration.Add(new CandidateSolution(meals, constraints)); } generationNumber = 1; //main loop while (true) { float bestFitnessScoreThisGeneration = System.Int32.MaxValue; CandidateSolution bestSolutionThisGeneration = null; foreach (var candidate in currentGeneration) { candidate.Repair(); float fitness = candidate.Fitness; //sum up fitness scores for the roulette wheel selection totalFitnessThisGeneration += fitness; totalInverseFitnessThisGeneration += 1 / (double)fitness; if (fitness < bestFitnessScoreThisGeneration) { bestFitnessScoreThisGeneration = fitness; bestSolutionThisGeneration = candidate; } } Debug.WriteLine("Iteration count {0}, best fitness: {1}", generationNumber, bestFitnessScoreAllTime); //compare this generation's best to to the best we had so far if (bestFitnessScoreThisGeneration < bestFitnessScoreAllTime) { //save the best score bestFitnessScoreAllTime = bestFitnessScoreThisGeneration; //and save possible solution bestSolution = bestSolutionThisGeneration.DeepClone(); bestSolutionGenerationNumber = generationNumber; } else { if ((generationNumber - bestSolutionGenerationNumber) > MaxGenerationsWithNoChange) { break; } } List <CandidateSolution> nextGeneration = new List <CandidateSolution>(); while (nextGeneration.Count < populationSize) { //Select two parents(the lower the fitness, the higher the chance of selection) var parent1 = SelectCandidate(); var parent2 = SelectCandidate(); //cross them over to generate two new children CandidateSolution child1, child2; CrossOverParents(parent1, parent2, out child1, out child2); //appy mutation if needed child1.AddPossibleMutation(mutationRate); child2.AddPossibleMutation(mutationRate); //add them to next generation nextGeneration.Add(child1); nextGeneration.Add(child2); } currentGeneration = nextGeneration; generationNumber++; } return(bestSolution.GetSelectedItems()); }
internal CandidateSolution DeepClone() { var clone = new CandidateSolution(Meals, NutritionConstraints, isSelected); return(clone); }