Beispiel #1
0
        /// <summary>
        /// Improves an existing solution.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="difference"></param>
        /// <returns></returns>
        public bool Improve(IProblemWeights problem, IRoute route, out double difference)
        {
            if (!route.IsValid())
            {
                throw new Exception();
            }

            _dont_look_bits = new bool[problem.Size];
            double[][] weights = problem.WeightMatrix;

            // loop over all customers.
            bool any_improvement = false;
            bool improvement     = true;

            difference = -1;
            while (improvement)
            {
                improvement = false;
                foreach (int v_1 in route)
                {
                    if (!this.Check(problem, v_1))
                    {
                        if (this.Try3OptMoves(problem, weights, route, v_1))
                        {
                            any_improvement = true;
                            improvement     = true;
                            break;
                        }
                        this.Set(problem, v_1, true);
                    }
                }
            }
            return(any_improvement);
        }
Beispiel #2
0
 /// <summary>
 /// Returns true if the route is valid.
 /// </summary>
 /// <returns></returns>
 public bool IsValid()
 {
     if (_route == null)
     {
         return(true);
     }
     return(_route.IsValid() && !_route.Contains(0));
 }
Beispiel #3
0
        /// <summary>
        /// Apply some improvements within one route.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="currentWeight"></param>
        private double ImproveIntraRoute(OsmSharp.Math.VRP.Core.IProblemWeights problem, IRoute route,
                                         double currentWeight)
        {
            bool   improvement = true;
            double newWeight   = currentWeight;

            while (improvement)
            { // keep trying while there are still improvements.
                improvement = false;

                // loop over all improvement operations.
                foreach (IImprovement improvementOperation in _intraImprovements)
                { // try the current improvement operations.
                    double difference;
                    if (improvementOperation.Improve(problem, route, out difference))
                    { // there was an improvement.
                        OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.WithDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information,
                                                        "Intra-improvement found {0} {1}->{2}",
                                                        improvementOperation.Name, newWeight, newWeight + difference);

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

                        // update the weight.
                        newWeight = newWeight + difference;

                        improvement = true;

                        break;
                    }
                }
            }
            return(newWeight);
        }
        /// <summary>
        /// Tries to improve the existing route using CI and return true if succesful.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="difference"></param>
        /// <returns></returns>
        public bool Improve(IProblemWeights problem, IRoute route, out double difference)
        {
            bool improvement = false;

            difference = 0;
            if (route.Count > 3)
            {
                // loop over all customers and try cheapest insertion.
                for (int customer = 0; customer < problem.Size; customer++)
                {
                    //string route_string = route.ToString();
                    //IRoute previous = route.Clone() as IRoute;
                    if (route.Contains(customer))
                    {
                        // remove customer and keep position.
                        int next = route.GetNeigbours(customer)[0];
                        route.Remove(customer);

                        // insert again.
                        ArbitraryInsertionSolver.InsertOne(problem, route, customer, out difference);

                        if (!route.IsValid())
                        {
                            throw new Exception();
                        }
                        if (route.GetNeigbours(customer)[0] != next &&
                            difference < 0)
                        { // another customer was found as the best, improvement is succesful.
                            improvement = true;
                            break;
                        }
                    }
                }
            }
            return(improvement);
        }
Beispiel #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);
        }
Beispiel #6
0
        /// <summary>
        /// Apply some improvements within one route.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="currentWeight"></param>
        private double ImproveIntraRoute(IProblemWeights problem, IRoute route, double currentWeight)
        {
            bool improvement = true;
            double newWeight = currentWeight;
            while (improvement)
            { // keep trying while there are still improvements.
                improvement = false;

                // loop over all improvement operations.
                foreach (IImprovement improvementOperation in _intra_improvements)
                { // try the current improvement operations.
                    double difference;
                    if (improvementOperation.Improve(problem, route, out difference))
                    { // there was an improvement.
                        OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information,
                            "Intra-improvement found {0} {1}->{2}",
                            improvementOperation.Name, newWeight, newWeight + difference);

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

                        // update the weight.
                        newWeight = newWeight + difference;

                        improvement = true;

                        break;
                    }
                }
            }
            return newWeight;
        }
