コード例 #1
0
        private IRoute Improve(MaxTimeProblem problem,
                               MaxTimeSolution solution, double max, int currentRouteIdx)
        {
            // the current route.
            IRoute currentRoute = solution.Route(currentRouteIdx);

            for (int routeIdx = 0; routeIdx < solution.Count; routeIdx++)
            { // apply the intra-route heurstic between the new and all existing routes.
                if (routeIdx != currentRouteIdx &&
                    this.Overlaps(problem, solution.Route(routeIdx), solution.Route(currentRouteIdx)))
                {     // only check routes that overlap.
                    if (this.ImproveInterRoute(problem, solution, routeIdx, currentRouteIdx, max))
                    { // an improvement was found, again to the intra operators.
                        if (!solution.IsValid())
                        {
                            throw new Exception();
                        }

                        solution[currentRouteIdx] = this.ImproveIntraRoute(problem, currentRoute, solution[currentRouteIdx]);
                        solution[routeIdx]        = this.ImproveIntraRoute(problem, solution.Route(routeIdx), solution[routeIdx]);

                        // recalculate weights.
                        solution[currentRouteIdx] = problem.Time(solution.Route(currentRouteIdx));
                        solution[routeIdx]        = problem.Time(solution.Route(routeIdx));
                    }
                }
            }

            return(solution.Route(solution.Count - 1));
        }
コード例 #2
0
        /// <summary>
        /// Selects a new seed customer.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="solution"></param>
        /// <param name="customers"></param>
        /// <returns></returns>
        private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator,
                               MaxTimeSolution solution, List <int> customers)
        {
            int    selected_customer = -1;
            double max_distance      = double.MaxValue;

            foreach (int customer_to_check in customers)
            {
                SortedDictionary <double, List <int> > neighbours = new SortedDictionary <double, List <int> >();
                for (int idx = 0; idx < customers.Count; idx++)
                {
                    int customer = customers[idx];
                    if (customer != customer_to_check)
                    {
                        double weight = problem.WeightMatrix[customer_to_check][customer] +
                                        problem.WeightMatrix[customer_to_check][customer];
                        List <int> customers_list = null;
                        if (!neighbours.TryGetValue(weight, out customers_list))
                        {
                            customers_list = new List <int>();
                            neighbours.Add(weight, customers_list);
                        }
                        customers_list.Add(customer);
                    }
                }

                double nearest_neighbour_average = 0;
                int    neighbour_count           = 20;
                int    neighbour_counted         = 0;
                foreach (KeyValuePair <double, List <int> > pair in neighbours)
                {
                    foreach (int customer in pair.Value)
                    {
                        if (neighbour_counted < neighbour_count)
                        {
                            neighbour_counted++;
                            nearest_neighbour_average = nearest_neighbour_average +
                                                        pair.Key;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                if (max_distance > nearest_neighbour_average)
                {
                    max_distance      = nearest_neighbour_average;
                    selected_customer = customer_to_check;
                }
            }
            return(selected_customer);
        }
コード例 #3
0
 /// <summary>
 /// Tries to improve the existing routes by re-inserting a customer from one route into another.
 /// </summary>
 /// <param name="problem"></param>
 /// <param name="solution"></param>
 /// <param name="route1_idx"></param>
 /// <param name="route2_idx"></param>
 /// <param name="max"></param>
 /// <returns></returns>
 public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
     int route1_idx, int route2_idx, double max)
 {
     if (this.RelocateFromTo(problem, solution, route1_idx, route2_idx, max))
     {
         return true;
     }
     if (this.RelocateFromTo(problem, solution, route2_idx, route1_idx, max))
     {
         return true;
     }
     return false;
 }
コード例 #4
0
 /// <summary>
 /// Tries to improve the existing routes by re-inserting a customer from one route into another.
 /// </summary>
 /// <param name="problem"></param>
 /// <param name="solution"></param>
 /// <param name="route1_idx"></param>
 /// <param name="route2_idx"></param>
 /// <param name="max"></param>
 /// <returns></returns>
 public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
                     int route1_idx, int route2_idx, double max)
 {
     if (this.RelocateFromTo(problem, solution, route1_idx, route2_idx, max))
     {
         return(true);
     }
     if (this.RelocateFromTo(problem, solution, route2_idx, route1_idx, max))
     {
         return(true);
     }
     return(false);
 }
コード例 #5
0
        void solver_NewFittest(Individual <MaxTimeSolution, MaxTimeProblem, Fitness> solution)
        {
            long ticks_after = DateTime.Now.Ticks;

            MaxTimeSolution routes = solution.Genomes;

            if (output_each)
            {
                StringBuilder sizes = new StringBuilder();
                foreach (int size in routes.Sizes)
                {
                    sizes.Append(size);
                    sizes.Append(" ");
                }

                StringBuilder weights = new StringBuilder();
                foreach (double weight in solution.Fitness.Weights)
                {
                    weights.Append(weight.ToString(CultureInfo.InvariantCulture));
                    weights.Append(" ");
                }

                StringBuilder probalities = new StringBuilder();
                foreach (double prod in _probabilities)
                {
                    probalities.Append(prod.ToString(CultureInfo.InvariantCulture));
                    probalities.Append(";");
                }


                string settings_string = string.Format("{0};{1};{2};{3};{4};{5};{6};{7};",
                                                       _customers.Count, this.Max.Value,
                                                       _stagnation, _population, _max_generations, _elitism_percentage, _cross_percentage, _mutation_percentage);

                //output.Close();
                //output.Dispose();
                //output_file = null;
            }

            //Genome routes = individual.Genomes[0];
            // TODO: convert solution.
            int[][] result = new int[routes.Count][];
            for (int idx = 0; idx < routes.Count; idx++)
            {
                IRoute route = routes.Route(idx);
                result[idx] = route.ToArray();
            }

            this.RaiseIntermidiateResult(result);
        }
コード例 #6
0
        /// <summary>
        /// Selects a new seed customer.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="solution"></param>
        /// <param name="customers"></param>
        /// <returns></returns>
        private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator,
                               MaxTimeSolution solution, List <int> customers)
        { // select the customer farthest from the depot.
            int    selectedCustomer = -1;
            double maxDistance      = double.MinValue;

            foreach (int customerToCheck in customers)
            {
                double distance = problem.WeightMatrix[0][customerToCheck] +
                                  problem.WeightMatrix[customerToCheck][0];
                if (distance > maxDistance)
                {
                    maxDistance      = distance;
                    selectedCustomer = customerToCheck;
                }
            }
            return(selectedCustomer);
        }
コード例 #7
0
        void solver_NewGeneration(int generation, int stagnation_count, Population <MaxTimeSolution, MaxTimeProblem, Fitness> population)
        {
            generations++;

            long ticks_after = DateTime.Now.Ticks;

            Individual <MaxTimeSolution, MaxTimeProblem, Fitness> solution = population[0];

            MaxTimeSolution routes = solution.Genomes;

            if (output_each)
            {
                StringBuilder sizes = new StringBuilder();
                foreach (int size in routes.Sizes)
                {
                    sizes.Append(size);
                    sizes.Append(" ");
                }

                StringBuilder weights = new StringBuilder();
                foreach (double weight in solution.Fitness.Weights)
                {
                    weights.Append(weight.ToString(CultureInfo.InvariantCulture));
                    weights.Append(" ");
                }

                StringBuilder probalities = new StringBuilder();
                foreach (double prod in _probabilities)
                {
                    probalities.Append(prod.ToString(CultureInfo.InvariantCulture));
                    probalities.Append(";");
                }


                string settings_string = string.Format("{0};{1};{2};{3};{4};{5};{6};{7};",
                                                       _customers.Count, this.Max.Value,
                                                       _stagnation, _population, _max_generations, _elitism_percentage, _cross_percentage, _mutation_percentage);
                //output.Close();
                //output.Dispose();
                //output_file = null;
            }
        }
コード例 #8
0
        /// <summary>
        /// Calculates the tot weight of one solution.
        /// </summary>
        /// <param name="solution"></param>
        /// <returns></returns>
        public double Calculate(MaxTimeSolution solution)
        {
            int vehicles = solution.Count;

            //            List<double> above_max = new List<double>();
            double total = 0;
            double total_above_max = 0;
            int total_count_above_max = 0;
            double max = -1;
            List<double> weights = new List<double>();
            for (int route_idx = 0; route_idx < solution.Count; route_idx++)
            {
                double weight = this.CalculateOneRoute(solution.Route(
                    route_idx));
                weights.Add(weight);
                total = total + weight;
                if (weight > _problem.Max.Value)
                {
                    total_above_max = total_above_max +
                        (weight - _problem.Max.Value);
                    total_count_above_max++;
                }
                if (max < weight)
                {
                    max = weight;
                }
            }

            //double above_max_factor = 3;
            // multiply with the maximum.
            //fitness.ActualFitness = (vehicles * ((total_above_max) + total));
            //fitness.ActualFitness = (vehicles * ((total_above_max * max) + total));
            //fitness.ActualFitness = (vehicles * ((System.Math.Pow(total_above_max, 1.28)) + total + max));
            return (vehicles * System.Math.Pow(total_above_max, 4)) + total;
            ////fitness.ActualFitness = (vehicles * (total + ((total_count_above_max * above_max_factor) * max)));
            ////fitness.ActualFitness = (total + ((total_count_above_max * above_max_factor) * max));
            //fitness.Vehicles = vehicles;
            //fitness.TotalTime = total;
            //fitness.TotalAboveMax = total_above_max;
            //return fitness;
        }
コード例 #9
0
        /// <summary>
        /// Tries a relocation of the customers in route1 to route2.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private bool RelocateFromTo(MaxTimeProblem problem, MaxTimeSolution solution,
                                    int route1_idx, int route2_idx, double max)
        {
            int previous = -1;
            int current  = -1;

            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            double route2_weight = solution[route2_idx];

            foreach (int next in route1)
            {
                if (previous >= 0 && current >= 0)
                { // consider the next customer.
                    int count_before1 = route1.Count;
                    int count_before2 = route2.Count;

//                    string route1_string = route1.ToString();
//                    string route2_string = route2.ToString();

                    if (this.ConsiderCustomer(problem, route2, previous, current, next, route2_weight, max))
                    {
                        route1.ReplaceEdgeFrom(previous, next);

                        int count_after = route1.Count + route2.Count;
                        if ((count_before1 + count_before2) != count_after)
                        {
                            throw new Exception();
                        }
                        return(true);
                    }
                }

                previous = current;
                current  = next;
            }

            return(false);
        }
コード例 #10
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            var solution = new MaxTimeSolution(problem.Size);

            // keep placing customer until none are left.
            var customers = new List<int>(problem.Customers);
            customers.RemoveAt(0);

            double max = problem.Max.Value - (problem.Max.Value * _deltaPercentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs = new BinaryHeapInsertionCosts();
            //            double percentage = _thresholdPercentage;
            while (customers.Count > 0)
            {
                //// try and distribute the remaining customers if there are only a few left.
                //if (customers.Count < problem.Size * percentage)
                //{
                //    bool succes = true;
                //    while (succes && customers.Count > 0)
                //    {
                //        succes = false;
                //        CheapestInsertionResult best = new CheapestInsertionResult();
                //        best.Increase = float.MaxValue;
                //        int best_idx = -1;
                //        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                //        {
                //            IRoute route = solution.Route(route_idx);
                //            CheapestInsertionResult result =
                //                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                //            if (best.Increase > result.Increase)
                //            {
                //                best = result;
                //                best_idx = route_idx;
                //            }
                //        }

                //        IRoute best_route = solution.Route(best_idx);
                //        double route_time = problem.Time(best_route);
                //        if (route_time + best.Increase < max)
                //        { // insert the customer.
                //            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                //            customers.Remove(best.Customer);

                //            this.Improve(problem, solution, max, best_idx);

                //            succes = true;
                //        }
                //    }
                //}

                // select a customer using some heuristic.
                int customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                customers.Remove(customer);

                // start a route r.
                IRoute currentRoute = solution.Add(customer);
                solution[solution.Count - 1] = 0;

                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result;
                    if (_useSeedCost)
                    { // use the seed cost; the cost to the seed customer.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers,
                            customer, 0.7);

                        // calculate the 'real' increase.
                        result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                            problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                            problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                    }
                    else
                    { // just use cheapest insertion.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers, costs);
                    }

                    // calculate the new weight.
                    solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                    double potentialWeight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                        result.Increase);
                    // cram as many customers into one route as possible.
                    if (potentialWeight < max)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        currentRoute.InsertAfter(result.CustomerBefore, result.Customer);

                        // free some memory in the costs list.
                        costs.Remove(result.CustomerBefore, result.CustomerAfter);

                        // update the cost of the route.
                        solution[solution.Count - 1] = potentialWeight;

                        // improve if needed.
                        if (((problem.Size - customers.Count) % _k) == 0)
                        { // an improvement is decided.
                            // apply the inter-route improvements.
            //                            var copy = (solution.Clone() as MaxTimeSolution);

                            int countBefore = solution.Route(solution.Count - 1).Count;

                            solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                solution.Route(solution.Count - 1), solution[solution.Count - 1]);
                            if (!solution.IsValid())
                            {
                                throw new Exception();
                            }
                            int countAfter = solution.Route(solution.Count - 1).Count;
                            if (countAfter != countBefore)
                            {
                                throw new Exception();
                            }

                            // also to the inter-improvements.
                            currentRoute = this.Improve(problem, solution, max, solution.Count - 1);
                        }
                    }
                    else
                    {// ok we are done!
                        this.Improve(problem, solution, max, solution.Count - 1);

                        // break the route.
                        break;
                    }
                }
            }

            // remove empty routes.
            for (int routeIdx = solution.Count - 1; routeIdx >= 0; routeIdx--)
            {
                if (solution.Route(routeIdx).IsEmpty)
                {
                    solution.Remove(routeIdx);
                }
            }

            return solution;
        }
