Exemplo n.º 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));
        }
        /// <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;
        }
        /// <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);
        }
Exemplo n.º 4
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);
        }
Exemplo n.º 5
0
        /// <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;
        }
Exemplo n.º 6
0
        /// <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;
        }
        /// <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;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            float lambda = _lambda;

            CheapestInsertionSolverWithImprovements vrp_router =
                new CheapestInsertionSolverWithImprovements(problem.Max.Value, problem.DeliveryTime.Value, 10, 0.10f, true, _threshold_percentage, true, 0.75f);
            MaxTimeSolution original_solution = vrp_router.Solve(
                problem);

            for (int round_x = 0; round_x < original_solution.Count; round_x++)
            { // keep looping on rounds.
                for (int round_y = 0; round_y < round_x; round_y++)
                { // keep looping on rounds with a smaller index not equal to the current round.
                    if (round_x != round_y)
                    { // routes are different.
                        if (this.Overlaps(problem, original_solution.Route(round_x), original_solution.Route(round_y)))
                        { // only check routes that overlap.
                            double tau = double.MinValue;
                            Dictionary<Edge, int> 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 route1_actual_before = problem.Time(original_solution.Route(round_x));
                                double route2_actual_before = problem.Time(original_solution.Route(round_y));

                                // copy orignal solution.
                                MaxTimeSolution solution = (original_solution.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 count_before = solution.Route(round_x).Count + solution.Route(round_y).Count;
                                int count_after;
                                if (this.ImproveInterRoute(problem, solution, round_x, round_y, problem.Max.Value))
                                { // the improve inter route succeeded.
                                    if (!solution.IsValid())
                                    {
                                        throw new Exception();
                                    }
                                    //improvement_inter = true;

                                    count_after = solution.Route(round_x).Count + solution.Route(round_y).Count;
                                    if (count_before != count_after)
                                    {
                                        throw new Exception();
                                    }

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

                                    // recalculate weights.
                                    solution[round_x] = problem.Time(solution.Route(round_x));
                                    solution[round_y] = problem.Time(solution.Route(round_y));
                                }

                                // check customer counts.
                                count_after = solution.Route(round_x).Count + solution.Route(round_y).Count;
                                if (count_before != count_after)
                                {
                                    throw new Exception();
                                }

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

                                // check against the orginal objective function.
                                double route1_actual_after = problem.Time(solution.Route(round_x));
                                double route2_actual_after = problem.Time(solution.Route(round_y));
                                if (route1_actual_after + route2_actual_after < route1_actual_before + route2_actual_before - 0.001 &&
                                    route1_actual_after < problem.Max.Value && route2_actual_after < problem.Max.Value)
                                { // there is improvement!
                                    original_solution = solution;

                                    //improvement = true;

                                    OsmSharp.Tools.Output.OutputStreamHost.WriteLine("IMPROVEMENT: {0}->{1}",
                                        route1_actual_before + route2_actual_before, route1_actual_after + route2_actual_after);
                                }

                                // select arc to be penalized.
                                IRoute route1 = original_solution.Route(round_x);
                                IRoute route2 = original_solution.Route(round_y);
                                double u = double.MinValue;
                                Edge penalizing_edge = new Edge();
                                double total_p = 0;
                                foreach (Edge edge in route1.Edges())
                                {
                                    int edge_p;
                                    if (!penalizations.TryGetValue(edge, out edge_p))
                                    {
                                        edge_p = 0;
                                    }
                                    total_p = total_p + edge_p;
                                    double edge_u = ((lambda * (double)edge_p) + problem.WeightMatrix[edge.From][edge.To]) /
                                        ((double)edge_p + 1.0);
                                    if (u <= edge_u)
                                    {
                                        penalizing_edge = edge;
                                        u = edge_u;
                                    }
                                }
                                foreach (Edge edge in route2.Edges())
                                {
                                    int edge_p;
                                    if (!penalizations.TryGetValue(edge, out edge_p))
                                    {
                                        edge_p = 0;
                                    }
                                    total_p = total_p + edge_p;
                                    double edge_u = ((lambda * (double)edge_p) + problem.WeightMatrix[edge.From][edge.To]) /
                                        ((double)edge_p + 1.0);
                                    if (u <= edge_u)
                                    {
                                        penalizing_edge = edge;
                                        u = edge_u;
                                    }
                                }

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

                                // evaluate or set tau.
                                if (tau > double.MinValue)
                                { // evaluate if penalizations should end.
                                    if (tau <= lambda * total_p)
                                    { // the penalization should end!
                                        break;
                                    }
                                }
                                else
                                { // first edge being penalized.
                                    tau = lambda * problem.WeightMatrix[penalizing_edge.From][penalizing_edge.To] / 10;
                                }
                            }
                        }
                    }
                }
            }
            return original_solution;
        }
Exemplo n.º 9
0
        ///// <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;
        }
Exemplo n.º 10
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;
        }
Exemplo n.º 11
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);
        }
Exemplo n.º 12
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);
        }
        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);
        }
        /// <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;
        }
Exemplo n.º 15
0
        /// <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);
        }
Exemplo n.º 16
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);
        }
Exemplo n.º 17
0
        /// <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);
        }
        /// <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;
        }