Beispiel #7
0
        /// <summary>
        /// Tries all 3Opt Moves for the neighbourhood of v_1 containing v_3.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="weights"></param>
        /// <param name="route"></param>
        /// <param name="v1"></param>
        /// <param name="v_2"></param>
        /// <param name="v_3"></param>
        /// <param name="weights_3"></param>
        /// <param name="v_4"></param>
        /// <param name="weight_1_2_plus_3_4"></param>
        /// <param name="weight_1_4"></param>
        /// <returns></returns>
        public bool Try3OptMoves(IProblemWeights problem, double[][] weights, IRoute route,
                                 int v1, int v_2, int v_3, double[] weights_3, int v_4, double weight_1_2_plus_3_4, double weight_1_4)
        {
            //IEnumerable<int> between_v_4_v_1 = route.Between(v_4, v_1);
            //foreach (int v_5 in between_v_4_v_1)
            //{
            //    if (v_5 != v_1)
            //    {
            //        if (this.Try3OptMove(problem, weights, route, v_1, v_2, v_3, weights_3, v_4, weight_1_2_plus_3_4, weight_1_4, v_5))
            //        {
            //            return true;
            //        }
            //    }
            //}
            //return false;

            IEnumerator <int> between_v_4_v_1_enumerator = route.Between(v_4, v1).GetEnumerator();

            if (between_v_4_v_1_enumerator.MoveNext())
            {
                int v_5 = between_v_4_v_1_enumerator.Current;
                if (v_5 != v1)
                {
                    while (between_v_4_v_1_enumerator.MoveNext())
                    {
                        int v_6 = between_v_4_v_1_enumerator.Current;
                        //Console.WriteLine(v_6);
                        //if (this.Try3OptMove(problem, weights,
                        //    route, v_1, v_2, v_3, weights_3, v_4,
                        //    weight_1_2_plus_3_4, weight_1_4, v_5, v_6))
                        //{
                        // calculate the total weight of the 'new' arcs.
                        double weight_new = weight_1_4 +
                                            weights_3[v_6] +
                                            weights[v_5][v_2];

                        // calculate the total weights.
                        double weight = weight_1_2_plus_3_4 + weights[v_5][v_6];

                        if (weight - weight_new > _epsilon)
                        { // actually do replace the vertices.
                            int count_before = route.Count;
                            //string route_string = route.ToString();

                            route.ReplaceEdgeFrom(v1, v_4);
                            route.ReplaceEdgeFrom(v_3, v_6);
                            route.ReplaceEdgeFrom(v_5, v_2);

                            int count_after = route.Count;

                            if (count_before != count_after)
                            {
                                throw new Exception();
                            }
                            // set bits.
                            //this.Set(problem, v_1, false);
                            this.Set(problem, v_3, false);
                            this.Set(problem, v_5, false);

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

                            return(true); // move succeeded.
                        }
                        //}
                        v_5 = v_6;
                    }
                }
            }
            return(false);
        }
Beispiel #8
0
        /// <summary>
        /// Apply some improvements within one route.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="current_weight"></param>
        private double ImproveIntraRoute(IProblemWeights problem, IRoute route, double current_weight)
        {
            bool improvement = true;
            double new_weight = current_weight;
            while (improvement)
            { // keep trying while there are still improvements.
                improvement = false;

                // loop over all improvement operations.
                foreach (IImprovement improvement_operation in _intra_improvements)
                { // try the current improvement operations.
                    double difference;
                    if (improvement_operation.Improve(problem, route, out difference))
                    { // there was an improvement.
                        OsmSharp.Tools.Output.OutputStreamHost.WriteLine("Intra-improvement found {0} {1}->{2}",
                            improvement_operation.Name, new_weight, new_weight + difference);

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

                        // update the weight.
                        new_weight = new_weight + difference;

                        improvement = true;

                        break;
                    }
                }
            }
            return new_weight;
        }