コード例 #11
0
        /// <summary>
        /// Applies inter-improvements by exchanging parts of the route(s).
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
                            int route1_idx, int route2_idx, double max)
        {
            int max_window = 40;

            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            int route1_customers = route1.Count;
            int route2_customers = route2.Count;

            double[] route1_cumul = problem.TimeCumul(route1);
            double[] route2_cumul = problem.TimeCumul(route2);

            // build all edge weights.
            List <Edge> route1_edges = new List <Edge>(route1.Edges());
            List <Edge> route2_edges = new List <Edge>(route2.Edges());

            double[] route1_weights = new double[route1_edges.Count];
            for (int idx = 0; idx < route1_edges.Count; idx++)
            {
                Edge edge = route1_edges[idx];
                route1_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }
            double[] route2_weights = new double[route2_edges.Count];
            for (int idx = 0; idx < route2_edges.Count; idx++)
            {
                Edge edge = route2_edges[idx];
                route2_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }

            List <EdgePair> route2_pairs = new List <EdgePair>();

            for (int i_idx = 0; i_idx < route2_edges.Count - 2; i_idx++)
            {
                Edge   i               = route2_edges[i_idx];
                double i_weight        = route2_weights[i_idx];
                double weight_before_i = route2_cumul[i_idx];

                int k_idx_max = route2_edges.Count;
                if (k_idx_max > i_idx + 2 + max_window)
                {
                    k_idx_max = i_idx + 2 + max_window;
                }
                for (int k_idx = i_idx + 2; k_idx < k_idx_max; k_idx++)
                {
                    Edge   k                    = route2_edges[k_idx];
                    double k_weight             = route2_weights[k_idx];
                    double weight_after_k       = route2_cumul[route2_cumul.Length - 1] - route2_cumul[k_idx + 1];
                    double weight_between_route = route2_cumul[k_idx] - route2_cumul[i_idx + 1];

                    route2_pairs.Add(new EdgePair()
                    {
                        First            = i,
                        FirstWeight      = i_weight,
                        Second           = k,
                        SecondWeight     = k_weight,
                        Between          = new List <int>(route2.Between(i.To, k.From)),
                        WeightTotal      = i_weight + k_weight,
                        WeightAfter      = weight_after_k,
                        WeightBefore     = weight_before_i,
                        WeightBetween    = weight_between_route,
                        CustomersBetween = k_idx - i_idx
                    });
                }
            }

            // build all edge pairs.
            for (int i_idx = 0; i_idx < route1_edges.Count - 2; i_idx++)
            {
                Edge   i               = route1_edges[i_idx];
                double i_weight        = route1_weights[i_idx];
                double weight_before_i = route1_cumul[i_idx];

                int k_idx_max = route1_edges.Count;
                if (k_idx_max > i_idx + 2 + max_window)
                {
                    k_idx_max = i_idx + 2 + max_window;
                }
                for (int k_idx = i_idx + 2; k_idx < k_idx_max; k_idx++)
                {
                    Edge   k                    = route1_edges[k_idx];
                    double k_weight             = route1_weights[k_idx];
                    double weight_after_k       = route1_cumul[route1_cumul.Length - 1] - route1_cumul[k_idx + 1];
                    double weight_between_route = route1_cumul[k_idx] - route1_cumul[i_idx + 1];

                    EdgePair pair1 = new EdgePair()
                    {
                        First            = i,
                        FirstWeight      = i_weight,
                        Second           = k,
                        SecondWeight     = k_weight,
                        Between          = new List <int>(route1.Between(i.To, k.From)),
                        WeightTotal      = i_weight + k_weight,
                        WeightAfter      = weight_after_k,
                        WeightBefore     = weight_before_i,
                        WeightBetween    = weight_between_route,
                        CustomersBetween = k_idx - i_idx
                    };

                    foreach (EdgePair pair2 in route2_pairs)
                    {
                        double existing_weight = pair1.WeightTotal + pair2.WeightTotal;

                        //double new_weight = 0;

                        // get first route new.
                        double new_weight = problem.WeightMatrix[pair1.First.From][pair2.First.To];
                        //new_weight = first_route1_new;
                        if (new_weight > existing_weight - 0.001)
                        {
                            continue;
                        }

                        double first_route2_new = problem.WeightMatrix[pair2.First.From][pair1.First.To];
                        new_weight = new_weight + first_route2_new;
                        if (new_weight > existing_weight - 0.001)
                        {
                            continue;
                        }

                        double second_route1_new = problem.WeightMatrix[pair1.Second.From][pair2.Second.To];
                        new_weight = new_weight + second_route1_new;
                        if (new_weight > existing_weight - 0.001)
                        {
                            continue;
                        }

                        double second_route2_new = problem.WeightMatrix[pair2.Second.From][pair1.Second.To];
                        new_weight = new_weight + second_route2_new;

                        if (new_weight < existing_weight - 0.001)
                        { // there is a decrease in total weight; check bounds.
                            double route1_weight = pair1.WeightBefore + pair2.WeightBetween + pair1.WeightAfter;
                            double route2_weight = pair2.WeightBefore + pair1.WeightBetween + pair2.WeightAfter;

                            // calculate the maximum.
                            int route1_customers_between = pair1.CustomersBetween;
                            int route2_customers_between = pair1.CustomersBetween;
                            route1_weight = problem.Time(route1_weight,
                                                         route1_customers - route1_customers_between + route2_customers_between);
                            route2_weight = problem.Time(route2_weight,
                                                         route2_customers - route2_customers_between + route1_customers_between);

                            if (route1_weight < max && route2_weight < max)
                            {
                                MaxTimeSolution solution_copy = solution.Clone() as MaxTimeSolution;

                                List <int> route1_between = pair1.Between;
                                List <int> route2_between = pair2.Between;

                                route1.ReplaceEdgeFrom(pair1.First.From, pair1.Second.To);
                                route2.ReplaceEdgeFrom(pair2.First.From, pair2.Second.To);

                                int previous = pair1.First.From;
                                for (int idx = 0; idx < route2_between.Count; idx++)
                                {
                                    route1.ReplaceEdgeFrom(previous, route2_between[idx]);
                                    previous = route2_between[idx];
                                }
                                route1.ReplaceEdgeFrom(previous, pair1.Second.To);

                                previous = pair2.First.From;
                                for (int idx = 0; idx < route1_between.Count; idx++)
                                {
                                    route2.ReplaceEdgeFrom(previous, route1_between[idx]);
                                    previous = route1_between[idx];
                                }
                                route2.ReplaceEdgeFrom(previous, pair2.Second.To);

                                if (!solution.IsValid())
                                {
                                    throw new Exception();
                                }
                                return(true);
                            }
                        }
                    }
                }
            }
            return(false);
        }
コード例 #12
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            var solution = new MaxTimeSolution(problem.Size);

            // keep placing customer until none are left.
            var customers = new List <int>(problem.Customers);

            customers.RemoveAt(0);

            double max = problem.Max.Value - (problem.Max.Value * _deltaPercentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs      = new BinaryHeapInsertionCosts();
            double          percentage = _thresholdPercentage;

            while (customers.Count > 0)
            {
                //// try and distribute the remaining customers if there are only a few left.
                //if (customers.Count < problem.Size * percentage)
                //{
                //    bool succes = true;
                //    while (succes && customers.Count > 0)
                //    {
                //        succes = false;
                //        CheapestInsertionResult best = new CheapestInsertionResult();
                //        best.Increase = float.MaxValue;
                //        int best_idx = -1;
                //        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                //        {
                //            IRoute route = solution.Route(route_idx);
                //            CheapestInsertionResult result =
                //                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                //            if (best.Increase > result.Increase)
                //            {
                //                best = result;
                //                best_idx = route_idx;
                //            }
                //        }

                //        IRoute best_route = solution.Route(best_idx);
                //        double route_time = problem.Time(best_route);
                //        if (route_time + best.Increase < max)
                //        { // insert the customer.
                //            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                //            customers.Remove(best.Customer);

                //            this.Improve(problem, solution, max, best_idx);

                //            succes = true;
                //        }
                //    }
                //}

                // select a customer using some heuristic.
                int customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                customers.Remove(customer);

                // start a route r.
                IRoute currentRoute = solution.Add(customer);
                solution[solution.Count - 1] = 0;

                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result;
                    if (_useSeedCost)
                    { // use the seed cost; the cost to the seed customer.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers,
                                                                                customer, 0.7);

                        // calculate the 'real' increase.
                        result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                                           problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                                          problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                    }
                    else
                    { // just use cheapest insertion.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers, costs);
                    }

                    // calculate the new weight.
                    solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                    double potentialWeight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                                                                                                 result.Increase);
                    // cram as many customers into one route as possible.
                    if (potentialWeight < max)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        currentRoute.InsertAfter(result.CustomerBefore, result.Customer);

                        // free some memory in the costs list.
                        costs.Remove(result.CustomerBefore, result.CustomerAfter);

                        // update the cost of the route.
                        solution[solution.Count - 1] = potentialWeight;

                        // improve if needed.
                        if (((problem.Size - customers.Count) % _k) == 0)
                        { // an improvement is decided.
                            // apply the inter-route improvements.
                            var copy = (solution.Clone() as MaxTimeSolution);

                            int countBefore = solution.Route(solution.Count - 1).Count;

                            solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                                                                  solution.Route(solution.Count - 1), solution[solution.Count - 1]);
                            if (!solution.IsValid())
                            {
                                throw new Exception();
                            }
                            int countAfter = solution.Route(solution.Count - 1).Count;
                            if (countAfter != countBefore)
                            {
                                throw new Exception();
                            }

                            // also to the inter-improvements.
                            currentRoute = this.Improve(problem, solution, max, solution.Count - 1);
                        }
                    }
                    else
                    {// ok we are done!
                        this.Improve(problem, solution, max, solution.Count - 1);

                        // break the route.
                        break;
                    }
                }
            }

            // remove empty routes.
            for (int routeIdx = solution.Count - 1; routeIdx >= 0; routeIdx--)
            {
                if (solution.Route(routeIdx).IsEmpty)
                {
                    solution.Remove(routeIdx);
                }
            }

            return(solution);
        }
コード例 #13
0
        /// <summary>
        /// Try and merge route2 into route1.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private MergeResult TryMerge(MaxTimeProblem problem, MaxTimeSolution solution, 
            int route1_idx, int route2_idx, double max)
        {
            // get the route weights.
            double route1_weight = solution[route1_idx];
            double route2_weight = solution[route2_idx];

            // creates a result.
            MergeResult result = new MergeResult();
            result.Weight = double.MaxValue;

            // get the two routes.
            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            // just first do the case where both routes are of zero length.
            if (route1.Count == 1 && route2.Count == 1)
            { // calculate the increase when joining the two points.
                foreach (int customer1 in route1)
                {
                    foreach (int customer2 in route2)
                    {
                        double difference = problem.WeightMatrix[customer1][customer2] +
                                problem.WeightMatrix[customer2][customer1];
                        double new_route_weight = route1_weight + difference + route2_weight;
                        if (new_route_weight < max)
                        {
                            result.Weight = difference;
                            result.RouteSourceId = route2_idx;
                            result.RouteTargetId = route1_idx;
                            result.CustomerSourceSource = customer2;
                            result.CustomerSourceTarget = customer2;
                            result.CustomerTargetSource = customer1;

                            return result;
                        }
                    }
                }
            }

            foreach (Edge route1_edge in route1.Edges())
            { // loop over all route1 edges.
                // calculate weight of the current edge.
                double route1_edge_weight = problem.WeightMatrix[route1_edge.From][route1_edge.To];
                double route1_edge_without = route1_weight - route1_edge_weight;

                if (route2.Count == 1)
                { // there is only one customer.
                    foreach (int customer2 in route2)
                    {
                        //// calculate weight of the current edge.
                        //double route2_edge_weight = problem.WeightMatrix[route2_edge.From][route2_edge.To];
                        //double route2_edge_without = route2_weight - route2_edge_weight;

                        double new_edges_weight = problem.WeightMatrix[route1_edge.From][customer2] +
                            problem.WeightMatrix[customer2][route1_edge.To];

                        double difference = problem.WeightDifferenceAfterMerge(solution,
                            new_edges_weight - (route1_edge_weight));

                        // check if the max bound is not violated.
                        double new_route_weight = route1_edge_without + difference + route2_weight; // the customer remain the same.
                        if (new_route_weight < max)
                        {
                            // the difference is smaller than the current result.
                            if (difference < result.Weight)
                            {
                                result.Weight = difference;
                                result.RouteSourceId = route2_idx;
                                result.RouteTargetId = route1_idx;
                                result.CustomerSourceSource = customer2;
                                result.CustomerSourceTarget = customer2;
                                result.CustomerTargetSource = route1_edge.From;
                            }
                        }
                    }
                }
                else
                { // there is at least one edge.
                    foreach (Edge route2_edge in route2.Edges())
                    { // loop over all route2 edges.
                        // calculate weight of the current edge.
                        double route2_edge_weight = problem.WeightMatrix[route2_edge.From][route2_edge.To];
                        double route2_edge_without = route2_weight - route2_edge_weight;

                        double new_edges_weight = problem.WeightMatrix[route1_edge.From][route2_edge.To] +
                            problem.WeightMatrix[route2_edge.From][route1_edge.To];

                        double difference = problem.WeightDifferenceAfterMerge(solution,
                            new_edges_weight - (route1_edge_weight + route2_edge_weight));

                        // check if the max bound is not violated.
                        double new_route_weight = route1_edge_weight + route2_edge_without + new_edges_weight; // the customer remain the same.
                        if (new_route_weight < max)
                        {
                            // the difference is smaller than the current result.
                            if (difference < result.Weight)
                            {
                                result.Weight = difference;
                                result.RouteSourceId = route2_idx;
                                result.RouteTargetId = route1_idx;
                                result.CustomerSourceSource = route2_edge.To;
                                result.CustomerSourceTarget = route2_edge.From;
                                result.CustomerTargetSource = route1_edge.From;
                            }
                        }
                    }
                }
            }
            return result;
        }
