/// <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);
        }
Esempio n. 2
0
        /// <summary>
        /// Does the actual solving.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        protected override IRoute DoSolve(IProblem problem)
        {
            // convert to a symetric problem if needed.
            IProblem _problem = problem;
            if (!_problem.Symmetric)
            {
                _problem = Convertor.ConvertToSymmetric(_problem);
                _was_asym = true;
            }

            // create the list of customers.
            _customers = new List<int>();
            for (int customer = 0; customer < _problem.Size; customer++)
            {
                _customers.Add(customer);
            }
            _sparse_set = SparseSetHelper.CreateNearestNeighourSet(_problem, _customers, _customers.Count / 10);
            //_sparse_set = SparseSetHelper.CreateNonSparseSet(_problem, _customers);
            // construct a route from the customers.
            //FixedSymmetricRoute init_route = new FixedSymmetricRoute(_customers);

            // construct a random route using best-placement.
            ArbitraryInsertionSolver bp_solver = new ArbitraryInsertionSolver();
            IRoute bp_route = bp_solver.Solve(_problem);
            FixedSymmetricRoute init_route = new FixedSymmetricRoute(bp_route);

            double init_route_weight = LinKernighanSolver.Weight(_problem, init_route);
            RouteFound route = new RouteFound()
            {
                Route = init_route,
                RouteWeight = init_route_weight
            };
            OsmSharp.Logging.Log.TraceEvent("LinKernighanSolver", Logging.TraceEventType.Information, "Route {0}:{1}",
                route.Route.ToString(),
                route.RouteWeight);

            // step 2.
            EdgeSet X = new EdgeSet();
            EdgeSet Y = new EdgeSet();
            IList<int> untried_t_1 = new List<int>(route.Route);
            while (untried_t_1.Count > 0)
            {
                // select t1.
                int t_1 = untried_t_1[0];
                untried_t_1.RemoveAt(0);

                // search route with t_1.
                RouteFound t_1_route = this.AfterSelectt1(_problem, route, X, Y, t_1);

                // select the better route.
                if (t_1_route.RouteWeight < route.RouteWeight)
                {
                    untried_t_1 = new List<int>(route.Route);
                    route = RouteFound.SelectBest(route, t_1_route);
                    X = new EdgeSet();
                    Y = new EdgeSet();
                }
            } // step 2 and step 12.

            // convert back to asym solution if needed.
            //result.RemoveAt(result.Count - 1);
            if (_was_asym)
            {
                return this.ConvertToASymRoute(new List<int>(route.Route));
            }
            return route.Route;
        }
        /// <summary>
        /// Returns a solution found using best-placement.
        /// </summary>
        /// <returns></returns>
        protected override IRoute DoSolve(IProblem problem)
        {
            // build the customer list to place.
            List <int> customers = null;

            if (_customers != null)
            { // copy the list of the given customers and keep this order.
                customers = new List <int>(_customers);
            }
            else
            { // generate some random route.
                customers = new List <int>();
                List <int> customers_to_place = new List <int>();
                for (int customer = 0; customer < problem.Size; customer++)
                {
                    customers_to_place.Add(customer);
                }
                while (customers_to_place.Count > 0)
                {
                    int idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers_to_place.Count);
                    customers.Add(customers_to_place[idx]);
                    customers_to_place.RemoveAt(idx);
                }
            }

            // initialize the route based on the problem definition.
            IRoute route  = null;
            double weight = double.MaxValue;

            if (problem.Symmetric)
            {     // create a symmetric route that is dynamic and can accept new customers.
                if (problem.First.HasValue && problem.Last.HasValue && problem.First == problem.Last)
                { // route is a round.
                    route = new DynamicSymmetricRoute(problem.First.Value);
                }
                else
                { // not a round.
                    throw new NotImplementedException("No symmetric routes implemented that are not rounds!");
                }
            }
            else
            {     // create a asymmetric route that is dynamic and can accept new customers.
                if (problem.First.HasValue)
                { // the first customer is set.
                    // test if the last customer is the same.
                    if (!problem.Last.HasValue ||
                        problem.Last == problem.First)
                    { // the route is a round.
                        route = new DynamicAsymmetricRoute(customers.Count, problem.First.Value, true);

                        // remove the first customer.
                        customers.Remove(problem.First.Value);

                        // find the customer that is farthest away and add it.
                        int to = -1;
                        weight = double.MinValue;
                        for (int x = 0; x < customers.Count; x++)
                        {
                            if (x != problem.First.Value)
                            { // only different customers.
                                double current_weight = problem.WeightMatrix[x][problem.First.Value] +
                                                        problem.WeightMatrix[problem.First.Value][x];
                                if (current_weight > weight)
                                { // the current weight is better.
                                    to     = x;
                                    weight = current_weight;
                                }
                            }
                        }
                        route.InsertAfter(problem.First.Value, to);
                        customers.Remove(to);
                    }
                    else
                    { // the route is not a round.
                        route = new DynamicAsymmetricRoute(customers.Count, problem.First.Value, false);
                        route.InsertAfter(problem.First.Value, problem.Last.Value);

                        // remove the first customer.
                        customers.Remove(problem.First.Value);
                        customers.Remove(problem.Last.Value);
                    }
                }
                else
                { // the first and last customer can be choosen randomly.
                    // find two customers close together.
                    int from = -1;
                    int to   = -1;
                    for (int x = 0; x < customers.Count; x++)
                    {
                        for (int y = 0; y < customers.Count; y++)
                        {
                            if (x != y)
                            { // only different customers.
                                double current_weight = problem.WeightMatrix[x][y];
                                if (current_weight < weight)
                                { // the current weight is better.
                                    from   = x;
                                    to     = y;
                                    weight = current_weight;

                                    if (weight == 0)
                                    { // no edge with less weight is going to be found.
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    route = new DynamicAsymmetricRoute(customers.Count, from, false);
                    route.InsertAfter(from, to);

                    // remove the first customer.
                    customers.Remove(from);
                    customers.Remove(to);
                }
            }

            // insert the rest of the customers.
            while (customers.Count > 0 && !_stopped)
            { // keep placing customer 0 until all customers are placed.
                int customer = customers[0];
                customers.RemoveAt(0);

                // insert the customer at the best place.
                double difference;
                ArbitraryInsertionSolver.InsertOne(problem, route, customer, out difference);
            }

            return(route);
        }