Ejemplo n.º 1
0
        /// <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);
        }