コード例 #14
0
        /// <summary>
        /// Tries to relocate customers using the source the same as the CrossExchange but places customers using cheapest insertion.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
                            int route1_idx, int route2_idx, double max)
        {
            int max_window = 10;

            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            double total_before = problem.Time(solution.Route(route1_idx)) +
                                  problem.Time(solution.Route(route2_idx));

            int route1_customers = route1.Count;
            int route2_customers = route2.Count;

            double[] route1_cumul = problem.TimeCumul(route1);
            double[] route2_cumul = problem.TimeCumul(route2);

            // build all edge weights.
            List <Edge> route1_edges = new List <Edge>(route1.Edges());
            List <Edge> route2_edges = new List <Edge>(route2.Edges());

            double[] route1_weights = new double[route1_edges.Count];
            for (int idx = 0; idx < route1_edges.Count; idx++)
            {
                Edge edge = route1_edges[idx];
                route1_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }
            double[] route2_weights = new double[route2_edges.Count];
            for (int idx = 0; idx < route2_edges.Count; idx++)
            {
                Edge edge = route2_edges[idx];
                route2_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }

            List <EdgePair> route2_pairs = new List <EdgePair>();

            for (int i_idx = 0; i_idx < route2_edges.Count - 2; i_idx++)
            {
                Edge   i               = route2_edges[i_idx];
                double i_weight        = route2_weights[i_idx];
                double weight_before_i = route2_cumul[i_idx];

                int k_idx_max = route2_edges.Count;
                if (k_idx_max > i_idx + 2 + max_window)
                {
                    k_idx_max = i_idx + 2 + max_window;
                }
                for (int k_idx = i_idx + 2; k_idx < k_idx_max; k_idx++)
                {
                    Edge   k                    = route2_edges[k_idx];
                    double k_weight             = route2_weights[k_idx];
                    double weight_after_k       = route2_cumul[route2_cumul.Length - 1] - route2_cumul[k_idx + 1];
                    double weight_between_route = route2_cumul[k_idx] - route2_cumul[i_idx + 1];

                    route2_pairs.Add(new EdgePair()
                    {
                        First            = i,
                        FirstWeight      = i_weight,
                        Second           = k,
                        SecondWeight     = k_weight,
                        Between          = new List <int>(route2.Between(i.To, k.From)),
                        WeightTotal      = i_weight + k_weight,
                        WeightAfter      = weight_after_k,
                        WeightBefore     = weight_before_i,
                        WeightBetween    = weight_between_route,
                        CustomersBetween = k_idx - i_idx
                    });
                }
            }

            // try to relocate all and find best pair.
            double   route1_weight = route1_cumul[route1_cumul.Length - 1];
            EdgePair best          = null;
            CheapestInsertionResult best_result = new CheapestInsertionResult();
            double best_extra = double.MaxValue;

            foreach (EdgePair pair2 in route2_pairs)
            {
                // calculate cheapest insertion.
                CheapestInsertionResult result =
                    CheapestInsertionHelper.CalculateBestPlacement(problem, route1,
                                                                   pair2.First.To, pair2.Second.From);

                double extra_route2 = problem.WeightMatrix[pair2.First.From][pair2.Second.To];

                // check if the result has a net-decrease.
                if (result.Increase + extra_route2 < pair2.WeightTotal - 0.01)
                { // there is a net decrease.
                    // calculate the real increase.
                    double new_weight = problem.Time(route1_weight + result.Increase + pair2.WeightBetween, route1_customers +
                                                     pair2.CustomersBetween);

                    // check the max.
                    if (new_weight < max && new_weight < best_extra)
                    { // the route is smaller than max.
                        best_extra  = new_weight;
                        best_result = result;
                        best        = pair2;
                    }
                }
            }

            if (best != null)
            {
                if (route2.Last == best.Second.To)
                {
                    //throw new Exception();
                }
                route2.ReplaceEdgeFrom(best.First.From, best.Second.To);

                int previous = best_result.CustomerBefore;
                foreach (int customer in best.Between)
                {
                    route1.ReplaceEdgeFrom(previous, customer);

                    previous = customer;
                }
                route1.ReplaceEdgeFrom(previous, best_result.CustomerAfter);

                // check validity.
                if (!route2.IsValid())
                {
                    throw new Exception();
                }
                if (!route1.IsValid())
                {
                    throw new Exception();
                }

                if (route1.Count + route2.Count != route1_customers + route2_customers)
                {
                    throw new Exception();
                }

                double total_after = problem.Time(solution.Route(route1_idx)) +
                                     problem.Time(solution.Route(route2_idx));
                if (total_after >= total_before)
                {
                    throw new Exception("this is not an improvement!");
                }

                return(true);
            }
            return(false);
        }
コード例 #15
0
        /// <summary>
        /// Tries a relocation of the customers in route1 to route2.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private bool RelocateFromTo(MaxTimeProblem problem, MaxTimeSolution solution,
            int route1_idx, int route2_idx, double max)
        {
            int previous = -1;
            int current = -1;

            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            double route2_weight = solution[route2_idx];

            foreach (int next in route1)
            {
                if (previous >= 0 && current >= 0)
                { // consider the next customer.

                    int count_before1 = route1.Count;
                    int count_before2 = route2.Count;

            //                    string route1_string = route1.ToString();
            //                    string route2_string = route2.ToString();

                    if (this.ConsiderCustomer(problem, route2, previous, current, next, route2_weight, max))
                    {
                        route1.ReplaceEdgeFrom(previous, next);

                        int count_after = route1.Count + route2.Count;
                        if ((count_before1 + count_before2) != count_after)
                        {
                            throw new Exception();
                        }
                        return true;
                    }
                }

                previous = current;
                current = next;
            }

            return false;
        }
コード例 #16
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            _customers = problem.Customers;

            //float[] solutions = OsmSharp.Math.VRP.Core.BestPlacement.CheapestInsertionHelper.CalculateBestValues(
            //    problem, _customers);

            generations = 0;

            _max_generations = 10000000;

            // calculate one tsp solution.
            //Tools.Math.TSP.ISolver tsp_solver = new OsmSharp.Math.TSP.EdgeAssemblyGenetic.EdgeAssemblyCrossOverSolver(_population, _stagnation,
            //         new OsmSharp.Math.TSP.Genetic.Solver.Operations.Generation._3OptGenerationOperation(),
            //          new OsmSharp.Math.TSP.Genetic.Solver.Operations.CrossOver.EdgeAssemblyCrossover(30,
            //                 OsmSharp.Math.TSP.Genetic.Solver.Operations.CrossOver.EdgeAssemblyCrossover.EdgeAssemblyCrossoverSelectionStrategyEnum.SingleRandom,
            //                 true));
            //IRoute tsp_solution = tsp_solver.Solve(new OsmSharp.Routing.VRP.NoDepot.MaxTime.TSPPlacement.TSPProblem(
            //    problem));
            // initialize the generation.
            IGenerationOperation <MaxTimeSolution, MaxTimeProblem, Fitness> generation =
                //new SolverGenerationOperation(new TSPPlacement.TSPPlacementSolver<ResolvedType>(
                //    this.Router, this.Max, this.DeliveryTime, tsp_solution));
                new OsmSharp.Routing.VRP.NoDepot.MaxTime.Genetic.Generation.RandomBestPlacement();
            //new SolverGenerationOperation(new CheapestInsertionSolverWithImprovements<ResolvedType>(
            //    this.Router, this.Max, this.DeliveryTime, 5, 0.1f, true, 0.1f, false, 1f, null, null));
            //new SolverGenerationOperation(new CheapestInsertionSolverWithImprovements<ResolvedType>(
            //    this.Router, this.Max, this.DeliveryTime, 5, 0.1f, true, 0.1f, true, 1f));

            // initialize the crossover.
            ICrossOverOperation <MaxTimeSolution, MaxTimeProblem, Fitness> cross_over =
                new OsmSharp.Routing.VRP.NoDepot.MaxTime.Genetic.CrossOver.RouteExchangeOperation();

            // initialize the mutation.
            //IMutationOperation<MaxTimeSolution, MaxTimeProblem, Fitness> mutation =
            //    new VehicleMutation();

            List <IMutationOperation <MaxTimeSolution, MaxTimeProblem, Fitness> > mutators =
                new List <IMutationOperation <MaxTimeSolution, MaxTimeProblem, Fitness> >();

            mutators.Add(new VehicleMutation());
            //mutators.Add(new ThreeOptMutation());
            //mutators.Add(new RedivideRouteMutation());
            mutators.Add(new RoutePartExchangeMutation());
            if (_probabilities == null)
            {
                _probabilities = new List <double>();
                _probabilities.Add(0.2);
                _probabilities.Add(0.6);
                _probabilities.Add(0.2);
            }

            CombinedMutation <MaxTimeSolution, MaxTimeProblem, Fitness> mutation = new CombinedMutation <MaxTimeSolution, MaxTimeProblem, Fitness>(
                StaticRandomGenerator.Get(),
                mutators,
                _probabilities);


            SolverSettings settings = new SolverSettings(_stagnation, _population, _max_generations,
                                                         _elitism_percentage, _cross_percentage, _mutation_percentage);
            MaxTimeProblem genetic_problem = problem;// new MaxTimeProblem(max,  problem, solutions);
            Solver <MaxTimeSolution, MaxTimeProblem, Fitness> solver =
                new Solver <MaxTimeSolution, MaxTimeProblem, Fitness>(genetic_problem, settings,
                                                                      new TournamentBasedSelector <MaxTimeSolution, MaxTimeProblem, Fitness>(5, 0.5),
                                                                      mutation,   //new ThreeOptMutation(),
                                                                      cross_over, // new RouteExchangeOperation(), //new RouteExchangeOperation(), //new RouteExchangeAndVehicleOperation(), // Order1CrossoverOperation()
                                                                      generation, //new RandomBestPlacement(),//new RandomGeneration(), //new RandomBestPlacement(),
                                                                      new FitnessCalculator());

            solver.NewFittest += new Solver <MaxTimeSolution, MaxTimeProblem, Fitness> .NewFittestDelegate(solver_NewFittest);

            //solver.NewGeneration += new Solver<MaxTimeSolution, Problem, Fitness>.NewGenerationDelegate(solver_NewGeneration);
            Individual <MaxTimeSolution, MaxTimeProblem, Fitness> solution = solver.Start(null);
            //this.solver_NewFittest(solution);

            MaxTimeSolution routes = solution.Genomes;

            long ticks_after = DateTime.Now.Ticks;

            StringBuilder sizes = new StringBuilder();

            foreach (int size in routes.Sizes)
            {
                sizes.Append(size);
                sizes.Append(" ");
            }

            StringBuilder weights = new StringBuilder();

            foreach (double weight in solution.Fitness.Weights)
            {
                weights.Append(weight.ToString(CultureInfo.InvariantCulture));
                weights.Append(" ");
            }

            return(routes);
        }
コード例 #17
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // get the seed customers.
            ICollection <int> seeds = _seed_selector.SelectSeeds(
                problem, _k);

            double[] weights = new double[seeds.Count];

            // start the seed routes.
            List <int>      selectable_customers = problem.Customers;
            MaxTimeSolution routes = new MaxTimeSolution(
                problem.Size, true);

            foreach (int seed in seeds)
            {
                routes.Add(seed);
                selectable_customers.Remove(seed);
            }

            if (!routes.IsValid())
            {
                throw new Exception();
            }

            // keep a list of cheapest insertions.
            IInsertionCosts costs = new BinaryHeapInsertionCosts();

            // keep looping until all customers have been placed.
            while (selectable_customers.Count > 0)
            {
                // try and place into every route.
                CheapestInsertionResult best_result = new CheapestInsertionResult();
                best_result.Increase = float.MaxValue;
                int best_route_idx = -1;

                CheapestInsertionResult best_result_above_max = new CheapestInsertionResult();
                best_result_above_max.Increase = float.MaxValue;
                int best_route_above_max_idx = -1;

                for (int route_idx = 0; route_idx < routes.Count; route_idx++)
                {
                    IRoute current_route = routes.Route(route_idx);

                    // choose the next customer.
                    CheapestInsertionResult result =
                        CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, selectable_customers, costs);
                    if (result.Customer == result.CustomerAfter)
                    {
                        throw new Exception();
                    }
                    // get the current weight
                    double weight = weights[route_idx];
                    if (result.Increase < best_result.Increase)
                    {
                        if (weight + result.Increase + calculator.DeliveryTime < problem.Max.Value)
                        { // route will still be inside bounds.
                            best_result    = result;
                            best_route_idx = route_idx;
                        }
                        else
                        { // route will become above max.
                            if (result.Increase < best_result_above_max.Increase)
                            {
                                best_result_above_max    = result;
                                best_route_above_max_idx = route_idx;
                            }
                        }
                    }
                }

                // do the placement if a placement is found without max violation.
                // else do the placement in the above max route.
                CheapestInsertionResult placement_result = new CheapestInsertionResult();
                placement_result.Increase = double.MaxValue;
                int placement_result_idx = -1;
                if (best_route_idx >= 0)
                { // best placement found.
                    placement_result     = best_result;
                    placement_result_idx = best_route_idx;
                }
                else
                { // best placement found but only above max.
                    placement_result     = best_result_above_max;
                    placement_result_idx = best_route_above_max_idx;
                }

                // do the actual placement.
                weights[placement_result_idx] = calculator.CalculateOneRouteIncrease(
                    weights[placement_result_idx], placement_result.Increase);
                selectable_customers.Remove(placement_result.Customer);
                //routes.Route(placement_result_idx).InsertAfterAndRemove(
                //    placement_result.CustomerBefore, placement_result.Customer, placement_result.CustomerAfter);
                routes.Route(placement_result_idx).InsertAfter(
                    placement_result.CustomerBefore, placement_result.Customer);

                if (!routes.IsValid())
                {
                    throw new Exception();
                }
            }

            return(routes);
        }
コード例 #18
0
        /// <summary>
        /// Calculates a solution.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the calculator.
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            double max = problem.Max.Value;

            // keep placing customer until none are left.
            List <int> customers = new List <int>(problem.Customers);

            // create n routes.
            for (int customer = 0; customer < customers.Count; customer++)
            {
                solution.Add(customer);
                solution[solution.Count - 1] = calculator.CalculateOneRouteIncrease(
                    0, 0);
            }

            // creates a result.
            MergeResult result = new MergeResult();

            result.Weight = double.MaxValue;

            // loop over all route pairs and merge the smallest merge.
            while (result != null)
            { // keep looping until there is no result anymore.
                result        = new MergeResult();
                result.Weight = double.MaxValue;

                for (int route1_idx = 1; route1_idx < solution.Count; route1_idx++)
                {         // keep looping over all routes.
                    for (int route2_idx = 0; route2_idx < solution.Count; route2_idx++)
                    {     // keep looping over all routes.
                        if (route1_idx == route2_idx)
                        { // only consider different routes.
                            break;
                        }

                        // calculate the merge result.
                        MergeResult current_result = this.TryMerge(problem, solution,
                                                                   route1_idx, route2_idx, problem.Max.Value);

                        // evaluate the current result.
                        if (current_result != null && current_result.Weight < result.Weight)
                        { // current result is best.
                            result = current_result;
                        }
                    }
                }

                // evaluate the result.
                if (result.Weight < double.MaxValue)
                { // there is a result; apply it!
                    IRoute source = solution.Route(result.RouteSourceId);
                    IRoute target = solution.Route(result.RouteTargetId);

                    //string source_string = source.ToString();
                    //string target_string = target.ToString();

                    if (target.Count > 1 && target.First == target.GetNeigbours(result.CustomerTargetSource)[0])
                    {
                        //throw new Exception();
                    }

                    // create an enumeration of all customers of source in the correct order.
                    IEnumerable <int> source_between = new List <int>(
                        source.Between(result.CustomerSourceSource, result.CustomerSourceTarget));

                    // insert after the complete source.
                    int previous = result.CustomerTargetSource;
                    int next     = target.GetNeigbours(result.CustomerTargetSource)[0];
                    foreach (int source_customer in source_between)
                    {
                        // insert.
                        target.ReplaceEdgeFrom(previous, source_customer);

                        previous = source_customer; // update previous.
                    }
                    target.ReplaceEdgeFrom(previous, next);

                    // remove the source route.
                    solution.Remove(result.RouteSourceId);
                    solution.RemoveWeight(result.RouteTargetId);

                    // calculate the weight of the new route.
                    solution[result.RouteTargetId] = solution[result.RouteTargetId] + result.Weight +
                                                     solution[result.RouteSourceId];

                    if (!solution.IsValid())
                    {
                        throw new Exception();
                    }
                }
                else
                { // set the result null.
                    result = null;
                }
            }

            return(solution);
        }
