/// <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);
        }
Esempio n. 2
0
        /// <summary>
        /// Applies this operator using the given solutions and produces a new solution.
        /// </summary>
        /// <returns></returns>
        public Tour Apply(TSProblem problem, TSPObjective objective, Tour solution1, Tour solution2, out float fitness)
        {
            if (solution1.Last != problem.Last)
            {
                throw new ArgumentException("Route and problem have to have the same last customer.");
            }
            if (solution2.Last != problem.Last)
            {
                throw new ArgumentException("Route and problem have to have the same last customer.");
            }

            var originalProblem   = problem;
            var originalSolution1 = solution1;
            var originalSolution2 = solution2;

            if (!problem.Last.HasValue)
            { // convert to closed problem.
                Logger.Log("EAXOperator.Apply", Logging.TraceEventType.Warning,
                           string.Format("EAX operator cannot be applied to 'open' TSP's: converting problem and routes to a closed equivalent."));

                problem   = problem.ToClosed();
                solution1 = new Tour(solution1, 0);
                solution2 = new Tour(solution2, 0);
            }
            else if (problem.First != problem.Last)
            { // last is set but is not the same as first.
                Logger.Log("EAXSolver.Solve", Logging.TraceEventType.Warning,
                           string.Format("EAX operator cannot be applied to 'closed' TSP's with a fixed endpoint: converting problem and routes to a closed equivalent."));

                problem   = problem.ToClosed();
                solution1 = new Tour(solution1, 0);
                solution2 = new Tour(solution2, 0);
                solution1.Remove(originalProblem.Last.Value);
                solution2.Remove(originalProblem.Last.Value);
            }
            fitness = float.MaxValue;
            var weights = problem.Weights;

            // first create E_a
            var e_a = new AsymmetricCycles(solution1.Count);

            foreach (var edge in solution1.Pairs())
            {
                e_a.AddEdge(edge.From, edge.To);
            }

            // create E_b
            var e_b = new int[solution2.Count];

            foreach (var edge in solution2.Pairs())
            {
                e_b[edge.To] = edge.From;
            }

            // create cycles.
            var cycles = new AsymmetricAlternatingCycles(solution2.Count);

            for (var idx = 0; idx < e_b.Length; idx++)
            {
                var a = e_a[idx];
                if (a != Constants.NOT_SET)
                {
                    var b = e_b[a];
                    if (idx != b && b != Constants.NOT_SET)
                    {
                        cycles.AddEdge(idx, a, b);
                    }
                }
            }

            // the cycles that can be selected.
            var selectableCycles = new List <int>(cycles.Cycles.Keys);

            int  generated = 0;
            Tour best      = null;

            while (generated < _maxOffspring &&
                   selectableCycles.Count > 0)
            {
                // select some random cycles.
                var cycleStarts = this.SelectCycles(selectableCycles);

                // copy if needed.
                AsymmetricCycles a = null;
                if (_maxOffspring > 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
                var nextArrayA = a.NextArray;
                foreach (int start in cycleStarts)
                {
                    var current     = start;
                    var currentNext = cycles.Next(current);
                    do
                    {
                        a.AddEdge(currentNext.Value, currentNext.Key);

                        current     = currentNext.Value;
                        currentNext = cycles.Next(current);
                    } while (current != start);
                }

                // connect all subtoures.
                var cycleCount = a.Cycles.Count;
                while (cycleCount > 1)
                {
                    // get the smallest tour.
                    var currentTour = new KeyValuePair <int, int>(-1, int.MaxValue);
                    foreach (KeyValuePair <int, int> tour in a.Cycles)
                    {
                        if (tour.Value < currentTour.Value)
                        {
                            currentTour = tour;
                        }
                    }

                    // first try nn approach.
                    var weight        = double.MaxValue;
                    var selectedFrom1 = -1;
                    var selectedFrom2 = -1;
                    var selectedTo1   = -1;
                    var selectedTo2   = -1;

                    var ignoreList = new bool[a.Length];
                    int from;
                    int to;
                    from             = currentTour.Key;
                    ignoreList[from] = true;
                    to = nextArrayA[from];
                    do
                    {
                        // step to the next ones.
                        from = to;
                        to   = nextArrayA[from];

                        //ignore_list.Add(from);
                        ignoreList[from] = true;
                    } while (from != currentTour.Key);

                    if (_nn)
                    { // only try tours containing nn.
                        from = currentTour.Key;
                        to   = nextArrayA[from];
                        var weightFromTo = weights[from][to];
                        do
                        {
                            // check the nearest neighbours of from
                            foreach (var nn in problem.GetNNearestNeighboursForward(10, from))
                            {
                                var nnTo = nextArrayA[nn];

                                if (nnTo != Constants.NOT_SET &&
                                    !ignoreList[nn] &&
                                    !ignoreList[nnTo])
                                {
                                    float mergeWeight =
                                        (weights[from][nnTo] + weights[nn][to]) -
                                        (weightFromTo + weights[nn][nnTo]);
                                    if (weight > mergeWeight)
                                    {
                                        weight        = mergeWeight;
                                        selectedFrom1 = from;
                                        selectedFrom2 = nn;
                                        selectedTo1   = to;
                                        selectedTo2   = nnTo;
                                    }
                                }
                            }

                            // step to the next ones.
                            from = to;
                            to   = nextArrayA[from];
                        } while (from != currentTour.Key);
                    }
                    if (selectedFrom2 < 0)
                    {
                        // check the nearest neighbours of from
                        foreach (var customer in solution1)
                        {
                            int customerTo = nextArrayA[customer];

                            if (!ignoreList[customer] &&
                                !ignoreList[customerTo])
                            {
                                var mergeWeight =
                                    (weights[from][customerTo] + weights[customer][to]) -
                                    (weights[from][to] + weights[customer][customerTo]);
                                if (weight > mergeWeight)
                                {
                                    weight        = mergeWeight;
                                    selectedFrom1 = from;
                                    selectedFrom2 = customer;
                                    selectedTo1   = to;
                                    selectedTo2   = customerTo;
                                }
                            }
                        }
                    }

                    a.AddEdge(selectedFrom1, selectedTo2);
                    a.AddEdge(selectedFrom2, selectedTo1);

                    cycleCount--;
                }

                var newRoute = new Tour(new int[] { problem.First }, problem.Last);
                var previous = problem.First;
                var next     = nextArrayA[problem.First];
                do
                {
                    newRoute.InsertAfter(previous, next);
                    previous = next;
                    next     = nextArrayA[next];
                }while (next != Constants.NOT_SET &&
                        next != problem.First);

                var newFitness = 0.0f;
                foreach (var edge in newRoute.Pairs())
                {
                    newFitness = newFitness + weights[edge.From][edge.To];
                }

                if (newRoute.Count == solution1.Count)
                {
                    if (best == null ||
                        fitness > newFitness)
                    {
                        best    = newRoute;
                        fitness = newFitness;
                    }

                    generated++;
                }
            }

            if (best == null)
            {
                best = new Tour(new int[] { problem.First }, problem.Last);
                var previous = problem.First;
                var next     = e_a[problem.First];
                do
                {
                    best.InsertAfter(previous, next);
                    previous = next;
                    next     = e_a[next];
                }while (next != Constants.NOT_SET &&
                        next != problem.First);

                fitness = 0.0f;
                foreach (var edge in best.Pairs())
                {
                    fitness = fitness + weights[edge.From][edge.To];
                }
            }

            if (!originalProblem.Last.HasValue)
            { // original problem as an 'open' problem, convert to an 'open' route.
                best    = new Tour(best, null);
                fitness = objective.Calculate(problem, best);
            }
            else if (originalProblem.First != originalProblem.Last)
            { // original problem was a problem with a fixed last point different from the first point.
                best.InsertAfter(System.Linq.Enumerable.Last(best), originalProblem.Last.Value);
                best    = new Tour(best, problem.Last.Value);
                fitness = objective.Calculate(originalProblem, best);
            }
            return(best);
        }