/// <summary> /// Generates a random individual. /// </summary> /// <param name="solver"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> Generate( Solver <List <int>, GeneticProblem, Fitness> solver) { // create new genomes list. List <int> genome = new List <int>(); // build cities to place (in a thread-safe way!) List <int> cities_to_place = new List <int>(); lock (solver) { for (int idx = 0; idx < solver.Problem.Along.Count; idx++) { cities_to_place.Add(solver.Problem.Along[idx]); } } BestPlacementHelper helper = BestPlacementHelper.Instance(); helper.DoFast( solver.Problem, solver.FitnessCalculator as FitnessCalculator, genome, cities_to_place); Individual individual = new Individual(genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
/// <summary> /// Generates a random individual. /// </summary> /// <param name="solver"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> Generate( Solver <List <int>, GeneticProblem, Fitness> solver) { List <int> genome = new List <int>(); List <int> node_indexes = new List <int>(); for (int i = 0; i < solver.Problem.Along.Count; i++) { node_indexes.Add(i); } for (int i = 0; i < solver.Problem.Along.Count; i++) { // get the random idx. int idx = solver.Random.Next(node_indexes.Count); // get the node at the given idx. genome.Add(solver.Problem.Along[node_indexes[idx]]); node_indexes.RemoveAt(idx); // remove the idx. } Individual individual = new Individual(genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
/// <summary> /// Re-places all the cities again to their own best place. /// </summary> /// <param name="solver"></param> /// <param name="mutating"></param> /// <returns></returns> private Individual <List <int>, GeneticProblem, Fitness> MutateByRePlacement( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> mutating) { List <int> nodes_to_re_place = mutating.Genomes.ToList <int>(); List <int> current_placement = mutating.Genomes.ToList <int>(); foreach (int node_to_place in nodes_to_re_place) { // take the node out. current_placement.Remove(node_to_place); // place the node back in. BestPlacementHelper helper = BestPlacementHelper.Instance(); helper.Do( solver.Problem, solver.FitnessCalculator as FitnessCalculator, current_placement, node_to_place); } Individual individual = new Individual(current_placement); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
/// <summary> /// Places a city into an idividual. /// </summary> /// <param name="problem"></param> /// <param name="calculator"></param> /// <param name="round_idx"></param> /// <param name="individual"></param> /// <param name="city_to_place"></param> /// <returns></returns> internal static BestPlacementResult CalculateBestPlacementInIndividual( Problem problem, FitnessCalculator calculator, int round_idx, Individual <List <Genome>, Problem, Fitness> individual, int city_to_place) { // if the target round is empty best placement is impossible. Genome round = individual.Genomes[round_idx]; // do best placement in the genome/round. BestPlacementResult result = BestPlacementHelper.CalculateBestPlacementInGenome(problem, calculator, round, city_to_place); // set the round index. result.RoundIdx = round_idx; if (!individual.FitnessCalculated) { individual.CalculateFitness( problem, calculator); } result.Fitness = calculator.Adjust( problem, individual.Fitness, round_idx, result.Increase); // return the result. return(result); }
/// <summary> /// Mutates a given individual. /// </summary> /// <param name="solver"></param> /// <param name="mutating"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> Mutate( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> mutating) { // take a random piece. int idx = solver.Random.Next(mutating.Genomes.Count); List <int> new_genome = new List <int>(mutating.Genomes); int customer = new_genome[idx]; new_genome.RemoveAt(idx); // apply best placement algorithm to place the selected genomes. BestPlacementHelper helper = BestPlacementHelper.Instance(); helper.Do( solver.Problem, solver.FitnessCalculator as FitnessCalculator, new_genome, customer); Individual individual = new Individual(new_genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
/// <summary> /// Generates a random individual. /// </summary> /// <param name="solver"></param> /// <returns></returns> public Individual<List<int>, GeneticProblem, Fitness> Generate( Solver<List<int>, GeneticProblem, Fitness> solver) { ISolver lk_solver = new HillClimbing3OptSolver(true, true); IRoute route = lk_solver.Solve(solver.Problem.BaseProblem); List<int> new_genome = new List<int>(); bool first_found = false; foreach (int customer in route) { if (first_found) { new_genome.Add(customer); } if (customer == 0) { first_found = true; } } foreach (int customer in route) { if (customer == 0) { break; } new_genome.Add(customer); } Individual individual = new Individual(new_genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return individual; }
public void Should_Return_Correct_Fitness(string target, string genes, double fitness) { var sut = new Individual(genes.ToCharArray(), Random); sut.CalculateFitness(target.ToCharArray()); Assert.Equal(fitness, sut.Fitness); }
/// <summary> /// Mutates an idividual. /// </summary> /// <param name="solver"></param> /// <param name="mutating"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> Mutate( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> mutating) { List <int> genome = new List <int>(mutating.Genomes); if (solver.Random.Next(2) > 0) { // switch two nodes. int idx1 = solver.Random.Next(genome.Count); int idx2 = solver.Random.Next(genome.Count); if (idx1 != idx2) { int temp = genome[idx1]; genome[idx1] = genome[idx2]; genome[idx2] = temp; } } else { // switch two nodes. int idx1 = solver.Random.Next(genome.Count); int idx2 = solver.Random.Next(genome.Count); // make sure idx1 < idx2. if (idx1 > idx2) { int idx_temp = idx2; idx2 = idx1; idx1 = idx_temp; } // switch order. if (idx1 != idx2) { List <int> genomes_to_change = new List <int>(); for (int idx = idx1; idx <= idx2; idx++) { genomes_to_change.Add(genome[idx]); } genomes_to_change.Reverse(); int idx_list = 0; for (int idx = idx1; idx <= idx2; idx++) { genome[idx] = genomes_to_change[idx_list]; idx_list++; } } } Individual individual = new Individual(genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
/// <summary> /// Generates a random individual. /// </summary> /// <param name="solver"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> Generate( Solver <List <int>, GeneticProblem, Fitness> solver) { ISolver lk_solver = new LinKernighanSolver(); IRoute route = lk_solver.Solve(solver.Problem.BaseProblem); Individual individual = new Individual(new List <int>(route)); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
public void Should_Calculate_Fitness() { const string targetString = "sample text"; var sut = new Individual("sample other".ToCharArray(), Random); var oldFitness = sut.Fitness; sut.CalculateFitness(targetString.ToCharArray()); Assert.NotEqual(sut.Fitness, oldFitness); }
public void Should_Return_Correct_String_Representation() { const string s = "*****@*****.**"; var sut = new Individual(s.ToCharArray(), Random); sut.CalculateFitness(s.ToCharArray()); Assert.Equal(1d, sut.Fitness); Assert.Equal($"fitness: 100.00% - phrase: {s}", sut.ToString()); }
/// <summary> /// Take a piece of the genome and re-do best placement. /// </summary> /// <param name="solver"></param> /// <param name="mutating"></param> /// <returns></returns> private Individual <List <int>, GeneticProblem, Fitness> MutateByTakingPiece( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> mutating) { // take a random piece. int idx1 = 0; int idx2 = 0; while (idx2 - idx1 == 0) { idx1 = solver.Random.Next(mutating.Genomes.Count - 1) + 1; idx2 = solver.Random.Next(mutating.Genomes.Count - 1) + 1; if (idx1 > idx2) { int temp = idx1; idx1 = idx2; idx2 = temp; } } // if the genome range is big take it from the best individual. Individual <List <int>, GeneticProblem, Fitness> source = (mutating as Individual <List <int>, GeneticProblem, Fitness>); Individual <List <int>, GeneticProblem, Fitness> target = (mutating as Individual <List <int>, GeneticProblem, Fitness>); List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1); List <int> new_genome = target.Genomes.GetRange(0, target.Genomes.Count); // insert the piece into the worst individual. // remove nodes in the source_piece. foreach (int source_node in source_piece) { new_genome.Remove(source_node); } // apply best placement algorithm to place the selected genomes. //List<int> genome = new List<int>(); BestPlacementHelper helper = BestPlacementHelper.Instance(); helper.DoFast( solver.Problem, solver.FitnessCalculator as FitnessCalculator, new_genome, source_piece); Individual individual = new Individual(new_genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
static string SimpleReplacement_Hack() { List <Individual> generation = GetFirstGeneration(); Individual best = new Individual(generation[0]); Stopwatch sw = Stopwatch.StartNew(); best.CalculateFitness(); int i = 0; while (true) { Parallel.ForEach(generation, x => x.CalculateFitness()); generation.Sort((x, y) => x.Fitness.CompareTo(y.Fitness)); Console.WriteLine($"[Gen {++i,4}] {generation[0].Fitness}"); if (generation[0].Fitness < best.Fitness) { best = generation[0]; } if (Math.Abs(SourseFitness - generation[0].Fitness) < FitnessDelta || i >= MaxGenerations) { break; } generation = Crossover(generation); Parallel.ForEach(generation, x => x.CalculateFitness()); generation.Sort((x, y) => x.Fitness.CompareTo(y.Fitness)); Mutation(generation); } Console.WriteLine(); Console.WriteLine($"[Total generations] {i}"); Console.WriteLine($"[Total time(sec)] {sw.Elapsed.TotalSeconds}"); Console.WriteLine($"[Average ms/gen] {(double)sw.ElapsedMilliseconds / i}"); Console.WriteLine($"[Best fitness] {best.Fitness}"); return(ByteArrToString(SimpleReplacement_Decode(best.Key))); }
static List <Individual> GetFirstGeneration() { Random random = new Random(Guid.NewGuid().GetHashCode()); Individual[] keys = new Individual[PopulationSize]; Parallel.For(0, PopulationSize, i => { byte[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; Individual ind = new Individual(new List <byte>(arr).OrderBy(x => random.Next()).ToArray()); ind.CalculateFitness(); while (ind.Fitness > FirstPopulationMinFitness) { ind = new Individual(new List <byte>(arr).OrderBy(x => random.Next()).ToArray()); ind.CalculateFitness(); } keys[i] = ind; }); return(keys.ToList()); }
/// <summary> /// Applies this operation. /// </summary> /// <param name="solver"></param> /// <param name="parent1"></param> /// <param name="parent2"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> CrossOver( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> parent1, Individual <List <int>, GeneticProblem, Fitness> parent2) { OsmSharp.Math.TSP.Problems.IProblem tsp_problem = solver.Problem.BaseProblem; // first create E_a int[] e_a = new int[parent1.Genomes.Count + 1]; e_a[0] = parent1.Genomes[0]; for (int idx = 0; idx < parent1.Genomes.Count - 1; idx++) { int from = parent1.Genomes[idx]; int to = parent1.Genomes[idx + 1]; e_a[from] = to; } e_a[parent1.Genomes[parent1.Genomes.Count - 1]] = 0; // create E_b int[] e_b = new int[parent2.Genomes.Count + 1]; e_b[0] = parent2.Genomes[0]; for (int idx = 0; idx < parent2.Genomes.Count - 1; idx++) { int from = parent2.Genomes[idx]; int to = parent2.Genomes[idx + 1]; e_b[from] = to; } e_b[parent2.Genomes[parent2.Genomes.Count - 1]] = 0; // create G_ab. Dictionary <int, int> g_a = new Dictionary <int, int>(); Dictionary <int, int> g_b_opposite = new Dictionary <int, int>(); for (int idx = 0; idx < e_b.Length; idx++) { if (e_a[idx] != e_b[idx]) { g_a.Add(idx, e_a[idx]); g_b_opposite.Add(e_b[idx], idx); } } List <Dictionary <int, KeyValuePair <int, int> > > cycles = new List <Dictionary <int, KeyValuePair <int, int> > >(); while (g_a.Count > 0) { int first = g_a.Keys.First <int>(); KeyValuePair <int, int> next_pair; Dictionary <int, KeyValuePair <int, int> > cycle = new Dictionary <int, KeyValuePair <int, int> >(); while (!cycle.ContainsKey(first)) { next_pair = new KeyValuePair <int, int>(g_a[first], g_b_opposite[g_a[first]]); // remove. g_a.Remove(first); g_b_opposite.Remove(next_pair.Key); cycle.Add(first, next_pair); // get all the nexts ones. first = next_pair.Value; } cycles.Add(cycle); } int generated = 0; Individual best = null; while (generated < _max_offspring) { // select some random cycles. List <Dictionary <int, KeyValuePair <int, int> > > selected_cycles = this.SelectCycles(cycles); // take e_a and remove all edges that are in the selected cycles and replace them by the eges // from e_b in the cycles. foreach (Dictionary <int, KeyValuePair <int, int> > cycle in selected_cycles) { foreach (KeyValuePair <int, KeyValuePair <int, int> > pair in cycle) { e_a[pair.Value.Value] = pair.Value.Key; } } // construct all subtours. List <Dictionary <int, KeyValuePair <int, double> > > subtours = new List <Dictionary <int, KeyValuePair <int, double> > >(); List <int> e_a_list = new List <int>(e_a); int start_idx = 0; while (start_idx < e_a_list.Count) { Dictionary <int, KeyValuePair <int, double> > current_tour = new Dictionary <int, KeyValuePair <int, double> >(); int from = start_idx; int to = e_a_list[from]; while (to >= 0) { e_a_list[from] = -1; current_tour.Add(from, new KeyValuePair <int, double>(to, tsp_problem.WeightMatrix[from][to])); from = to; to = e_a_list[from]; } for (start_idx = start_idx + 1; start_idx < e_a_list.Count; start_idx++) { if (e_a_list[start_idx] >= 0) { break; } } subtours.Add(current_tour); } while (subtours.Count > 1) { int size = e_a.Length; Dictionary <int, KeyValuePair <int, double> > current_tour = null; foreach (Dictionary <int, KeyValuePair <int, double> > tour in subtours) { if (current_tour == null || tour.Count < current_tour.Count) { current_tour = tour; } } // merge two tours. Dictionary <int, KeyValuePair <int, double> > target_tour = null; double weight = double.MaxValue; KeyValuePair <int, KeyValuePair <int, double> > from = new KeyValuePair <int, KeyValuePair <int, double> >(); KeyValuePair <int, KeyValuePair <int, double> > to = new KeyValuePair <int, KeyValuePair <int, double> >(); // first try nn approach. if (_nn) { foreach (KeyValuePair <int, KeyValuePair <int, double> > from_pair in current_tour) { foreach (int nn in tsp_problem.Get10NearestNeighbours(from_pair.Key)) { if (!current_tour.ContainsKey(nn)) { foreach (Dictionary <int, KeyValuePair <int, double> > target in subtours) { KeyValuePair <int, double> to_pair_value; if (target.TryGetValue(nn, out to_pair_value)) { double merge_weight = (tsp_problem.WeightMatrix[from_pair.Key][to_pair_value.Key] + tsp_problem.WeightMatrix[nn][from_pair.Value.Key]) - (from_pair.Value.Value + to_pair_value.Value); if (merge_weight < weight) { weight = merge_weight; from = from_pair; to = new KeyValuePair <int, KeyValuePair <int, double> >(nn, to_pair_value); target_tour = target; } } } } } } } if (target_tour == null) { foreach (KeyValuePair <int, KeyValuePair <int, double> > from_pair in current_tour) { foreach (Dictionary <int, KeyValuePair <int, double> > target in subtours) { if (target != current_tour) { foreach (KeyValuePair <int, KeyValuePair <int, double> > to_pair in target) { double merge_weight = (tsp_problem.WeightMatrix[from_pair.Key][to_pair.Value.Key] + tsp_problem.WeightMatrix[to_pair.Key][from_pair.Value.Key]) - (from_pair.Value.Value + to_pair.Value.Value); if (merge_weight < weight) { weight = merge_weight; from = from_pair; to = to_pair; target_tour = target; } } } } } } // merge the tours. subtours.Remove(current_tour); foreach (KeyValuePair <int, KeyValuePair <int, double> > for_target in current_tour) { target_tour.Add(for_target.Key, for_target.Value); } target_tour[from.Key] = new KeyValuePair <int, double>(to.Value.Key, tsp_problem.WeightMatrix[from.Key][to.Value.Key]); target_tour[to.Key] = new KeyValuePair <int, double>(from.Value.Key, tsp_problem.WeightMatrix[to.Key][from.Value.Key]); } List <int> new_genome = new List <int>(); int next = subtours[0][0].Key; do { new_genome.Add(next); next = subtours[0][next].Key; }while (next != 0); Individual individual = new Individual(new_genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); if (best == null || best.Fitness.CompareTo(individual.Fitness) > 0) { best = individual; } generated++; } return(best); }
/// <summary> /// Calculates/generates a next generation based on the given one. /// </summary> /// <param name="population"></param> /// <returns></returns> private Population <GenomeType, ProblemType, WeightType> NextGeneration(Population <GenomeType, ProblemType, WeightType> population) { Population <GenomeType, ProblemType, WeightType> next_population = new Population <GenomeType, ProblemType, WeightType>(true); // do elitims selection. int elitism_count = (int)(population.Count * (_settings.ElitismPercentage / 100f)); next_population.AddRange( population.GetRange( 0, elitism_count)); // do selection/cross-over. //Tools.Core.Output.OutputTextStreamHost.Write(" C:"); int cross_over_count = (int)(population.Count * (_settings.CrossOverPercentage / 100f)) + elitism_count; while (next_population.Count < cross_over_count && next_population.Count < population.Count) { // select two individuals. Individual <GenomeType, ProblemType, WeightType> individual1 = _selector.Select( this, population, null); Individual <GenomeType, ProblemType, WeightType> individual2 = _selector.Select( this, population, new HashSet <Individual <GenomeType, ProblemType, WeightType> >( new Individual <GenomeType, ProblemType, WeightType>[] { individual1 })); // cross-over. Individual <GenomeType, ProblemType, WeightType> new_individual = _crossOverOperation.CrossOver( this, individual1, individual2); new_individual.CalculateFitness(_problem, _fitness_calculator); if (_accept_only_better_on_cross_over) { if (new_individual.Fitness.CompareTo(individual1.Fitness) < 0 && new_individual.Fitness.CompareTo(individual2.Fitness) < 0) { // add to the new population. next_population.Add(new_individual); } else { //next_population.Add(individual1); if (individual2.Fitness.CompareTo(individual1.Fitness) < 0) { // add to the new population. next_population.Add(individual2); } else { next_population.Add(individual1); } } } else { // add to the new population. next_population.Add(new_individual); } //this.ReportNew("Crossing over population!", next_population.Count, population.Count); //Tools.Core.Output.OutputTextStreamHost.Write("."); } // do mutation to generate the rest of the population. int mutation_count = (int)(population.Count * (_settings.MutationPercentage / 100f)) + cross_over_count; int mutation_count_max_tries = mutation_count * 2; // try mutation 10 times more. int mutation_idx_absolute = 0; //Tools.Core.Output.OutputTextStreamHost.Write(" m:"); while (next_population.Count < mutation_count && next_population.Count < population.Count) { // get random individual. int individual_to_mutate_idx = this.Random.Next(population.Count); Individual <GenomeType, ProblemType, WeightType> individual_to_mutate = population[individual_to_mutate_idx]; // mutate. Individual <GenomeType, ProblemType, WeightType> mutation = _mutation_operation.Mutate( this, individual_to_mutate); //if (!mutation.Equals(individual_to_mutate)) //{ // do not add indentical ones. // add to population. if (_accept_only_better_on_mutation) { mutation.CalculateFitness(_problem, _fitness_calculator); if (mutation.Fitness.CompareTo(individual_to_mutate.Fitness) < 0) { next_population.Add(mutation); } } else { next_population.Add(mutation); } // //Tools.Core.Output.OutputTextStreamHost.Write("."); // this.ReportNew("Mutating population!", next_population.Count, population.Count); //} // increase the absolute count. mutation_idx_absolute++; if (mutation_idx_absolute > mutation_count_max_tries) { // stop trying to mutate not new individuals could be found. break; } } while (next_population.Count < population.Count) { // get random individual. int individual_to_mutate_idx = this.Random.Next(population.Count); Individual <GenomeType, ProblemType, WeightType> individual = population[individual_to_mutate_idx]; // place in the new population. next_population.Add(individual); this.ReportNew("Filling population!", next_population.Count, population.Count); } return(next_population); }
/// <summary> /// Crosses over the two indivduals using sequantial contructive crossover. /// </summary> /// <param name="solver"></param> /// <param name="parent1"></param> /// <param name="parent2"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> CrossOver( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> parent1, Individual <List <int>, GeneticProblem, Fitness> parent2) { List <int> new_individual = new List <int>(); HashSet <int> selected_nodes = new HashSet <int>(); List <int> non_selected_nodes = new List <int>(parent1.Genomes); // build the edge list. int edges = 1; if (solver.Problem.First != solver.Problem.Last) { edges = 2; } int[] edges_in_parent1 = new int[parent1.Genomes.Count + edges]; int[] edges_in_parent2 = new int[parent1.Genomes.Count + edges]; edges_in_parent1[solver.Problem.First] = -1; edges_in_parent1[solver.Problem.Last] = -1; edges_in_parent2[solver.Problem.First] = -1; edges_in_parent2[solver.Problem.Last] = -1; for (int idx = 0; idx < parent1.Genomes.Count - 1; idx++) { edges_in_parent1[parent1.Genomes[idx]] = parent1.Genomes[idx + 1]; edges_in_parent2[parent2.Genomes[idx]] = parent2.Genomes[idx + 1]; } edges_in_parent1[parent1.Genomes[parent1.Genomes.Count - 1]] = -1; edges_in_parent2[parent2.Genomes[parent2.Genomes.Count - 1]] = -1; // start with the first node. int selected_node = parent1.Genomes[0]; new_individual.Add(selected_node); selected_nodes.Add(selected_node); non_selected_nodes.Remove(selected_node); // find the next legitimate node in both. double total_weight = solver.Problem.Weight(solver.Problem.First, selected_node); while (non_selected_nodes.Count > 0) { int node_parent1 = edges_in_parent1[selected_node]; bool node_parent1_found = false; int node_parent2 = edges_in_parent2[selected_node]; bool node_parent2_found = false; // find a node for parent1 if no legitimate one was found. if (node_parent1 >= 0) { node_parent1_found = (!selected_nodes.Contains(node_parent1)); edges_in_parent1[selected_node] = -1; } // find a node for parent2 if no legitimate one was found. if (node_parent2 >= 0) { node_parent2_found = (!selected_nodes.Contains(node_parent2)); edges_in_parent2[selected_node] = -1; } // find a node for parent1 if no legitimate one was found. if (!node_parent1_found) { // Select the first node just like that! node_parent1 = non_selected_nodes[0]; } // find a node for parent2 if no legitimate one was found. if (!node_parent2_found) { // Select the first node just like that! node_parent2 = non_selected_nodes[0]; } // select one of two if (node_parent1 == node_parent2) { total_weight = total_weight + solver.Problem.Weight(selected_node, node_parent2); selected_node = node_parent1; } else { double weight1 = solver.Problem.Weight(selected_node, node_parent1); double weight2 = solver.Problem.Weight(selected_node, node_parent2); if (weight1 < weight2) { selected_node = node_parent1; total_weight = total_weight + weight1; } else { selected_node = node_parent2; total_weight = total_weight + weight2; } } total_weight = total_weight + solver.Problem.Weight(selected_node, solver.Problem.Last); // update data structures. new_individual.Add(selected_node); selected_nodes.Add(selected_node); non_selected_nodes.Remove(selected_node); //if (non_selected_nodes.Count + selected_nodes.Count != parent1.Genomes.Count) //{ // Console.WriteLine("HELP"); //} } Individual individual = new Individual(new_individual); //individual.CalculateFitness(total_weight); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); //if (individual.Count > parent1.Genomes.Count) //{ // Console.WriteLine("HELP"); //} return(individual); }
/// <summary> /// Returns a solution found using best-placement. /// </summary> /// <returns></returns> protected override IRoute DoSolve(OsmSharp.Math.TSP.Problems.IProblem problem) { // create the settings. SolverSettings settings = new SolverSettings( -1, -1, 1000000000, -1, -1, -1); Solver <List <int>, GeneticProblem, Fitness> solver = new Solver <List <int>, GeneticProblem, Fitness>( new GeneticProblem(problem), settings, null, null, null, _generation_operation, new FitnessCalculator(), true, false); Population <List <int>, GeneticProblem, Fitness> population = new Population <List <int>, GeneticProblem, Fitness>(true); while (population.Count < _population_size) { // generate new. Individual <List <int>, GeneticProblem, Fitness> new_individual = _generation_operation.Generate(solver); // add to population. population.Add(new_individual); } // select each individual once. Population <List <int>, GeneticProblem, Fitness> new_population = new Population <List <int>, GeneticProblem, Fitness>(true); Individual <List <int>, GeneticProblem, Fitness> best = null; int stagnation = 0; while (stagnation < _stagnation) { while (new_population.Count < _population_size) { // select an individual and the next one. int idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(population.Count); Individual <List <int>, GeneticProblem, Fitness> individual1 = population[idx]; Individual <List <int>, GeneticProblem, Fitness> individual2 = null; if (idx == population.Count - 1) { individual2 = population[0]; } else { individual2 = population[idx + 1]; } population.RemoveAt(idx); Individual <List <int>, GeneticProblem, Fitness> new_individual = _cross_over_operation.CrossOver(solver, individual1, individual2); new_individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); if (new_individual.Fitness.CompareTo( individual1.Fitness) < 0) { new_population.Add(new_individual); } else { new_population.Add(individual1); } } population = new_population; population.Sort(solver, solver.FitnessCalculator); new_population = new Population <List <int>, GeneticProblem, Fitness>(true); if (best == null || best.Fitness.CompareTo(population[0].Fitness) > 0) { stagnation = 0; best = population[0]; } else { stagnation++; } // report progress. OsmSharp.Logging.Log.TraceEvent("EdgeAssemblyCrossOverSolver", Logging.TraceEventType.Information, string.Format("Solving using EAX: Stagnation {0}.", stagnation)); } var result = new List <int>(best.Genomes); result.Insert(0, 0); return(DynamicAsymmetricRoute.CreateFrom(result)); }
CrossOver(Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> parent1, Individual <List <int>, GeneticProblem, Fitness> parent2) { // take a random piece. int idx1 = 0; int idx2 = 0; while (idx2 - idx1 == 0) { idx1 = solver.Random.Next(parent1.Genomes.Count - 1) + 1; idx2 = solver.Random.Next(parent2.Genomes.Count - 1) + 1; if (idx1 > idx2) { int temp = idx1; idx1 = idx2; idx2 = temp; } } // if the genome range is big take it from the best individual. Individual <List <int>, GeneticProblem, Fitness> source = (parent1 as Individual <List <int>, GeneticProblem, Fitness>); Individual <List <int>, GeneticProblem, Fitness> target = (parent2 as Individual <List <int>, GeneticProblem, Fitness>); if (idx2 - idx1 < parent1.Genomes.Count / 2) { // the range is small; take the worste genomes. if (source.Fitness.CompareTo(target.Fitness) > 0) { Individual <List <int>, GeneticProblem, Fitness> temp = source; source = target; target = temp; } else { // do nothing. } } else { // the range is big; take the good genomes. if (source.Fitness.CompareTo(target.Fitness) > 0) { // do nothing. } else { Individual <List <int>, GeneticProblem, Fitness> temp = source; source = target; target = temp; } } List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1); List <int> new_genome = target.Genomes.GetRange(0, target.Genomes.Count); // insert the piece into the worst individual. // remove nodes in the source_piece. foreach (int source_node in source_piece) { new_genome.Remove(source_node); } // apply best placement algorithm to place the selected genomes. //List<int> genome = new List<int>(); BestPlacementHelper helper = BestPlacementHelper.Instance(); helper.DoFast( solver.Problem, solver.FitnessCalculator as FitnessCalculator, new_genome, source_piece); // return a new individual based on the new genome list. Individual individual = new Individual(new_genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
/// <summary> /// Applies this operation. /// </summary> /// <param name="solver"></param> /// <param name="parent1"></param> /// <param name="parent2"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> CrossOver( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> parent1, Individual <List <int>, GeneticProblem, Fitness> parent2) { // take a random piece. int idx1 = solver.Random.Next(parent1.Genomes.Count - 1) + 1; int idx2 = solver.Random.Next(parent1.Genomes.Count - 1) + 1; if (idx1 > idx2) { int temp = idx1; idx1 = idx2; idx2 = temp; } // if the genome range is big take it from the best individual. Individual <List <int>, GeneticProblem, Fitness> source = (parent1 as Individual <List <int>, GeneticProblem, Fitness>); Individual <List <int>, GeneticProblem, Fitness> target = (parent2 as Individual <List <int>, GeneticProblem, Fitness>); if (idx2 - idx1 < parent1.Genomes.Count / 2) { // the range is small; take the worste genomes. if (source.Fitness.CompareTo(target.Fitness) > 0) { Individual <List <int>, GeneticProblem, Fitness> temp = source; source = target; target = temp; } else { // do nothing. } } else { // the range is big; take the good genomes. if (source.Fitness.CompareTo(target.Fitness) > 0) { // do nothing. } else { Individual <List <int>, GeneticProblem, Fitness> temp = source; source = target; target = temp; } } List <int> source_piece = source.Genomes.GetRange(idx1, idx2 - idx1); List <int> new_genome = target.Genomes.GetRange(0, target.Genomes.Count); // insert the piece into the worst individual. // remove nodes in the source_piece. foreach (int source_node in source_piece) { new_genome.Remove(source_node); } // insert the source_piece at index1 new_genome.InsertRange(idx1, source_piece); Individual individual = new Individual(new List <int>(new_genome)); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }
/// <summary> /// Applies this crossover operation. /// </summary> /// <param name="solver"></param> /// <param name="parent1"></param> /// <param name="parent2"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> CrossOver( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> parent1, Individual <List <int>, GeneticProblem, Fitness> parent2) { OsmSharp.Math.TSP.Problems.IProblem tsp_problem = solver.Problem.BaseProblem; double[][] weights = tsp_problem.WeightMatrix; // first create E_a AsymmetricCycles e_a = new AsymmetricCycles(parent1.Genomes.Count + 1); e_a.AddEdge(0, parent1.Genomes[0]); for (int idx = 0; idx < parent1.Genomes.Count - 1; idx++) { int from = parent1.Genomes[idx]; int to = parent1.Genomes[idx + 1]; e_a.AddEdge(from, to); } e_a.AddEdge(parent1.Genomes[parent1.Genomes.Count - 1], 0); // create E_b int[] e_b = new int[parent2.Genomes.Count + 1]; e_b[parent2.Genomes[0]] = 0; for (int idx = 0; idx < parent2.Genomes.Count - 1; idx++) { int from = parent2.Genomes[idx]; int to = parent2.Genomes[idx + 1]; e_b[to] = from; } e_b[0] = parent2.Genomes[parent2.Genomes.Count - 1]; // create cycles. AsymmetricAlternatingCycles cycles = new AsymmetricAlternatingCycles( parent2.Genomes.Count + 1); for (int idx = 0; idx < e_b.Length; idx++) { int a = e_a[idx]; int b = e_b[a]; if (idx != b) { cycles.AddEdge(idx, a, b); } } // the cycles that can be selected. List <int> selectable_cycles = new List <int>(cycles.Cycles.Keys); int generated = 0; Individual best = null; while (generated < _max_offspring && selectable_cycles.Count > 0) { // select some random cycles. List <int> cycle_starts = this.SelectCycles(selectable_cycles); // copy if needed. AsymmetricCycles a = null; if (_max_offspring > 1) { a = e_a.Clone(); } else { a = e_a; } // take e_a and remove all edges that are in the selected cycles and replace them by the eges int[] next_array_a = a.NextArray; foreach (int start in cycle_starts) { int current = start; KeyValuePair <int, int> current_next = cycles.Next(current); do { a.AddEdge(current_next.Value, current_next.Key); current = current_next.Value; current_next = cycles.Next(current); } while(current != start); } // connect all subtoures. int cycle_count = a.Cycles.Count; while (cycle_count > 1) { // get the smallest tour. KeyValuePair <int, int> current_tour = new KeyValuePair <int, int>(-1, int.MaxValue); foreach (KeyValuePair <int, int> tour in a.Cycles) { if (tour.Value < current_tour.Value) { current_tour = tour; } } // first try nn approach. double weight = double.MaxValue; int selected_from1 = -1; int selected_from2 = -1; int selected_to1 = -1; int selected_to2 = -1; bool[] ignore_list = new bool[a.Length]; int from; int to; from = current_tour.Key; ignore_list[from] = true; //ignore_list.Add(from); to = next_array_a[from]; do { // step to the next ones. from = to; to = next_array_a[from]; //ignore_list.Add(from); ignore_list[from] = true; } while (from != current_tour.Key); if (_nn) { // only try tours containing nn. from = current_tour.Key; to = next_array_a[from]; double weight_from_to = weights[from][to]; do { // check the nearest neighbours of from foreach (int nn in tsp_problem.Get10NearestNeighbours(from)) { int nn_to = next_array_a[nn]; //if (!ignore_list.Contains(nn) && // !ignore_list.Contains(nn_to)) if (!ignore_list[nn] && !ignore_list[nn_to]) { double merge_weight = (weights[from][nn_to] + weights[nn][to]) - (weight_from_to + weights[nn][nn_to]); if (weight > merge_weight) { weight = merge_weight; selected_from1 = from; selected_from2 = nn; selected_to1 = to; selected_to2 = nn_to; } } } // step to the next ones. from = to; to = next_array_a[from]; } while (from != current_tour.Key); } if (selected_from2 < 0) { // check the nearest neighbours of from foreach (int customer in parent1.Genomes) { int customer_to = next_array_a[customer]; //if (!ignore_list.Contains(customer) && // !ignore_list.Contains(customer_to)) if (!ignore_list[customer] && !ignore_list[customer_to]) { double merge_weight = (weights[from][customer_to] + weights[customer][to]) - (weights[from][to] + weights[customer][customer_to]); if (weight > merge_weight) { weight = merge_weight; selected_from1 = from; selected_from2 = customer; selected_to1 = to; selected_to2 = customer_to; } } } } //if (selected_from1 >= 0) //{ a.AddEdge(selected_from1, selected_to2); a.AddEdge(selected_from2, selected_to1); //} //else //{ // throw new Exception(); //} cycle_count--; } //if (a.Cycles.Values.First<int>() != a.Length) //{ // throw new Exception(); //} List <int> new_genome = new List <int>(a.Length); int next = next_array_a[0]; do { new_genome.Add(next); next = next_array_a[next]; }while (next != 0); Individual individual = new Individual(new_genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); if (best == null || best.Fitness.CompareTo(individual.Fitness) > 0) { best = individual; } generated++; } if (best == null) { List <int> new_genome = new List <int>(); int next = e_a[0]; do { new_genome.Add(next); next = e_a[next]; }while (next != 0); Individual individual = new Individual(new_genome); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); if (best == null || best.Fitness.CompareTo(individual.Fitness) > 0) { best = individual; } } return(best); }
/// <summary> /// Places a city into an idividual. /// </summary> /// <param name="problem"></param> /// <param name="calculator"></param> /// <param name="round_idx"></param> /// <param name="individual"></param> /// <param name="city_to_place"></param> /// <returns></returns> internal static BestPlacementResult CalculateBestPlacementInIndividual( Problem problem, FitnessCalculator calculator, int round_idx, Individual<List<Genome>, Problem, Fitness> individual, int city_to_place) { // if the target round is empty best placement is impossible. Genome round = individual.Genomes[round_idx]; // do best placement in the genome/round. BestPlacementResult result = BestPlacementHelper.CalculateBestPlacementInGenome(problem, calculator, round, city_to_place); // set the round index. result.RoundIdx = round_idx; if (!individual.FitnessCalculated) { individual.CalculateFitness( problem, calculator); } result.Fitness = calculator.Adjust( problem, individual.Fitness, round_idx, result.Increase); // return the result. return result; }
/// <summary> /// Applies this operation. /// </summary> /// <param name="solver"></param> /// <param name="parent1"></param> /// <param name="parent2"></param> /// <returns></returns> public Individual <List <int>, GeneticProblem, Fitness> CrossOver( Solver <List <int>, GeneticProblem, Fitness> solver, Individual <List <int>, GeneticProblem, Fitness> parent1, Individual <List <int>, GeneticProblem, Fitness> parent2) { List <int> new_individual = new List <int>(); HashSet <int> selected_cities = new HashSet <int>(); List <int> non_selected_cities = new List <int>(parent1.Genomes); // build the edge list. Dictionary <int, HashSet <int> > edges_in_parents = new Dictionary <int, HashSet <int> >(); for (int idx = 0; idx < parent1.Genomes.Count; idx++) { int city = parent1.Genomes[idx]; HashSet <int> city_edges = null; if (!edges_in_parents.TryGetValue(city, out city_edges)) { city_edges = new HashSet <int>(); edges_in_parents.Add(city, city_edges); } int next_idx = idx + 1; if (next_idx >= parent1.Genomes.Count) { next_idx = 0; } city_edges.Add(parent1.Genomes[next_idx]); city = parent2.Genomes[idx]; if (!edges_in_parents.TryGetValue(city, out city_edges)) { city_edges = new HashSet <int>(); edges_in_parents.Add(city, city_edges); } next_idx = idx + 1; if (next_idx >= parent2.Genomes.Count) { next_idx = 0; } city_edges.Add(parent2.Genomes[next_idx]); } // select the initial city. int selected_city = parent1.Genomes[0]; if (edges_in_parents[parent2.Genomes[0]].Count < edges_in_parents[parent1.Genomes[0]].Count) { selected_city = parent2.Genomes[0]; } new_individual.Add(selected_city); selected_cities.Add(selected_city); non_selected_cities.Remove(selected_city); while (non_selected_cities.Count > 0) { // select the next city. HashSet <int> edges_of_current = edges_in_parents[selected_city]; edges_in_parents.Remove(selected_city); if (edges_of_current.Count > 0) { int edge_count = parent1.Genomes.Count; List <int> minimum_edges = new List <int>(); // build a list of cities with the minimum neighbour count. foreach (int edge_of_current in edges_of_current) { HashSet <int> edges_of_edge = null; if (edges_in_parents.TryGetValue(edge_of_current, out edges_of_edge)) { int count = 0; foreach (int edge_of_edge in edges_of_edge) { if (!selected_cities.Contains(edge_of_edge)) { count++; } } if (count < edge_count) { minimum_edges.Clear(); minimum_edges.Add(edge_of_current); edge_count = count; } else if (count == edge_count) { minimum_edges.Add(edge_of_current); } } } // randomly select one. if (minimum_edges.Count != 0) { selected_city = minimum_edges[Math.Random.StaticRandomGenerator.Get().Generate(minimum_edges.Count)]; } else { selected_city = non_selected_cities[Math.Random.StaticRandomGenerator.Get().Generate(non_selected_cities.Count)]; } } else { // randomly select a city. selected_city = non_selected_cities[Math.Random.StaticRandomGenerator.Get().Generate(non_selected_cities.Count)]; } new_individual.Add(selected_city); selected_cities.Add(selected_city); non_selected_cities.Remove(selected_city); } Individual individual = new Individual(new_individual); individual.CalculateFitness(solver.Problem, solver.FitnessCalculator); return(individual); }