コード例 #19
0
        /// <summary>
        /// Try and merge route2 into route1.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private MergeResult TryMerge(MaxTimeProblem problem, MaxTimeSolution solution,
                                     int route1_idx, int route2_idx, double max)
        {
            // get the route weights.
            double route1_weight = solution[route1_idx];
            double route2_weight = solution[route2_idx];

            // creates a result.
            MergeResult result = new MergeResult();

            result.Weight = double.MaxValue;

            // get the two routes.
            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            // just first do the case where both routes are of zero length.
            if (route1.Count == 1 && route2.Count == 1)
            { // calculate the increase when joining the two points.
                foreach (int customer1 in route1)
                {
                    foreach (int customer2 in route2)
                    {
                        double difference = problem.WeightMatrix[customer1][customer2] +
                                            problem.WeightMatrix[customer2][customer1];
                        double new_route_weight = route1_weight + difference + route2_weight;
                        if (new_route_weight < max)
                        {
                            result.Weight               = difference;
                            result.RouteSourceId        = route2_idx;
                            result.RouteTargetId        = route1_idx;
                            result.CustomerSourceSource = customer2;
                            result.CustomerSourceTarget = customer2;
                            result.CustomerTargetSource = customer1;

                            return(result);
                        }
                    }
                }
            }

            foreach (Edge route1_edge in route1.Edges())
            { // loop over all route1 edges.
                // calculate weight of the current edge.
                double route1_edge_weight  = problem.WeightMatrix[route1_edge.From][route1_edge.To];
                double route1_edge_without = route1_weight - route1_edge_weight;

                if (route2.Count == 1)
                { // there is only one customer.
                    foreach (int customer2 in route2)
                    {
                        //// calculate weight of the current edge.
                        //double route2_edge_weight = problem.WeightMatrix[route2_edge.From][route2_edge.To];
                        //double route2_edge_without = route2_weight - route2_edge_weight;

                        double new_edges_weight = problem.WeightMatrix[route1_edge.From][customer2] +
                                                  problem.WeightMatrix[customer2][route1_edge.To];

                        double difference = problem.WeightDifferenceAfterMerge(solution,
                                                                               new_edges_weight - (route1_edge_weight));

                        // check if the max bound is not violated.
                        double new_route_weight = route1_edge_without + difference + route2_weight; // the customer remain the same.
                        if (new_route_weight < max)
                        {
                            // the difference is smaller than the current result.
                            if (difference < result.Weight)
                            {
                                result.Weight               = difference;
                                result.RouteSourceId        = route2_idx;
                                result.RouteTargetId        = route1_idx;
                                result.CustomerSourceSource = customer2;
                                result.CustomerSourceTarget = customer2;
                                result.CustomerTargetSource = route1_edge.From;
                            }
                        }
                    }
                }
                else
                {     // there is at least one edge.
                    foreach (Edge route2_edge in route2.Edges())
                    { // loop over all route2 edges.
                        // calculate weight of the current edge.
                        double route2_edge_weight  = problem.WeightMatrix[route2_edge.From][route2_edge.To];
                        double route2_edge_without = route2_weight - route2_edge_weight;

                        double new_edges_weight = problem.WeightMatrix[route1_edge.From][route2_edge.To] +
                                                  problem.WeightMatrix[route2_edge.From][route1_edge.To];

                        double difference = problem.WeightDifferenceAfterMerge(solution,
                                                                               new_edges_weight - (route1_edge_weight + route2_edge_weight));

                        // check if the max bound is not violated.
                        double new_route_weight = route1_edge_weight + route2_edge_without + new_edges_weight; // the customer remain the same.
                        if (new_route_weight < max)
                        {
                            // the difference is smaller than the current result.
                            if (difference < result.Weight)
                            {
                                result.Weight               = difference;
                                result.RouteSourceId        = route2_idx;
                                result.RouteTargetId        = route1_idx;
                                result.CustomerSourceSource = route2_edge.To;
                                result.CustomerSourceTarget = route2_edge.From;
                                result.CustomerTargetSource = route1_edge.From;
                            }
                        }
                    }
                }
            }
            return(result);
        }
コード例 #20
0
 /// <summary>
 /// Selects a new seed customer.
 /// </summary>
 /// <param name="problem"></param>
 /// <param name="calculator"></param>
 /// <param name="solution"></param>
 /// <param name="customers"></param>
 /// <returns></returns>
 private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator,
     MaxTimeSolution solution, List<int> customers)
 {
     // select the customer farthest from the depot.
     int selectedCustomer = -1;
     double maxDistance = double.MinValue;
     foreach (int customerToCheck in customers)
     {
         double distance = problem.WeightMatrix[0][customerToCheck] +
             problem.WeightMatrix[customerToCheck][0];
         if (distance > maxDistance)
         {
             maxDistance = distance;
             selectedCustomer = customerToCheck;
         }
     }
     return selectedCustomer;
 }
コード例 #21
0
ファイル: MaxTimeProblem.cs プロジェクト: UnifyKit/OsmSharp
        /// <summary>
        /// Calculates the total weight.
        /// </summary>
        /// <param name="solution"></param>
        /// <returns></returns>
        public double Weight(MaxTimeSolution solution)
        {
            double time = 0;
            double time_above_max = 0;
            for (int idx = 0; idx < solution.Count; idx++)
            {
                // calculate one route.
                double route_time = this.Time(solution.Route(idx));

                // add the total time about max.
                if (route_time > this.Max.Value)
                { // route time too big!
                    time_above_max = time_above_max + (route_time - this.Max.Value);
                }

                // add to the total time.
                time = time + route_time;
            }

            // the route count.
            double route_count = solution.Count;

            // the punished for breaking max.
            double punishment = System.Math.Pow(time_above_max, 4) * route_count;

            return route_count * time * _cost_per_second + route_count * _cost_per_vehicle + punishment;
        }
コード例 #22
0
        /// <summary>
        /// Tries to relocate customers using the source the same as the CrossExchange but places customers using cheapest insertion.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
            int route1_idx, int route2_idx, double max)
        {
            int max_window = 5;

            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            double total_before = problem.Time(solution.Route(route1_idx)) +
                problem.Time(solution.Route(route2_idx));

            int route1_customers = route1.Count;
            int route2_customers = route2.Count;

            double[] route1_cumul = problem.TimeCumul(route1);
            double[] route2_cumul = problem.TimeCumul(route2);

            // build all edge weights.
            List<Edge> route1_edges = new List<Edge>(route1.Edges());
            List<Edge> route2_edges = new List<Edge>(route2.Edges());
            double[] route1_weights = new double[route1_edges.Count];
            for (int idx = 0; idx < route1_edges.Count; idx++)
            {
                Edge edge = route1_edges[idx];
                route1_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }
            double[] route2_weights = new double[route2_edges.Count];
            for (int idx = 0; idx < route2_edges.Count; idx++)
            {
                Edge edge = route2_edges[idx];
                route2_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }

            List<EdgePair> route2_pairs = new List<EdgePair>();
            for (int i_idx = 0; i_idx < route2_edges.Count - 2; i_idx++)
            {
                Edge i = route2_edges[i_idx];
                double i_weight = route2_weights[i_idx];
                double weight_before_i = route2_cumul[i_idx];

                int k_idx_max = route2_edges.Count;
                if (k_idx_max > i_idx + 2 + max_window)
                {
                    k_idx_max = i_idx + 2 + max_window;
                }
                for (int k_idx = i_idx + 2; k_idx < k_idx_max; k_idx++)
                {
                    Edge k = route2_edges[k_idx];
                    double k_weight = route2_weights[k_idx];
                    double weight_after_k = route2_cumul[route2_cumul.Length - 1] - route2_cumul[k_idx + 1];
                    double weight_between_route = route2_cumul[k_idx] - route2_cumul[i_idx + 1];

                    route2_pairs.Add(new EdgePair()
                    {
                        First = i,
                        FirstWeight = i_weight,
                        Second = k,
                        SecondWeight = k_weight,
                        Between = new List<int>(route2.Between(i.To, k.From)),
                        WeightTotal = i_weight + k_weight,
                        WeightAfter = weight_after_k,
                        WeightBefore = weight_before_i,
                        WeightBetween = weight_between_route,
                        CustomersBetween = k_idx - i_idx
                    });
                }
            }

            // try to relocate all and find best pair.
            double route1_weight = route1_cumul[route1_cumul.Length - 1];
            EdgePair best = null;
            CheapestInsertionResult best_result = new CheapestInsertionResult();
            double best_extra = double.MaxValue;
            foreach (EdgePair pair2 in route2_pairs)
            {
                // calculate cheapest insertion.
                CheapestInsertionResult result =
                    CheapestInsertionHelper.CalculateBestPlacement(problem, route1,
                    pair2.First.To, pair2.Second.From);

                double extra_route2 = problem.WeightMatrix[pair2.First.From][pair2.Second.To];

                // check if the result has a net-decrease.
                if (result.Increase + extra_route2 < pair2.WeightTotal - 0.01)
                { // there is a net decrease.
                    // calculate the real increase.
                    double new_weight = problem.Time(route1_weight + result.Increase + pair2.WeightBetween, route1_customers +
                        pair2.CustomersBetween);

                    // check the max.
                    if (new_weight < max && new_weight < best_extra)
                    { // the route is smaller than max.
                        best_extra = new_weight;
                        best_result = result;
                        best = pair2;
                    }
                }
            }

            if (best != null)
            {
                if (route2.Last == best.Second.To)
                {
                    //throw new Exception();
                }
                route2.ReplaceEdgeFrom(best.First.From, best.Second.To);

                int previous = best_result.CustomerBefore;
                foreach (int customer in best.Between)
                {
                    route1.ReplaceEdgeFrom(previous, customer);

                    previous = customer;
                }
                route1.ReplaceEdgeFrom(previous, best_result.CustomerAfter);

                // check validity.
                if (!route2.IsValid())
                {
                    throw new Exception();
                }
                if (!route1.IsValid())
                {
                    throw new Exception();
                }

                if (route1.Count + route2.Count != route1_customers + route2_customers)
                {
                    throw new Exception();
                }

                double total_after = problem.Time(solution.Route(route1_idx)) +
                    problem.Time(solution.Route(route2_idx));
                if (total_after >= total_before)
                {
                    throw new Exception("this is not an improvement!");
                }

                return true;
            }
            return false;
        }
コード例 #23
0
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            MaxTimeCalculator calculator = new MaxTimeCalculator(
                problem);

            // generate a ATSP solution.
            IRoute tsp_solution = _tsp_solution;

            if (tsp_solution == null)
            {
                tsp_solution = _tsp_solver.Solve(new TSPProblem(problem));
            }

            // generate subtours from this solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // select a random start point.
            int start = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(problem.Size);

            // start the first tour.
            int placed   = 0;
            int previous = -1;

            // place the first customer.
            double weight       = 0;
            double total_weight = 0;
            IRoute route        = solution.Add(start);

            previous = start;

            while (placed < problem.Size)
            {
                // get the next customer from the tsp solution.
                int next = tsp_solution.GetNeigbours(previous)[0];

                // get the weight to the current start.
                double weight_to_next  = problem.WeightMatrix[previous][next];
                double weight_to_start = problem.WeightMatrix[next][start];
                total_weight = calculator.CalculateOneRouteIncrease(
                    weight, weight_to_next + weight_to_start);
                weight = calculator.CalculateOneRouteIncrease(
                    weight, weight_to_next);

                if (total_weight > problem.Max.Value)
                { // start a new route.
                    route  = solution.Add(next);
                    weight = 0;
                }
                else
                { // just insert the next customer.
                    route.InsertAfter(previous, next);
                    //route.InsertAfterAndRemove(previous, next, -1);
                }

                // set the previous.
                previous = next;
                placed++;
            }

            if (!solution.IsValid())
            {
                throw new Exception();
            }

            StringBuilder builder = new StringBuilder();

            builder.Append("[");
            total_weight = 0;
            for (int idx = 0; idx < solution.Count; idx++)
            {
                //IRoute route = routes.Route(idx);
                route  = solution.Route(idx);
                weight = calculator.CalculateOneRoute(route);
                builder.Append(" ");
                builder.Append(weight);
                builder.Append(" ");

                total_weight = total_weight + weight;
            }
            builder.Append("]");
            builder.Append(total_weight);
            builder.Append(": ");
            builder.Append(calculator.Calculate(solution));
            Console.WriteLine(builder.ToString());

            return(solution);
        }
コード例 #24
0
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            MaxTimeCalculator calculator = new MaxTimeCalculator(
                problem);

            // generate a ATSP solution.
            IRoute tsp_solution = _tsp_solution;
            if (tsp_solution == null)
            {
                tsp_solution = _tsp_solver.Solve(new TSPProblem(problem));
            }

            // generate subtours from this solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // select a random start point.
            int start = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(problem.Size);

            // start the first tour.
            int placed = 0;
            int previous = -1;

            // place the first customer.
            double weight = 0;
            double total_weight = 0;
            IRoute route = solution.Add(start);
            previous = start;

            while (placed < problem.Size)
            {
                // get the next customer from the tsp solution.
                int next = tsp_solution.GetNeigbours(previous)[0];

                // get the weight to the current start.
                double weight_to_next = problem.WeightMatrix[previous][next];
                double weight_to_start = problem.WeightMatrix[next][start];
                total_weight = calculator.CalculateOneRouteIncrease(
                    weight, weight_to_next + weight_to_start);
                weight = calculator.CalculateOneRouteIncrease(
                    weight, weight_to_next);

                if (total_weight > problem.Max.Value)
                { // start a new route.
                    route = solution.Add(next);
                    weight = 0;
                }
                else
                { // just insert the next customer.
                    route.InsertAfter(previous, next);
                    //route.InsertAfterAndRemove(previous, next, -1);
                }

                // set the previous.
                previous = next;
                placed++;
            }

            if (!solution.IsValid())
            {
                throw new Exception();
            }

            StringBuilder builder = new StringBuilder();
            builder.Append("[");
            total_weight = 0;
            for (int idx = 0; idx < solution.Count; idx++)
            {
                //IRoute route = routes.Route(idx);
                route = solution.Route(idx);
                weight = calculator.CalculateOneRoute(route);
                builder.Append(" ");
                builder.Append(weight);
                builder.Append(" ");

                total_weight = total_weight + weight;
            }
            builder.Append("]");
            builder.Append(total_weight);
            builder.Append(": ");
            builder.Append(calculator.Calculate(solution));
            OsmSharp.Logging.Log.TraceEvent("TSPPlacementSolver", TraceEventType.Information, builder.ToString());

            return solution;
        }
