/// <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> /// 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); }