Beispiel #9
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);
        }
        /// <summary>
        /// Tries to improve the existing route using CI and return true if succesful.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="difference"></param>
        /// <returns></returns>
        public bool Improve(IProblemWeights problem, IRoute route, out double difference)
        {
            bool improvement = false;

            difference = 0;
            if (route.Count > 3)
            {
                // loop over all customers and try cheapest insertion.
                for (int customer = 0; customer < problem.Size; customer++)
                {
                    //string route_string = route.ToString();
                    //IRoute previous = route.Clone() as IRoute;
                    if (route.Contains(customer))
                    {
                        // remove customer and keep position.
                        int next = route.GetNeigbours(customer)[0];
                        route.Remove(customer);

                        // insert again.
                        ArbitraryInsertionSolver.InsertOne(problem, route, customer, out difference);

                        if (!route.IsValid())
                        {
                            throw new Exception();
                        }
                        if (route.GetNeigbours(customer)[0] != next
                            && difference < 0)
                        { // another customer was found as the best, improvement is succesful.
                            improvement = true;
                            break;
                        }
                    }
                }
            }
            return improvement;
        }
        /// <summary>
        /// Tries all 3Opt Moves for the neighbourhood of v_1 containing v_3.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="weights"></param>
        /// <param name="route"></param>
        /// <param name="v1"></param>
        /// <param name="v_2"></param>
        /// <param name="v_3"></param>
        /// <param name="weights_3"></param>
        /// <param name="v_4"></param>
        /// <param name="weight_1_2_plus_3_4"></param>
        /// <param name="weight_1_4"></param>
        /// <returns></returns>
        public bool Try3OptMoves(IProblemWeights problem, double[][] weights, IRoute route,
            int v1, int v_2, int v_3, double[] weights_3, int v_4, double weight_1_2_plus_3_4, double weight_1_4)
        {
            //IEnumerable<int> between_v_4_v_1 = route.Between(v_4, v_1);
            //foreach (int v_5 in between_v_4_v_1)
            //{
            //    if (v_5 != v_1)
            //    {
            //        if (this.Try3OptMove(problem, weights, route, v_1, v_2, v_3, weights_3, v_4, weight_1_2_plus_3_4, weight_1_4, v_5))
            //        {
            //            return true;
            //        }
            //    }
            //}
            //return false;

            IEnumerator<int> between_v_4_v_1_enumerator = route.Between(v_4, v1).GetEnumerator();
            if (between_v_4_v_1_enumerator.MoveNext())
            {
                int v_5 = between_v_4_v_1_enumerator.Current;
                if (v_5 != v1)
                {
                    while (between_v_4_v_1_enumerator.MoveNext())
                    {
                        int v_6 = between_v_4_v_1_enumerator.Current;
                        //Console.WriteLine(v_6);
                        //if (this.Try3OptMove(problem, weights,
                        //    route, v_1, v_2, v_3, weights_3, v_4,
                        //    weight_1_2_plus_3_4, weight_1_4, v_5, v_6))
                        //{
                        // calculate the total weight of the 'new' arcs.
                        double weight_new = weight_1_4 +
                            weights_3[v_6] +
                            weights[v_5][v_2];

                        // calculate the total weights.
                        double weight = weight_1_2_plus_3_4 + weights[v_5][v_6];

                        if (weight - weight_new > _epsilon)
                        { // actually do replace the vertices.
                            int count_before = route.Count;
                            //string route_string = route.ToString();

                            route.ReplaceEdgeFrom(v1, v_4);
                            route.ReplaceEdgeFrom(v_3, v_6);
                            route.ReplaceEdgeFrom(v_5, v_2);

                            int count_after = route.Count;

                            if (count_before != count_after)
                            {
                                throw new Exception();
                            }
                            // set bits.
                            //this.Set(problem, v_1, false);
                            this.Set(problem, v_3, false);
                            this.Set(problem, v_5, false);

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

                            return true; // move succeeded.
                        }
                        //}
                        v_5 = v_6;
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// Improves an existing solution.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="difference"></param>
        /// <returns></returns>
        public bool Improve(IProblemWeights problem, IRoute route, out double difference)
        {
            if (!route.IsValid())
            {
                throw new Exception();
            }

            _dont_look_bits = new bool[problem.Size];
            double[][] weights = problem.WeightMatrix;

            // loop over all customers.
            bool any_improvement = false;
            bool improvement = true;
            difference = -1;
            while (improvement)
            {
                improvement = false;
                foreach (int v_1 in route)
                {
                    if (!this.Check(problem, v_1))
                    {
                        if (this.Try3OptMoves(problem, weights, route, v_1))
                        {
                            any_improvement = true;
                            improvement = true;
                            break;
                        }
                        this.Set(problem, v_1, true);
                    }
                }
            }
            return any_improvement;
        }