コード例 #25
0
ファイル: GuidedVNS.cs プロジェクト: jorik041/osmsharp
        ///// <summary>
        ///// Apply some improvements between the given routes and returns the resulting weight.
        ///// </summary>
        ///// <param name="problem"></param>
        ///// <param name="route"></param>
        ///// <returns></returns>
        //private bool ImproveInterRoute(MaxTimeProblem problem, MaxTimeSolution solution, int route1_idx, int route2_idx, double max)
        //{
        //    // get the routes.
        //    IRoute route1 = solution.Route(route1_idx);
        //    IRoute route2 = solution.Route(route2_idx);
        //    int count_before = route1.Count + route2.Count;
        //    // get the weights.
        //    double route1_weight = solution[route1_idx];
        //    double route2_weight = solution[route2_idx];
        //    // loop over all improvement operations.
        //    bool global_improvement = false;
        //    foreach (IInterImprovement improvement_operation in _inter_improvements)
        //    { // try the current improvement operations.
        //        bool improvement = true;
        //        while (improvement)
        //        { // keep looping when there is improvement.
        //            improvement = false;
        //            if (improvement_operation.Improve(problem, solution, route1_idx, route2_idx, max))
        //            { // there was an improvement.
        //                improvement = true;
        //                global_improvement = true;
        //                OsmSharp.Tools.Output.OutputStreamHost.WriteLine("Inter-improvement found {0}<->{1}: {2}",
        //                    route1_idx, route2_idx, improvement_operation.Name);
        //                // check if the route is valid.
        //                if (!route1.IsValid())
        //                {
        //                    throw new Exception();
        //                }
        //                if (!route2.IsValid())
        //                {
        //                    throw new Exception();
        //                }
        //                int count_after = route1.Count + route2.Count;
        //                if (count_before != count_after)
        //                {
        //                    throw new Exception();
        //                }
        //                // recalculate weights.
        //                solution[route1_idx] = problem.Time(solution.Route(route1_idx));
        //                solution[route2_idx] = problem.Time(solution.Route(route2_idx));
        //                //break;
        //            }
        //        }
        //    }
        //    return global_improvement;
        //}
        /// <summary>
        /// Apply some improvements between the given routes and returns the resulting weight.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private bool ImproveInterRoute(MaxTimeProblem problem, MaxTimeSolution solution, 
            int route1_idx, int route2_idx, double max)
        {
            // get the routes.
            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            int count_before = route1.Count + route2.Count;

            //// get the weights.
            //double route1_weight = solution[route1_idx];
            //double route2_weight = solution[route2_idx];

            // loop over all improvement operations.
            bool global_improvement = false;
            foreach (IInterImprovement improvement_operation in _inter_improvements)
            { // try the current improvement operations.
                bool improvement = true;
                while (improvement)
                { // keep looping when there is improvement.
                    improvement = false;
                    double total_before = problem.Time(solution.Route(route1_idx)) +
                        problem.Time(solution.Route(route2_idx));
                    if (improvement_operation.Improve(problem, solution, route1_idx, route2_idx, max))
                    { // there was an improvement.
                        improvement = true;
                        global_improvement = true;

                        // check if the route is valid.
                        if (!route1.IsValid())
                        {
                            throw new Exception();
                        }
                        if (!route2.IsValid())
                        {
                            throw new Exception();
                        }

                        int count_after = route1.Count + route2.Count;
                        if (count_before != count_after)
                        {
                            throw new Exception();
                        }

                        double total_after = problem.Time(solution.Route(route1_idx)) +
                            problem.Time(solution.Route(route2_idx));
                        if (total_after >= total_before)
                        {
                            throw new Exception("this is not an improvement!");
                        }

                        OsmSharp.Tools.Output.OutputStreamHost.WriteLine("Inter-improvement found {0}<->{1}: {2} ({3}->{4})",
                            route1_idx, route2_idx, improvement_operation.Name, total_before, total_after);

                        // recalculate weights.
                        solution[route1_idx] = problem.Time(solution.Route(route1_idx));
                        solution[route2_idx] = problem.Time(solution.Route(route2_idx));

                        //break;
                    }
                    else if (!improvement_operation.IsSymmetric &&
                        improvement_operation.Improve(problem, solution, route2_idx, route1_idx, max))
                    { // also do the improvement the other way around when not symmetric.
                        improvement = true;
                        global_improvement = true;

                        // check if the route is valid.
                        if (!route1.IsValid())
                        {
                            throw new Exception();
                        }
                        if (!route2.IsValid())
                        {
                            throw new Exception();
                        }

                        int count_after = route1.Count + route2.Count;
                        if (count_before != count_after)
                        {
                            throw new Exception();
                        }

                        double total_after = problem.Time(solution.Route(route1_idx)) +
                            problem.Time(solution.Route(route2_idx));
                        if (total_after >= total_before)
                        {
                            throw new Exception("this is not an improvement!");
                        }

                        OsmSharp.Tools.Output.OutputStreamHost.WriteLine("Inter-improvement found {0}<->{1}: {2} ({3}->{4})",
                            route2_idx, route1_idx, improvement_operation.Name, total_before, total_after);

                        // recalculate weights.
                        solution[route1_idx] = problem.Time(solution.Route(route1_idx));
                        solution[route2_idx] = problem.Time(solution.Route(route2_idx));

                        //break;
                    }
                }
            }
            return global_improvement;
        }
コード例 #26
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List<int> customers = new List<int>(problem.Customers);

            double max = problem.Max.Value - (problem.Max.Value * _delta_percentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs = new BinaryHeapInsertionCosts();
            double percentage = _threshold_percentage;
            while (customers.Count > 0)
            {
                // try and distribute the remaining customers if there are only a few left.
                if (customers.Count < problem.Size * percentage)
                {
                    bool succes = true;
                    while (succes && customers.Count > 0)
                    {
                        succes = false;
                        CheapestInsertionResult best = new CheapestInsertionResult();
                        best.Increase = float.MaxValue;
                        int best_idx = -1;
                        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        {
                            IRoute route = solution.Route(route_idx);
                            CheapestInsertionResult result =
                                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                            if (best.Increase > result.Increase)
                            {
                                best = result;
                                best_idx = route_idx;
                            }
                        }

                        IRoute best_route = solution.Route(best_idx);
                        double route_time = problem.Time(best_route);
                        if (route_time + best.Increase < max)
                        { // insert the customer.
                            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                            customers.Remove(best.Customer);

                            this.Improve(problem, solution, max, best_idx);

                            succes = true;
                        }
                    }
                }

                // select a customer using some heuristic.
                if (customers.Count > 0)
                {
                    // select a customer using some heuristic.
                    int customer = -1;
                    if (_use_seed)
                    { // use a seeding heuristic.
                        customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                    }
                    else
                    { // just select a random customer.
                        customer = customers[Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)];
                    }
                    customers.Remove(customer);

                    // start a route r.
                    IRoute current_route = solution.Add(customer);
                    solution[solution.Count - 1] = 0;

                    while (customers.Count > 0)
                    {
                        //OsmSharp.IO.Output.OutputStreamHost.WriteLine("{0}/{1} placed!",
                        //    customers.Count, problem.Size);

                        // calculate the best placement.
                        CheapestInsertionResult result;
                        if (_use_seed_cost)
                        { // use the seed cost; the cost to the seed customer.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers,
                                customer, _lambda);

                            // calculate the 'real' increase.
                            result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                                problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                                problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                        }
                        else
                        { // just use cheapest insertion.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers, costs);
                        }

                        // calculate the new weight.
                        solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                        double potential_weight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                            result.Increase);
                        // cram as many customers into one route as possible.
                        if (potential_weight < max)
                        {
                            // insert the customer, it is
                            customers.Remove(result.Customer);
                            current_route.InsertAfter(result.CustomerBefore, result.Customer);

                            // free some memory in the costs list.
                            costs.Remove(result.CustomerBefore, result.CustomerAfter);

                            // update the cost of the route.
                            solution[solution.Count - 1] = potential_weight;

                            // improve if needed.
                            if (((problem.Size - customers.Count) % _k) == 0)
                            { // an improvement is descided.
                                // apply the inter-route improvements.
                                int count_before = solution.Route(solution.Count - 1).Count;

                                solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                    current_route, solution[solution.Count - 1]);
                                if (!solution.IsValid())
                                {
                                    throw new Exception();
                                }
                                int count_after = solution.Route(solution.Count - 1).Count;

                                // also to the inter-improvements.
                                current_route = this.Improve(problem, solution, max, solution.Count - 1);
                            }
                        }
                        else
                        {// ok we are done!
                            this.Improve(problem, solution, max, solution.Count - 1);

                            // break the route.
                            break;
                        }
                    }
                    //else
                    //{// ok we are done!
                    //    solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                    //        current_route, solution[solution.Count - 1]);

                    //    if (!solution.IsValid())
                    //    {
                    //        throw new Exception();
                    //    }
                    //    int count_after = solution.Route(solution.Count - 1).Count;

                    //    this.Improve(problem, solution, max, solution.Count - 1);

                    //    // break the route.
                    //    break;
                    //}
                }
            }

            // remove empty routes.
            for (int route_idx = solution.Count - 1; route_idx >= 0; route_idx--)
            {
                if (solution.Route(route_idx).IsEmpty)
                {
                    solution.Remove(route_idx);
                }
            }

            return solution;
        }
コード例 #27
0
        /// <summary>
        /// Calculates a solution.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the calculator.
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            double max = problem.Max.Value;

            // keep placing customer until none are left.
            List<int> customers = new List<int>(problem.Customers);

            // create n routes.
            for (int customer = 0; customer < customers.Count; customer++)
            {
                solution.Add(customer);
                solution[solution.Count - 1] = calculator.CalculateOneRouteIncrease(
                    0, 0);
            }

            // creates a result.
            MergeResult result = new MergeResult();
            result.Weight = double.MaxValue;

            // loop over all route pairs and merge the smallest merge.
            while (result != null)
            { // keep looping until there is no result anymore.
                result = new MergeResult();
                result.Weight = double.MaxValue;

                for (int route1_idx = 1; route1_idx < solution.Count; route1_idx++)
                { // keep looping over all routes.
                    for (int route2_idx = 0; route2_idx < solution.Count; route2_idx++)
                    { // keep looping over all routes.
                        if (route1_idx == route2_idx)
                        { // only consider different routes.
                            break;
                        }

                        // calculate the merge result.
                        MergeResult current_result = this.TryMerge(problem, solution,
                            route1_idx, route2_idx, problem.Max.Value);

                        // evaluate the current result.
                        if (current_result != null && current_result.Weight < result.Weight)
                        { // current result is best.
                            result = current_result;
                        }
                    }
                }

                // evaluate the result.
                if (result.Weight < double.MaxValue)
                { // there is a result; apply it!
                    IRoute source = solution.Route(result.RouteSourceId);
                    IRoute target = solution.Route(result.RouteTargetId);

                    //string source_string = source.ToString();
                    //string target_string = target.ToString();

                    if (target.Count > 1 && target.First == target.GetNeigbours(result.CustomerTargetSource)[0])
                    {
                        //throw new Exception();
                    }

                    // create an enumeration of all customers of source in the correct order.
                    IEnumerable<int> source_between = new List<int>(
                        source.Between(result.CustomerSourceSource, result.CustomerSourceTarget));

                    // insert after the complete source.
                    int previous = result.CustomerTargetSource;
                    int next = target.GetNeigbours(result.CustomerTargetSource)[0];
                    foreach (int source_customer in source_between)
                    {
                        // insert.
                        target.ReplaceEdgeFrom(previous, source_customer);

                        previous = source_customer; // update previous.
                    }
                    target.ReplaceEdgeFrom(previous, next);

                    // remove the source route.
                    solution.Remove(result.RouteSourceId);
                    solution.RemoveWeight(result.RouteTargetId);

                    // calculate the weight of the new route.
                    solution[result.RouteTargetId] = solution[result.RouteTargetId] + result.Weight +
                        solution[result.RouteSourceId];

                    if (!solution.IsValid())
                    {
                        throw new Exception();
                    }
                }
                else
                { // set the result null.
                    result = null;
                }
            }

            return solution;
        }
コード例 #28
0
        private IRoute Improve(MaxTimeProblem problem,
            MaxTimeSolution solution, double max, int current_route_idx)
        {
            // the current route.
            IRoute current_route = solution.Route(current_route_idx);

            for (int route_idx = 0; route_idx < solution.Count; route_idx++)
            { // apply the intra-route heurstic between the new and all existing routes.
                if (route_idx != current_route_idx &&
                    this.Overlaps(problem, solution.Route(route_idx), solution.Route(current_route_idx)))
                { // only check routes that overlap.
                    if (this.ImproveInterRoute(problem, solution, route_idx, current_route_idx, max))
                    { // an improvement was found, again to the intra operators.
                        if (!solution.IsValid())
                        {
                            throw new Exception();
                        }

                        solution[current_route_idx] = this.ImproveIntraRoute(problem, current_route, solution[current_route_idx]);
                        solution[route_idx] = this.ImproveIntraRoute(problem, solution.Route(route_idx), solution[route_idx]);

                        // recalculate weights.
                        solution[current_route_idx] = problem.Time(solution.Route(current_route_idx));
                        solution[route_idx] = problem.Time(solution.Route(route_idx));
                    }
                }
            }

            return solution.Route(solution.Count - 1);
        }
コード例 #29
0
ファイル: MaxTimeProblem.cs プロジェクト: UnifyKit/OsmSharp
        /// <summary>
        /// Calculates the weight difference after merging two routes given the cost to merge them.
        /// </summary>
        /// <param name="solution"></param>
        /// <param name="merge_costs"></param>
        /// <returns></returns>
        public double WeightDifferenceAfterMerge(MaxTimeSolution solution, double merge_costs)
        {
            if (solution.Count < 2)
            { // the solution routes cannot be merged.
                return double.MaxValue;
            }
            // the route count.
            double route_count = solution.Count - 1;

            return route_count * merge_costs * _cost_per_second + route_count * _cost_per_vehicle;
        }
コード例 #30
0
        /// <summary>
        /// Selects a new seed customer.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="calculator"></param>
        /// <param name="solution"></param>
        /// <param name="customers"></param>
        /// <returns></returns>
        private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator, 
            MaxTimeSolution solution, List<int> customers)
        {
            int selected_customer = -1;
            double max_distance = double.MaxValue;
            foreach (int customer_to_check in customers)
            {
                SortedDictionary<double, List<int>> neighbours = new SortedDictionary<double, List<int>>();
                for (int idx = 0; idx < customers.Count; idx++)
                {
                    int customer = customers[idx];
                    if (customer != customer_to_check)
                    {
                        double weight = problem.WeightMatrix[customer_to_check][customer] +
                            problem.WeightMatrix[customer_to_check][customer];
                        List<int> customers_list = null;
                        if (!neighbours.TryGetValue(weight, out customers_list))
                        {
                            customers_list = new List<int>();
                            neighbours.Add(weight, customers_list);
                        }
                        customers_list.Add(customer);
                    }
                }

                double nearest_neighbour_average = 0;
                int neighbour_count = 20;
                int neighbour_counted = 0;
                foreach (KeyValuePair<double, List<int>> pair in neighbours)
                {
                    foreach (int customer in pair.Value)
                    {
                        if (neighbour_counted < neighbour_count)
                        {
                            neighbour_counted++;
                            nearest_neighbour_average = nearest_neighbour_average +
                                pair.Key;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                if (max_distance > nearest_neighbour_average)
                {
                    max_distance = nearest_neighbour_average;
                    selected_customer = customer_to_check;
                }
            }
            return selected_customer;
        }
コード例 #31
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List <int> customers = new List <int>(problem.Customers);

            double max = problem.Max.Value - (problem.Max.Value * _delta_percentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs      = new BinaryHeapInsertionCosts();
            double          percentage = _threshold_percentage;

            while (customers.Count > 0)
            {
                // try and distribute the remaining customers if there are only a few left.
                if (customers.Count < problem.Size * percentage)
                {
                    bool succes = true;
                    while (succes && customers.Count > 0)
                    {
                        succes = false;
                        CheapestInsertionResult best = new CheapestInsertionResult();
                        best.Increase = float.MaxValue;
                        int best_idx = -1;
                        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        {
                            IRoute route = solution.Route(route_idx);
                            CheapestInsertionResult result =
                                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                            if (best.Increase > result.Increase)
                            {
                                best     = result;
                                best_idx = route_idx;
                            }
                        }

                        IRoute best_route = solution.Route(best_idx);
                        double route_time = problem.Time(best_route);
                        if (route_time + best.Increase < max)
                        { // insert the customer.
                            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                            customers.Remove(best.Customer);

                            this.Improve(problem, solution, max, best_idx);

                            succes = true;
                        }
                    }
                }

                // select a customer using some heuristic.
                if (customers.Count > 0)
                {
                    // select a customer using some heuristic.
                    int customer = -1;
                    if (_use_seed)
                    { // use a seeding heuristic.
                        customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                    }
                    else
                    { // just select a random customer.
                        customer = customers[Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)];
                    }
                    customers.Remove(customer);

                    // start a route r.
                    IRoute current_route = solution.Add(customer);
                    solution[solution.Count - 1] = 0;

                    while (customers.Count > 0)
                    {
                        //OsmSharp.IO.Output.OutputStreamHost.WriteLine("{0}/{1} placed!",
                        //    customers.Count, problem.Size);

                        // calculate the best placement.
                        CheapestInsertionResult result;
                        if (_use_seed_cost)
                        { // use the seed cost; the cost to the seed customer.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers,
                                                                                    customer, _lambda);

                            // calculate the 'real' increase.
                            result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                                               problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                                              problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                        }
                        else
                        { // just use cheapest insertion.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers, costs);
                        }

                        // calculate the new weight.
                        solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                        double potential_weight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                                                                                                      result.Increase);
                        // cram as many customers into one route as possible.
                        if (potential_weight < max)
                        {
                            // insert the customer, it is
                            customers.Remove(result.Customer);
                            current_route.InsertAfter(result.CustomerBefore, result.Customer);

                            // free some memory in the costs list.
                            costs.Remove(result.CustomerBefore, result.CustomerAfter);

                            // update the cost of the route.
                            solution[solution.Count - 1] = potential_weight;

                            // improve if needed.
                            if (((problem.Size - customers.Count) % _k) == 0)
                            { // an improvement is descided.
                                // apply the inter-route improvements.
                                int count_before = solution.Route(solution.Count - 1).Count;

                                solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                                                                      current_route, solution[solution.Count - 1]);
                                if (!solution.IsValid())
                                {
                                    throw new Exception();
                                }
                                int count_after = solution.Route(solution.Count - 1).Count;

                                // also to the inter-improvements.
                                current_route = this.Improve(problem, solution, max, solution.Count - 1);
                            }
                        }
                        else
                        {// ok we are done!
                            this.Improve(problem, solution, max, solution.Count - 1);

                            // break the route.
                            break;
                        }
                    }
                    //else
                    //{// ok we are done!
                    //    solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                    //        current_route, solution[solution.Count - 1]);

                    //    if (!solution.IsValid())
                    //    {
                    //        throw new Exception();
                    //    }
                    //    int count_after = solution.Route(solution.Count - 1).Count;

                    //    this.Improve(problem, solution, max, solution.Count - 1);

                    //    // break the route.
                    //    break;
                    //}
                }
            }

            // remove empty routes.
            for (int route_idx = solution.Count - 1; route_idx >= 0; route_idx--)
            {
                if (solution.Route(route_idx).IsEmpty)
                {
                    solution.Remove(route_idx);
                }
            }

            return(solution);
        }
コード例 #32
0
        /// <summary>
        /// Applies inter-improvements by exchanging parts of the route(s).
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution, 
            int route1_idx, int route2_idx, double max)
        {
            int max_window = 50;

            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            int route1_customers = route1.Count;
            int route2_customers = route2.Count;

            double[] route1_cumul = problem.TimeCumul(route1);
            double[] route2_cumul = problem.TimeCumul(route2);

            // build all edge weights.
            List<Edge> route1_edges = new List<Edge>(route1.Edges());
            List<Edge> route2_edges = new List<Edge>(route2.Edges());
            double[] route1_weights = new double[route1_edges.Count];
            for (int idx = 0; idx < route1_edges.Count; idx++)
            {
                Edge edge = route1_edges[idx];
                route1_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }
            double[] route2_weights = new double[route2_edges.Count];
            for (int idx = 0; idx < route2_edges.Count; idx++)
            {
                Edge edge = route2_edges[idx];
                route2_weights[idx] = problem.WeightMatrix[edge.From][edge.To];
            }

            List<EdgePair> route2_pairs = new List<EdgePair>();
            for (int i_idx = 0; i_idx < route2_edges.Count - 2; i_idx++)
            {
                Edge i = route2_edges[i_idx];
                double i_weight = route2_weights[i_idx];
                double weight_before_i = route2_cumul[i_idx];

                int k_idx_max = route2_edges.Count;
                if (k_idx_max > i_idx + 2 + max_window)
                {
                    k_idx_max = i_idx + 2 + max_window;
                }
                for (int k_idx = i_idx + 2; k_idx < k_idx_max; k_idx++)
                {
                    Edge k = route2_edges[k_idx];
                    double k_weight = route2_weights[k_idx];
                    double weight_after_k = route2_cumul[route2_cumul.Length - 1] - route2_cumul[k_idx + 1];
                    double weight_between_route = route2_cumul[k_idx] - route2_cumul[i_idx + 1];

                    route2_pairs.Add(new EdgePair()
                    {
                        First = i,
                        FirstWeight = i_weight,
                        Second = k,
                        SecondWeight = k_weight,
                        Between = new List<int>(route2.Between(i.To, k.From)),
                        WeightTotal = i_weight + k_weight,
                        WeightAfter = weight_after_k,
                        WeightBefore = weight_before_i,
                        WeightBetween = weight_between_route,
                        CustomersBetween = k_idx - i_idx
                    });
                }
            }

            // build all edge pairs.
            for (int i_idx = 0; i_idx < route1_edges.Count - 2; i_idx++)
            {
                Edge i = route1_edges[i_idx];
                double i_weight = route1_weights[i_idx];
                double weight_before_i = route1_cumul[i_idx];

                int k_idx_max = route1_edges.Count;
                if (k_idx_max > i_idx + 2 + max_window)
                {
                    k_idx_max = i_idx + 2 + max_window;
                }
                for (int k_idx = i_idx + 2; k_idx < k_idx_max; k_idx++)
                {
                    Edge k = route1_edges[k_idx];
                    double k_weight = route1_weights[k_idx];
                    double weight_after_k = route1_cumul[route1_cumul.Length - 1] - route1_cumul[k_idx + 1];
                    double weight_between_route = route1_cumul[k_idx] - route1_cumul[i_idx + 1];

                    EdgePair pair1 = new EdgePair()
                    {
                        First = i,
                        FirstWeight = i_weight,
                        Second = k,
                        SecondWeight = k_weight,
                        Between = new List<int>(route1.Between(i.To, k.From)),
                        WeightTotal = i_weight + k_weight,
                        WeightAfter = weight_after_k,
                        WeightBefore = weight_before_i,
                        WeightBetween = weight_between_route,
                        CustomersBetween = k_idx - i_idx
                    };

                    foreach (EdgePair pair2 in route2_pairs)
                    {
                        double existing_weight = pair1.WeightTotal + pair2.WeightTotal;

                        //double new_weight = 0;

                        // get first route new.
                        double new_weight = problem.WeightMatrix[pair1.First.From][pair2.First.To];
                        //new_weight = first_route1_new;
                        if (new_weight > existing_weight - 0.001)
                        {
                            continue;
                        }

                        double first_route2_new = problem.WeightMatrix[pair2.First.From][pair1.First.To];
                        new_weight = new_weight + first_route2_new;
                        if (new_weight > existing_weight - 0.001)
                        {
                            continue;
                        }

                        double second_route1_new = problem.WeightMatrix[pair1.Second.From][pair2.Second.To];
                        new_weight = new_weight + second_route1_new;
                        if (new_weight > existing_weight - 0.001)
                        {
                            continue;
                        }

                        double second_route2_new = problem.WeightMatrix[pair2.Second.From][pair1.Second.To];
                        new_weight = new_weight + second_route2_new;

                        if (new_weight < existing_weight - 0.001)
                        { // there is a decrease in total weight; check bounds.
                            double route1_weight = pair1.WeightBefore + pair2.WeightBetween + pair1.WeightAfter;
                            double route2_weight = pair2.WeightBefore + pair1.WeightBetween + pair2.WeightAfter;

                            // calculate the maximum.
                            int route1_customers_between = pair1.CustomersBetween;
                            int route2_customers_between = pair1.CustomersBetween;
                            route1_weight = problem.Time(route1_weight,
                                route1_customers - route1_customers_between + route2_customers_between);
                            route2_weight = problem.Time(route2_weight,
                                route2_customers - route2_customers_between + route1_customers_between);

                            if (route1_weight < max && route2_weight < max)
                            {
            //                                MaxTimeSolution solution_copy = solution.Clone() as MaxTimeSolution;

                                List<int> route1_between = pair1.Between;
                                List<int> route2_between = pair2.Between;

                                route1.ReplaceEdgeFrom(pair1.First.From, pair1.Second.To);
                                route2.ReplaceEdgeFrom(pair2.First.From, pair2.Second.To);

                                int previous = pair1.First.From;
                                for (int idx = 0; idx < route2_between.Count; idx++)
                                {
                                    route1.ReplaceEdgeFrom(previous, route2_between[idx]);
                                    previous = route2_between[idx];
                                }
                                route1.ReplaceEdgeFrom(previous, pair1.Second.To);

                                previous = pair2.First.From;
                                for (int idx = 0; idx < route1_between.Count; idx++)
                                {
                                    route2.ReplaceEdgeFrom(previous, route1_between[idx]);
                                    previous = route1_between[idx];
                                }
                                route2.ReplaceEdgeFrom(previous, pair2.Second.To);

                                if (!solution.IsValid())
                                {
                                    throw new Exception();
                                }
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }
コード例 #33
0
ファイル: GuidedVNS.cs プロジェクト: OpenMaps/OsmSharp
        /// <summary>
        /// Apply some improvements between the given routes and returns the resulting weight.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1Idx"></param>
        /// <param name="route2Idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private bool ImproveInterRoute(MaxTimeProblem problem, MaxTimeSolution solution, 
            int route1Idx, int route2Idx, double max)
        {
            // get the routes.
            IRoute route1 = solution.Route(route1Idx);
            IRoute route2 = solution.Route(route2Idx);

            int countBefore = route1.Count + route2.Count;

            // loop over all improvement operations.
            bool globalImprovement = false;
            foreach (IInterImprovement improvementOperation in _inter_improvements)
            { // try the current improvement operations.
                bool improvement = true;
                while (improvement)
                { // keep looping when there is improvement.
                    improvement = false;
                    double totalBefore = problem.Time(solution.Route(route1Idx)) +
                        problem.Time(solution.Route(route2Idx));
                    if (improvementOperation.Improve(problem, solution, route1Idx, route2Idx, max))
                    { // there was an improvement.
                        improvement = true;
                        globalImprovement = true;

                        // check if the route is valid.
                        if (!route1.IsValid())
                        {
                            throw new Exception();
                        }
                        if (!route2.IsValid())
                        {
                            throw new Exception();
                        }

                        int countAfter = route1.Count + route2.Count;
                        if (countBefore != countAfter)
                        {
                            throw new Exception();
                        }

                        double totalAfter = problem.Time(solution.Route(route1Idx)) +
                            problem.Time(solution.Route(route2Idx));
                        if (totalAfter >= totalBefore)
                        {
                            throw new Exception("this is not an improvement!");
                        }

                        OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information,
                            "Inter-improvement found {0}<->{1}: {2} ({3}->{4})",
                            route1Idx, route2Idx, improvementOperation.Name, totalBefore, totalAfter);

                        // recalculate weights.
                        solution[route1Idx] = problem.Time(solution.Route(route1Idx));
                        solution[route2Idx] = problem.Time(solution.Route(route2Idx));

                        //break;
                    }
                    else if (!improvementOperation.IsSymmetric &&
                        improvementOperation.Improve(problem, solution, route2Idx, route1Idx, max))
                    { // also do the improvement the other way around when not symmetric.
                        improvement = true;
                        globalImprovement = true;

                        // check if the route is valid.
                        if (!route1.IsValid())
                        {
                            throw new Exception();
                        }
                        if (!route2.IsValid())
                        {
                            throw new Exception();
                        }

                        int countAfter = route1.Count + route2.Count;
                        if (countBefore != countAfter)
                        {
                            throw new Exception();
                        }

                        double totalAfter = problem.Time(solution.Route(route1Idx)) +
                            problem.Time(solution.Route(route2Idx));
                        if (totalAfter >= totalBefore)
                        {
                            throw new Exception("this is not an improvement!");
                        }

                        OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information,
                            "Inter-improvement found {0}<->{1}: {2} ({3}->{4})",
                            route2Idx, route1Idx, improvementOperation.Name, totalBefore, totalAfter);

                        // recalculate weights.
                        solution[route1Idx] = problem.Time(solution.Route(route1Idx));
                        solution[route2Idx] = problem.Time(solution.Route(route2Idx));

                        //break;
                    }
                }
            }
            return globalImprovement;
        }
コード例 #34
0
ファイル: GuidedVNS.cs プロジェクト: yousoftvn/OsmSharp
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            float lambda = _lambda;

            var vrpRouter =
                new CheapestInsertionSolverWithImprovements(problem.Max.Value, problem.DeliveryTime.Value, 10, 0.10f, true, _thresholdPercentage, true, 0.75f);
            MaxTimeSolution originalSolution = vrpRouter.Solve(
                problem);

            for (int roundX = 0; roundX < originalSolution.Count; roundX++)
            {             // keep looping on rounds.
                for (int roundY = 0; roundY < roundX; roundY++)
                {         // keep looping on rounds with a smaller index not equal to the current round.
                    if (roundX != roundY)
                    {     // routes are different.
                        if (this.Overlaps(problem, originalSolution.Route(roundX), originalSolution.Route(roundY)))
                        { // only check routes that overlap.
                            double tau           = double.MinValue;
                            var    penalizations = new Dictionary <Edge, int>();

                            //bool improvement = true;
                            //while (improvement)
                            //{ // keep looping until no more improvement is found.
                            //    improvement = false;

                            while (true)
                            { // keep trying to improve until the tau limit is exceeded.
                                // calculate the route sizes before.
                                double route1ActualBefore = problem.Time(originalSolution.Route(roundX));
                                double route2ActualBefore = problem.Time(originalSolution.Route(roundY));

                                // copy orignal solution.
                                var solution = (originalSolution.Clone() as MaxTimeSolution);

                                // apply penalties.
                                foreach (KeyValuePair <Edge, int> penalty in penalizations)
                                {
                                    problem.Penalize(penalty.Key, (double)penalty.Value * lambda);
                                }

                                // apply the inter-route improvements.
                                int countBefore = solution.Route(roundX).Count + solution.Route(roundY).Count;
                                int countAfter;
                                if (this.ImproveInterRoute(problem, solution, roundX, roundY, problem.Max.Value))
                                { // the improve inter route succeeded.
                                    if (!solution.IsValid())
                                    {
                                        throw new Exception();
                                    }
                                    //improvement_inter = true;

                                    countAfter = solution.Route(roundX).Count + solution.Route(roundY).Count;
                                    if (countBefore != countAfter)
                                    {
                                        throw new Exception();
                                    }

                                    // apply the intra-route improvements.
                                    solution[roundX] = this.ImproveIntraRoute(problem, solution.Route(roundX), solution[roundX]);
                                    solution[roundY] = this.ImproveIntraRoute(problem, solution.Route(roundY), solution[roundY]);

                                    // recalculate weights.
                                    solution[roundX] = problem.Time(solution.Route(roundX));
                                    solution[roundY] = problem.Time(solution.Route(roundY));
                                }

                                // check customer counts.
                                countAfter = solution.Route(roundX).Count + solution.Route(roundY).Count;
                                if (countBefore != countAfter)
                                {
                                    throw new Exception();
                                }

                                // undo the penalizations.
                                problem.ResetPenalizations();

                                // check against the orginal objective function.
                                double route1ActualAfter = problem.Time(solution.Route(roundX));
                                double route2ActualAfter = problem.Time(solution.Route(roundY));
                                if (route1ActualAfter + route2ActualAfter < route1ActualBefore + route2ActualBefore - 0.001 &&
                                    route1ActualAfter < problem.Max.Value && route2ActualAfter < problem.Max.Value)
                                { // there is improvement!
                                    originalSolution = solution;

                                    //improvement = true;

                                    OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information,
                                                                    "IMPROVEMENT: {0}->{1}",
                                                                    route1ActualBefore + route2ActualBefore, route1ActualAfter + route2ActualAfter);
                                }

                                // select arc to be penalized.
                                IRoute route1         = originalSolution.Route(roundX);
                                IRoute route2         = originalSolution.Route(roundY);
                                double u              = double.MinValue;
                                var    penalizingEdge = new Edge();
                                double totalP         = 0;
                                foreach (Edge edge in route1.Edges())
                                {
                                    int edgeP;
                                    if (!penalizations.TryGetValue(edge, out edgeP))
                                    {
                                        edgeP = 0;
                                    }
                                    totalP = totalP + edgeP;
                                    double edgeU = ((lambda * (double)edgeP) + problem.WeightMatrix[edge.From][edge.To]) /
                                                   ((double)edgeP + 1.0);
                                    if (u <= edgeU)
                                    {
                                        penalizingEdge = edge;
                                        u = edgeU;
                                    }
                                }
                                foreach (Edge edge in route2.Edges())
                                {
                                    int edgeP;
                                    if (!penalizations.TryGetValue(edge, out edgeP))
                                    {
                                        edgeP = 0;
                                    }
                                    totalP = totalP + edgeP;
                                    double edgeU = ((lambda * (double)edgeP) + problem.WeightMatrix[edge.From][edge.To]) /
                                                   ((double)edgeP + 1.0);
                                    if (u <= edgeU)
                                    {
                                        penalizingEdge = edge;
                                        u = edgeU;
                                    }
                                }

                                // actually penalize the edge.
                                int p;
                                if (!penalizations.TryGetValue(penalizingEdge, out p))
                                {
                                    p = 1;
                                }
                                else
                                {
                                    p++;
                                }
                                penalizations[penalizingEdge] = p;

                                // evaluate or set tau.
                                if (tau > double.MinValue)
                                {     // evaluate if penalizations should end.
                                    if (tau <= lambda * totalP)
                                    { // the penalization should end!
                                        break;
                                    }
                                }
                                else
                                { // first edge being penalized.
                                    tau = lambda * problem.WeightMatrix[penalizingEdge.From][penalizingEdge.To] / 10;
                                }
                            }
                        }
                    }
                }
            }
            return(originalSolution);
        }
コード例 #35
0
        /// <summary>
        /// Applies inter-improvements by exchanging customers.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
                            int route1_idx, int route2_idx, double max)
        {
            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            double total_before = problem.Time(solution.Route(route1_idx)) +
                                  problem.Time(solution.Route(route2_idx));

            double route1_size = solution[route1_idx];
            double route2_size = solution[route2_idx];

            // this heuristic removes a customer1 from route1 and a customer2 from route2 and inserts the customers again
            // but swappes them; customer1 in route2 and customer2 in route1.
            int previous_customer1 = -1;

            //if (route1.IsRound)
            //{
            //    previous_customer1= route1.Last; // set the previous customer.
            //}
            foreach (int customer1 in route1)
            {     // loop over all customers in route1.
                if (previous_customer1 >= 0)
                { // the previous customer is set.
                    int next_customer1 = route1.GetNeigbours(customer1)[0];
                    if (next_customer1 < 0)
                    {
                        continue;
                    }

                    int previous_customer2 = -1;
                    //if (route2.IsRound)
                    //{
                    //    previous_customer2 = route2.Last; // set the previous customer.
                    //}

                    foreach (int customer2 in route2)
                    { // loop over all customers in route2.
                        int next_customer2 = route2.GetNeigbours(customer2)[0];
                        if (previous_customer2 >= 0 && next_customer2 >= 0)
                        { // the previous customer is set.
                            float weight1 = (float)problem.WeightMatrix[previous_customer1][customer1] +
                                            (float)problem.WeightMatrix[customer1][next_customer1];
                            float weight2 = (float)problem.WeightMatrix[previous_customer2][customer2] +
                                            (float)problem.WeightMatrix[customer2][next_customer2];

                            float weight1_after = (float)problem.WeightMatrix[previous_customer1][customer2] +
                                                  (float)problem.WeightMatrix[customer2][next_customer1];
                            float weight2_after = (float)problem.WeightMatrix[previous_customer2][customer1] +
                                                  (float)problem.WeightMatrix[customer1][next_customer2];
                            double difference = (weight1_after + weight2_after) - (weight1 + weight2);

                            if (difference < -0.01)
                            { // the old weights are bigger!
                                // check if the new routes are bigger than max.
                                if (route1_size + (weight1_after - weight1) <= max &&
                                    route2_size + (weight2_after - weight1) <= max)
                                { // the exchange can happen, both routes stay within bound!
                                    // exchange customer.
                                    int count_before = route1.Count + route2.Count;

                                    //route1.Remove(customer1);
                                    //route2.Remove(customer2);
                                    if (previous_customer1 == next_customer2)
                                    {
                                        throw new Exception();
                                    }

                                    //route1.InsertAfter(previous_customer1, customer2);
                                    //route2.InsertAfter(previous_customer2, customer1);
                                    route1.ReplaceEdgeFrom(previous_customer1, customer2);
                                    route1.ReplaceEdgeFrom(customer2, next_customer1);
                                    route2.ReplaceEdgeFrom(previous_customer2, customer1);
                                    route2.ReplaceEdgeFrom(customer1, next_customer2);

                                    int count_after = route1.Count + route2.Count;
                                    if (count_before != count_after)
                                    {
                                        throw new Exception();
                                    }

                                    double total_after = problem.Time(solution.Route(route1_idx)) +
                                                         problem.Time(solution.Route(route2_idx));
                                    if (total_after >= total_before)
                                    {
                                        throw new Exception("this is not an improvement!");
                                    }

                                    return(true);
                                }
                            }
                        }

                        previous_customer2 = customer2; // set the previous customer.
                    }
                }
                previous_customer1 = customer1; // set the previous customer.
            }
            return(false);
        }
コード例 #36
0
ファイル: DepotRouteTests.cs プロジェクト: whztt1989/OsmSharp
        public void TestDepotDynamicAsymmetricMultiRouteExchanges()
        {
            // create two routes.
            // 0->11->12->13->14->15->0
            // 0->21->22->23->24->25->0
            var    multiRoute = new MaxTimeSolution(0);
            IRoute route1     = multiRoute.Add();
            var    customers  = new List <int>(route1);

            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route1.InsertAfter(0, 11);
            Assert.AreEqual("0->11", route1.ToString());
            route1.InsertAfter(11, 12);
            route1.InsertAfter(12, 13);
            route1.InsertAfter(13, 14);
            route1.InsertAfter(14, 15);
            IRoute route2 = multiRoute.Add();

            customers = new List <int>(route2);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route2.InsertAfter(0, 21);
            Assert.AreEqual("0->21", route2.ToString());
            route2.InsertAfter(21, 22);
            route2.InsertAfter(22, 23);
            route2.InsertAfter(23, 24);
            route2.InsertAfter(24, 25);

            customers = new List <int>(route1);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(11, customers[1]);
            Assert.AreEqual(12, customers[2]);
            Assert.AreEqual(13, customers[3]);
            Assert.AreEqual(14, customers[4]);
            Assert.AreEqual(15, customers[5]);


            customers = new List <int>(route2);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(21, customers[1]);
            Assert.AreEqual(22, customers[2]);
            Assert.AreEqual(23, customers[3]);
            Assert.AreEqual(24, customers[4]);
            Assert.AreEqual(25, customers[5]);

            // replace the entire first route.
            route1.ReplaceEdgeFrom(0, 0);

            route2.ReplaceEdgeFrom(25, 11);
            route2.ReplaceEdgeFrom(11, 12);
            route2.ReplaceEdgeFrom(12, 13);
            route2.ReplaceEdgeFrom(13, 14);
            route2.ReplaceEdgeFrom(14, 15);

            Assert.IsTrue(multiRoute.IsValid());

            // create two routes.
            // 0->11->12->13->14->15->0
            // 0->21->22->23->24->25->0
            multiRoute = new MaxTimeSolution(0);
            route1     = multiRoute.Add();
            customers  = new List <int>(route1);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route1.InsertAfter(0, 11);
            Assert.AreEqual("0->11", route1.ToString());
            route1.InsertAfter(11, 12);
            route1.InsertAfter(12, 13);
            route1.InsertAfter(13, 14);
            route1.InsertAfter(14, 15);
            route2    = multiRoute.Add();
            customers = new List <int>(route2);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route2.InsertAfter(0, 21);
            Assert.AreEqual("0->21", route2.ToString());
            route2.InsertAfter(21, 22);
            route2.InsertAfter(22, 23);
            route2.InsertAfter(23, 24);
            route2.InsertAfter(24, 25);

            // exchange parts.
            var part1 = new List <int>(route1.Between(11, 13));
            var part2 = new List <int>(route2.Between(23, 25));

            route1.ReplaceEdgeFrom(0, 14);
            route2.ReplaceEdgeFrom(22, 0);

            int previous = 0;

            for (int idx = 0; idx < part2.Count; idx++)
            {
                route1.ReplaceEdgeFrom(previous, part2[idx]);
                previous = part2[idx];
            }
            route1.ReplaceEdgeFrom(previous, 14);

            previous = 22;
            for (int idx = 0; idx < part1.Count; idx++)
            {
                route2.ReplaceEdgeFrom(previous, part1[idx]);
                previous = part1[idx];
            }
            route2.ReplaceEdgeFrom(previous, 0);

            Assert.IsTrue(multiRoute.IsValid());

            customers = new List <int>(route1);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(23, customers[1]);
            Assert.AreEqual(24, customers[2]);
            Assert.AreEqual(25, customers[3]);
            Assert.AreEqual(14, customers[4]);
            Assert.AreEqual(15, customers[5]);

            customers = new List <int>(route2);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(21, customers[1]);
            Assert.AreEqual(22, customers[2]);
            Assert.AreEqual(11, customers[3]);
            Assert.AreEqual(12, customers[4]);
            Assert.AreEqual(13, customers[5]);

            // create two routes.
            // 0->11->12->13->14->15->0
            // 0->21->22->23->24->25->0
            multiRoute = new MaxTimeSolution(0);
            route1     = multiRoute.Add();
            customers  = new List <int>(route1);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route1.InsertAfter(0, 11);
            Assert.AreEqual("0->11", route1.ToString());
            route1.InsertAfter(11, 12);
            route1.InsertAfter(12, 13);
            route1.InsertAfter(13, 14);
            route1.InsertAfter(14, 15);
            route2    = multiRoute.Add();
            customers = new List <int>(route2);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route2.InsertAfter(0, 21);
            Assert.AreEqual("0->21", route2.ToString());
            route2.InsertAfter(21, 22);
            route2.InsertAfter(22, 23);
            route2.InsertAfter(23, 24);
            route2.InsertAfter(24, 25);

            route1.ReplaceEdgeFrom(12, 15);
            route1.ReplaceEdgeFrom(14, 11);
            route1.ReplaceEdgeFrom(0, 13);

            customers = new List <int>(route1);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(13, customers[1]);
            Assert.AreEqual(14, customers[2]);
            Assert.AreEqual(11, customers[3]);
            Assert.AreEqual(12, customers[4]);
            Assert.AreEqual(15, customers[5]);

            route1.ToString();
        }
コード例 #37
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // get the seed customers.
            ICollection<int> seeds = _seed_selector.SelectSeeds(
                problem, _k);
            double[] weights = new double[seeds.Count];

            // start the seed routes.
            List<int> selectable_customers = problem.Customers;
            MaxTimeSolution routes = new MaxTimeSolution(
                problem.Size, true);
            foreach (int seed in seeds)
            {
                routes.Add(seed);
                selectable_customers.Remove(seed);
            }

            if (!routes.IsValid())
            {
                throw new Exception();
            }

            // keep a list of cheapest insertions.
            IInsertionCosts costs = new BinaryHeapInsertionCosts();

            // keep looping until all customers have been placed.
            while (selectable_customers.Count > 0)
            {
                // try and place into every route.
                CheapestInsertionResult best_result = new CheapestInsertionResult();
                best_result.Increase = float.MaxValue;
                int best_route_idx = -1;

                CheapestInsertionResult best_result_above_max = new CheapestInsertionResult();
                best_result_above_max.Increase = float.MaxValue;
                int best_route_above_max_idx = -1;

                for (int route_idx = 0; route_idx < routes.Count; route_idx++)
                {
                    IRoute current_route = routes.Route(route_idx);

                    // choose the next customer.
                    CheapestInsertionResult result =
                        CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, selectable_customers, costs);
                    if (result.Customer == result.CustomerAfter)
                    {
                        throw new Exception();
                    }
                    // get the current weight
                    double weight = weights[route_idx];
                    if (result.Increase < best_result.Increase)
                    {
                        if (weight + result.Increase + calculator.DeliveryTime < problem.Max.Value)
                        { // route will still be inside bounds.
                            best_result = result;
                            best_route_idx = route_idx;
                        }
                        else
                        { // route will become above max.
                            if (result.Increase < best_result_above_max.Increase)
                            {
                                best_result_above_max = result;
                                best_route_above_max_idx = route_idx;
                            }
                        }
                    }
                }

                // do the placement if a placement is found without max violation.
                // else do the placement in the above max route.
                CheapestInsertionResult placement_result = new CheapestInsertionResult();
                placement_result.Increase = double.MaxValue;
                int placement_result_idx = -1;
                if (best_route_idx >= 0)
                { // best placement found.
                    placement_result = best_result;
                    placement_result_idx = best_route_idx;
                }
                else
                { // best placement found but only above max.
                    placement_result = best_result_above_max;
                    placement_result_idx = best_route_above_max_idx;
                }

                // do the actual placement.
                weights[placement_result_idx] = calculator.CalculateOneRouteIncrease(
                    weights[placement_result_idx], placement_result.Increase);
                selectable_customers.Remove(placement_result.Customer);
                //routes.Route(placement_result_idx).InsertAfterAndRemove(
                //    placement_result.CustomerBefore, placement_result.Customer, placement_result.CustomerAfter);
                routes.Route(placement_result_idx).InsertAfter(
                    placement_result.CustomerBefore, placement_result.Customer);

                if (!routes.IsValid())
                {
                    throw new Exception();
                }
            }

            return routes;
        }
コード例 #38
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the calculator.
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List<int> customers = new List<int>(problem.Customers);
            while (customers.Count > 0)
            {
                // select a customer using some heuristic.
                int customer_idx = OsmSharp.Tools.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count);
                int customer = customers[customer_idx];
                customers.Remove(customer);

                // start a route r.
                double current_route_weight = 0;
                IRoute current_route = solution.Add(customer);
                //Console.WriteLine("Starting new route with {0}", customer);
                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result =
                        CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers);

                    // calculate the new weight.
                    double potential_weight = calculator.CalculateOneRouteIncrease(current_route_weight, result.Increase);
                    // cram as many customers into one route as possible.
                    if (potential_weight < problem.Max.Value)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                        current_route.InsertAfter(result.CustomerBefore, result.Customer);
                        current_route_weight = potential_weight;

                        //// improve if needed.
                        ////if (improvement_probalitity > OsmSharp.Tools.Math.Random.StaticRandomGenerator.Get().Generate(1))
                        //if (((problem.Size - customers.Count) % _k) == 0)
                        //{ // an improvement is descided.
                        //    current_route_weight = this.ImproveIntraRoute(problem,
                        //        current_route, current_route_weight);
                        //}
                    }
                    else
                    {// ok we are done!
                        //// apply the intra-route heuristics.
                        //for (int route_idx = 0; route_idx < solution.Count - 1; route_idx++)
                        //{ // apply the intra-route heurstic between the new and all existing routes.
                        //    this.ImproveInterRoute(problem, solution.Route(route_idx), current_route);
                        //}

                        //// apply the inter-route heuristics.
                        //for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        //{ // apply heurstic for each route.
                        //    IRoute route = solution.Route(route_idx);
                        //    this.ImproveIntraRoute(problem, current_route, current_route_weight);
                        //}

                        // break the route.
                        break;
                    }
                }
            }

            return solution;
        }
コード例 #39
0
ファイル: GuidedVNS.cs プロジェクト: yousoftvn/OsmSharp
        /// <summary>
        /// Apply some improvements between the given routes and returns the resulting weight.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1Idx"></param>
        /// <param name="route2Idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private bool ImproveInterRoute(MaxTimeProblem problem, MaxTimeSolution solution,
                                       int route1Idx, int route2Idx, double max)
        {
            // get the routes.
            IRoute route1 = solution.Route(route1Idx);
            IRoute route2 = solution.Route(route2Idx);

            int countBefore = route1.Count + route2.Count;

            // loop over all improvement operations.
            bool globalImprovement = false;

            foreach (IInterImprovement improvementOperation in _inter_improvements)
            { // try the current improvement operations.
                bool improvement = true;
                while (improvement)
                { // keep looping when there is improvement.
                    improvement = false;
                    double totalBefore = problem.Time(solution.Route(route1Idx)) +
                                         problem.Time(solution.Route(route2Idx));
                    if (improvementOperation.Improve(problem, solution, route1Idx, route2Idx, max))
                    { // there was an improvement.
                        improvement       = true;
                        globalImprovement = true;

                        // check if the route is valid.
                        if (!route1.IsValid())
                        {
                            throw new Exception();
                        }
                        if (!route2.IsValid())
                        {
                            throw new Exception();
                        }

                        int countAfter = route1.Count + route2.Count;
                        if (countBefore != countAfter)
                        {
                            throw new Exception();
                        }

                        double totalAfter = problem.Time(solution.Route(route1Idx)) +
                                            problem.Time(solution.Route(route2Idx));
                        if (totalAfter >= totalBefore)
                        {
                            throw new Exception("this is not an improvement!");
                        }

                        OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information,
                                                        "Inter-improvement found {0}<->{1}: {2} ({3}->{4})",
                                                        route1Idx, route2Idx, improvementOperation.Name, totalBefore, totalAfter);

                        // recalculate weights.
                        solution[route1Idx] = problem.Time(solution.Route(route1Idx));
                        solution[route2Idx] = problem.Time(solution.Route(route2Idx));

                        //break;
                    }
                    else if (!improvementOperation.IsSymmetric &&
                             improvementOperation.Improve(problem, solution, route2Idx, route1Idx, max))
                    { // also do the improvement the other way around when not symmetric.
                        improvement       = true;
                        globalImprovement = true;


                        // check if the route is valid.
                        if (!route1.IsValid())
                        {
                            throw new Exception();
                        }
                        if (!route2.IsValid())
                        {
                            throw new Exception();
                        }

                        int countAfter = route1.Count + route2.Count;
                        if (countBefore != countAfter)
                        {
                            throw new Exception();
                        }

                        double totalAfter = problem.Time(solution.Route(route1Idx)) +
                                            problem.Time(solution.Route(route2Idx));
                        if (totalAfter >= totalBefore)
                        {
                            throw new Exception("this is not an improvement!");
                        }

                        OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information,
                                                        "Inter-improvement found {0}<->{1}: {2} ({3}->{4})",
                                                        route2Idx, route1Idx, improvementOperation.Name, totalBefore, totalAfter);

                        // recalculate weights.
                        solution[route1Idx] = problem.Time(solution.Route(route1Idx));
                        solution[route2Idx] = problem.Time(solution.Route(route2Idx));

                        //break;
                    }
                }
            }
            return(globalImprovement);
        }
コード例 #40
0
        /// <summary>
        /// Applies inter-improvements by exchanging customers.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="solution"></param>
        /// <param name="route1_idx"></param>
        /// <param name="route2_idx"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public bool Improve(MaxTimeProblem problem, MaxTimeSolution solution,
            int route1_idx, int route2_idx, double max)
        {
            IRoute route1 = solution.Route(route1_idx);
            IRoute route2 = solution.Route(route2_idx);

            double total_before = problem.Time(solution.Route(route1_idx)) +
                problem.Time(solution.Route(route2_idx));

            double route1_size = solution[route1_idx];
            double route2_size = solution[route2_idx];

            // this heuristic removes a customer1 from route1 and a customer2 from route2 and inserts the customers again
            // but swappes them; customer1 in route2 and customer2 in route1.
            int previous_customer1 = -1;
            //if (route1.IsRound)
            //{
            //    previous_customer1= route1.Last; // set the previous customer.
            //}
            foreach (int customer1 in route1)
            { // loop over all customers in route1.
                if (previous_customer1 >= 0)
                { // the previous customer is set.
                    int next_customer1 = route1.GetNeigbours(customer1)[0];
                    if (next_customer1 < 0)
                    {
                        continue;
                    }

                    int previous_customer2 = -1;
                    //if (route2.IsRound)
                    //{
                    //    previous_customer2 = route2.Last; // set the previous customer.
                    //}

                    foreach (int customer2 in route2)
                    { // loop over all customers in route2.
                        int next_customer2 = route2.GetNeigbours(customer2)[0];
                        if (previous_customer2 >= 0 && next_customer2 >= 0)
                        { // the previous customer is set.
                            float weight1 = (float)problem.WeightMatrix[previous_customer1][customer1] +
                                (float)problem.WeightMatrix[customer1][next_customer1];
                            float weight2 = (float)problem.WeightMatrix[previous_customer2][customer2] +
                                (float)problem.WeightMatrix[customer2][next_customer2];

                            float weight1_after = (float)problem.WeightMatrix[previous_customer1][customer2] +
                                (float)problem.WeightMatrix[customer2][next_customer1];
                            float weight2_after = (float)problem.WeightMatrix[previous_customer2][customer1] +
                                (float)problem.WeightMatrix[customer1][next_customer2];
                            double difference = (weight1_after + weight2_after) - (weight1 + weight2);

                            if (difference < -0.01)
                            { // the old weights are bigger!
                                // check if the new routes are bigger than max.
                                if (route1_size + (weight1_after - weight1) <= max &&
                                    route2_size + (weight2_after - weight1) <= max)
                                { // the exchange can happen, both routes stay within bound!
                                    // exchange customer.
                                    int count_before = route1.Count + route2.Count;

                                    //route1.Remove(customer1);
                                    //route2.Remove(customer2);
                                    if (previous_customer1 == next_customer2)
                                    {
                                        throw new Exception();
                                    }

                                    //route1.InsertAfter(previous_customer1, customer2);
                                    //route2.InsertAfter(previous_customer2, customer1);
                                    route1.ReplaceEdgeFrom(previous_customer1, customer2);
                                    route1.ReplaceEdgeFrom(customer2, next_customer1);
                                    route2.ReplaceEdgeFrom(previous_customer2, customer1);
                                    route2.ReplaceEdgeFrom(customer1, next_customer2);

                                    int count_after = route1.Count + route2.Count;
                                    if (count_before != count_after)
                                    {
                                        throw new Exception();
                                    }

                                    double total_after = problem.Time(solution.Route(route1_idx)) +
                                        problem.Time(solution.Route(route2_idx));
                                    if (total_after >= total_before)
                                    {
                                        throw new Exception("this is not an improvement!");
                                    }

                                    return true;
                                }
                            }
                        }

                        previous_customer2 = customer2; // set the previous customer.
                    }
                }
                previous_customer1 = customer1; // set the previous customer.
            }
            return false;
        }
コード例 #41
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the calculator.
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List <int> customers = new List <int>(problem.Customers);

            while (customers.Count > 0)
            {
                // select a customer using some heuristic.
                int customer_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count);
                int customer     = customers[customer_idx];
                customers.Remove(customer);

                // start a route r.
                double current_route_weight = 0;
                IRoute current_route        = solution.Add(customer);
                //Console.WriteLine("Starting new route with {0}", customer);
                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result =
                        CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers);

                    // calculate the new weight.
                    double potential_weight = calculator.CalculateOneRouteIncrease(current_route_weight, result.Increase);
                    // cram as many customers into one route as possible.
                    if (potential_weight < problem.Max.Value)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                        current_route.InsertAfter(result.CustomerBefore, result.Customer);
                        current_route_weight = potential_weight;

                        //// improve if needed.
                        ////if (improvement_probalitity > OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(1))
                        //if (((problem.Size - customers.Count) % _k) == 0)
                        //{ // an improvement is descided.
                        //    current_route_weight = this.ImproveIntraRoute(problem,
                        //        current_route, current_route_weight);
                        //}
                    }
                    else
                    {// ok we are done!
                        //// apply the intra-route heuristics.
                        //for (int route_idx = 0; route_idx < solution.Count - 1; route_idx++)
                        //{ // apply the intra-route heurstic between the new and all existing routes.
                        //    this.ImproveInterRoute(problem, solution.Route(route_idx), current_route);
                        //}

                        //// apply the inter-route heuristics.
                        //for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        //{ // apply heurstic for each route.
                        //    IRoute route = solution.Route(route_idx);
                        //    this.ImproveIntraRoute(problem, current_route, current_route_weight);
                        //}

                        // break the route.
                        break;
                    }
                }
            }

            return(solution);
        }
コード例 #42
0
ファイル: MaxTimeProblem.cs プロジェクト: UnifyKit/OsmSharp
 /// <summary>
 /// Calculates the total time.
 /// </summary>
 /// <param name="solution"></param>
 /// <returns></returns>
 public double Time(MaxTimeSolution solution)
 {
     double time = 0;
     for (int idx = 0; idx < solution.Count; idx++)
     {
         time = time + this.Time(solution.Route(idx));
     }
     return time;
 }