Exemplo n.º 1
0
        private void AddTimeWindowConstrains(WorkData data, RoutingIndexManager manager, RoutingModel routing)
        {
            // Create and register a transit callback
            int transitCallbackIndex = routing.RegisterTransitCallback(
                (long fromIndex, long toIndex) =>
            {
                int fromNode = manager.IndexToNode(fromIndex);
                int toNode   = manager.IndexToNode(toIndex);
                return(data.DurationMatrix[fromNode, toNode] + data.ServiceTimes[fromNode]);
            });

            routing.AddDimension(transitCallbackIndex, 120, MAX_VEHICLE_ROUTING_TIME, false, "Time");

            // Add time window constraints for each location except depot
            RoutingDimension timeDimension = routing.GetDimensionOrDie("Time");

            for (int i = 1; i < data.TimeWindows.GetLength(0); ++i)
            {
                long index = manager.NodeToIndex(i);
                timeDimension.CumulVar(index).SetRange(data.TimeWindows[i][0], data.TimeWindows[i][1]);
            }
            // Add time window constraints for each vehicle start node
            for (int i = 0; i < data.VehiclesAmount; ++i)
            {
                long index = routing.Start(i);
                timeDimension.CumulVar(index).SetRange(data.TimeWindows[0][0], data.TimeWindows[0][1]);

                routing.AddVariableMinimizedByFinalizer(timeDimension.CumulVar(routing.Start(i)));
                routing.AddVariableMinimizedByFinalizer(timeDimension.CumulVar(routing.End(i)));
            }
        }
Exemplo n.º 2
0
    static void Solve(int size, int forbidden, int seed)
    {
        RoutingIndexManager manager = new RoutingIndexManager(size, 1, 0);
        RoutingModel        routing = new RoutingModel(manager);

        // Setting the cost function.
        // Put a permanent callback to the distance accessor here. The callback
        // has the following signature: ResultCallback2<int64_t, int64_t, int64_t>.
        // The two arguments are the from and to node inidices.
        RandomManhattan distances = new RandomManhattan(manager, size, seed);

        routing.SetArcCostEvaluatorOfAllVehicles(routing.RegisterTransitCallback(distances.Call));

        // Forbid node connections (randomly).
        Random randomizer            = new Random();
        long   forbidden_connections = 0;

        while (forbidden_connections < forbidden)
        {
            long from = randomizer.Next(size - 1);
            long to   = randomizer.Next(size - 1) + 1;
            if (routing.NextVar(from).Contains(to))
            {
                Console.WriteLine("Forbidding connection {0} -> {1}", from, to);
                routing.NextVar(from).RemoveValue(to);
                ++forbidden_connections;
            }
        }

        // Add dummy dimension to test API.
        routing.AddDimension(routing.RegisterUnaryTransitCallback((long index) =>
                                                                  { return(1); }),
                             size + 1, size + 1, true, "dummy");

        // Solve, returns a solution if any (owned by RoutingModel).
        RoutingSearchParameters search_parameters =
            operations_research_constraint_solver.DefaultRoutingSearchParameters();

        // Setting first solution heuristic (cheapest addition).
        search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;

        Assignment solution = routing.SolveWithParameters(search_parameters);

        Console.WriteLine("Status = {0}", routing.GetStatus());
        if (solution != null)
        {
            // Solution cost.
            Console.WriteLine("Cost = {0}", solution.ObjectiveValue());
            // Inspect solution.
            // Only one route here; otherwise iterate from 0 to routing.vehicles() - 1
            int route_number = 0;
            for (long node = routing.Start(route_number); !routing.IsEnd(node);
                 node = solution.Value(routing.NextVar(node)))
            {
                Console.Write("{0} -> ", node);
            }
            Console.WriteLine("0");
        }
    }
Exemplo n.º 3
0
    static void Solve(int size, int forbidden, int seed)
    {
        RoutingModel routing = new RoutingModel(size, 1);

        // Setting first solution heuristic (cheapest addition).
        routing.SetFirstSolutionStrategy(RoutingModel.ROUTING_PATH_CHEAPEST_ARC);

        // Setting the cost function.
        // Put a permanent callback to the distance accessor here. The callback
        // has the following signature: ResultCallback2<int64, int64, int64>.
        // The two arguments are the from and to node inidices.
        RandomManhattan distances = new RandomManhattan(size, seed);

        routing.SetCost(distances);

        // Forbid node connections (randomly).
        Random randomizer            = new Random();
        long   forbidden_connections = 0;

        while (forbidden_connections < forbidden)
        {
            long from = randomizer.Next(size - 1);
            long to   = randomizer.Next(size - 1) + 1;
            if (routing.NextVar(from).Contains(to))
            {
                Console.WriteLine("Forbidding connection {0} -> {1}", from, to);
                routing.NextVar(from).RemoveValue(to);
                ++forbidden_connections;
            }
        }

        // Add dummy dimension to test API.
        routing.AddDimension(new ConstantCallback(),
                             size + 1,
                             size + 1,
                             true,
                             "dummy");

        // Solve, returns a solution if any (owned by RoutingModel).
        Assignment solution = routing.Solve();

        if (solution != null)
        {
            // Solution cost.
            Console.WriteLine("Cost = {0}", solution.ObjectiveValue());
            // Inspect solution.
            // Only one route here; otherwise iterate from 0 to routing.vehicles() - 1
            int route_number = 0;
            for (long node = routing.Start(route_number);
                 !routing.IsEnd(node);
                 node = solution.Value(routing.NextVar(node)))
            {
                Console.Write("{0} -> ", node);
            }
            Console.WriteLine("0");
        }
    }
Exemplo n.º 4
0
        /// <summary>
        ///   Print the solution.
        /// </summary>
        static void VRP_LongestSingleRoute()
        {
            Console.WriteLine("VRP_LongestSingleRoute!");
            // Instantiate the data problem.
            ORDataModel data = new ORDataModel();

            // public RoutingIndexManager(int num_nodes, int num_vehicles, int depot);
            //public RoutingIndexManager(int num_nodes, int num_vehicles, int[] starts, int[] ends);

            // Create Routing Index Manager
            RoutingIndexManager manager = new RoutingIndexManager(
                data.DistanceMatrix.GetLength(0),
                data.VehicleNumber,
                data.Depot);


            // Create Routing Model.
            RoutingModel routing = new RoutingModel(manager);

            // Create and register a transit callback.
            int transitCallbackIndex = routing.RegisterTransitCallback(
                (long fromIndex, long toIndex) => {
                // Convert from routing variable Index to distance matrix NodeIndex.
                var fromNode = manager.IndexToNode(fromIndex);
                var toNode   = manager.IndexToNode(toIndex);
                return(data.DistanceMatrix[fromNode, toNode]);
            }
                );

            // Define cost of each arc.
            routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);

            // Add Distance constraint.
            routing.AddDimension(transitCallbackIndex, 0, 3000,
                                 true, // start cumul to zero
                                 "Distance");
            RoutingDimension distanceDimension = routing.GetMutableDimension("Distance");

            distanceDimension.SetGlobalSpanCostCoefficient(100);

            // Setting first solution heuristic.
            RoutingSearchParameters searchParameters =
                operations_research_constraint_solver.DefaultRoutingSearchParameters();

            searchParameters.FirstSolutionStrategy =
                FirstSolutionStrategy.Types.Value.PathCheapestArc;

            // Solve the problem.
            Assignment solution = routing.SolveWithParameters(searchParameters);

            // Print solution on console.
            PrintSolutionPathCheapest(data, routing, manager, solution);
        }
Exemplo n.º 5
0
        private static void AddTimeDimension(FeatureCollection input, RoutingModel routing, NodeEvaluator2 evaluator)
        {
            var speed = 10 * 1000 / 3600; // 10 km/h

            routing.AddDimension(new ServiceTimeEvaluator(evaluator, speed), 24 * 3600, 24 * 3600, true, "Time");
            var timeDimension = routing.GetDimensionOrDie("Time");
            var timeWindow    = 3600 * 3;

            for (int i = 0; i < input.Features.Count; i++)
            {
                var feature = input.Features[i];
                if (feature.Properties.ContainsKey("start"))
                {
                    int start = Convert.ToInt32(feature.Properties["start"]),
                        end   = start + timeWindow;
                    timeDimension.CumulVar(routing.NodeToIndex(i)).SetRange(start, end);
                }
            }
        }
Exemplo n.º 6
0
    /// <summary>
    ///   Solves the current routing problem.
    /// </summary>
    private void Solve(int number_of_orders, int number_of_vehicles)
    {
        Console.WriteLine("Creating model with " + number_of_orders +
                          " orders and " + number_of_vehicles + " vehicles.");
        // Finalizing model
        int number_of_locations = locations_.Length;

        RoutingModel model =
            new RoutingModel(number_of_locations, number_of_vehicles,
                             vehicle_starts_, vehicle_ends_);

        // Setting up dimensions
        const int      big_number         = 100000;
        NodeEvaluator2 manhattan_callback = new Manhattan(locations_, 1);

        model.AddDimension(
            manhattan_callback, big_number, big_number, false, "time");
        NodeEvaluator2 demand_callback = new Demand(order_demands_);

        model.AddDimension(demand_callback, 0, vehicle_capacity_, true, "capacity");

        // Setting up vehicles
        NodeEvaluator2[] cost_callbacks = new NodeEvaluator2[number_of_vehicles];
        for (int vehicle = 0; vehicle < number_of_vehicles; ++vehicle)
        {
            int            cost_coefficient        = vehicle_cost_coefficients_[vehicle];
            NodeEvaluator2 manhattan_cost_callback =
                new Manhattan(locations_, cost_coefficient);
            cost_callbacks[vehicle] = manhattan_cost_callback;
            model.SetVehicleCost(vehicle, manhattan_cost_callback);
            model.CumulVar(model.End(vehicle), "time").SetMax(
                vehicle_end_time_[vehicle]);
        }

        // Setting up orders
        for (int order = 0; order < number_of_orders; ++order)
        {
            model.CumulVar(order, "time").SetRange(order_time_windows_[order].start_,
                                                   order_time_windows_[order].end_);
            int[] orders = { order };
            model.AddDisjunction(orders, order_penalties_[order]);
        }

        // Solving
        RoutingSearchParameters search_parameters =
            RoutingModel.DefaultSearchParameters();

        search_parameters.FirstSolutionStrategy =
            FirstSolutionStrategy.Types.Value.AllUnperformed;

        Console.WriteLine("Search");
        Assignment solution = model.SolveWithParameters(search_parameters);

        //protect callbacks from the GC
        GC.KeepAlive(manhattan_callback);
        GC.KeepAlive(demand_callback);
        for (int cost_callback_index = 0; cost_callback_index < cost_callbacks.Length; cost_callback_index++)
        {
            GC.KeepAlive(cost_callbacks[cost_callback_index]);
        }

        if (solution != null)
        {
            String output = "Total cost: " + solution.ObjectiveValue() + "\n";
            // Dropped orders
            String dropped = "";
            for (int order = 0; order < number_of_orders; ++order)
            {
                if (solution.Value(model.NextVar(order)) == order)
                {
                    dropped += " " + order;
                }
            }
            if (dropped.Length > 0)
            {
                output += "Dropped orders:" + dropped + "\n";
            }
            // Routes
            for (int vehicle = 0; vehicle < number_of_vehicles; ++vehicle)
            {
                String route = "Vehicle " + vehicle + ": ";
                long   order = model.Start(vehicle);
                if (model.IsEnd(solution.Value(model.NextVar(order))))
                {
                    route += "Empty";
                }
                else
                {
                    for (;
                         !model.IsEnd(order);
                         order = solution.Value(model.NextVar(order)))
                    {
                        IntVar local_load = model.CumulVar(order, "capacity");
                        IntVar local_time = model.CumulVar(order, "time");
                        route += order + " Load(" + solution.Value(local_load) + ") " +
                                 "Time(" + solution.Min(local_time) + ", " +
                                 solution.Max(local_time) + ") -> ";
                    }
                    IntVar load = model.CumulVar(order, "capacity");
                    IntVar time = model.CumulVar(order, "time");
                    route += order + " Load(" + solution.Value(load) + ") " +
                             "Time(" + solution.Min(time) + ", " + solution.Max(time) + ")";
                }
                output += route + "\n";
            }
            Console.WriteLine(output);
        }
    }
Exemplo n.º 7
0
        // <summary>
        // Получаем предложение по оптимальному расположению адресов в указанном маршруте.
        // Рачет идет с учетом окон доставки. Но естественно без любых ограничений по весу и прочему.
        // </summary>
        // <returns>Предолженый маршрут</returns>
        // <param name="route">Первоначальный маршрутный лист, чтобы взять адреса.</param>
        public ProposedRoute RebuidOneRoute(RouteList route)
        {
            var trip = new PossibleTrip(route);

            logger.Info("Подготавливаем заказы...");
            PerformanceHelper.StartMeasurement($"Строим маршрут");

            List <CalculatedOrder> calculatedOrders = new List <CalculatedOrder>();

            foreach (var address in route.Addresses)
            {
                if (address.Order.DeliveryPoint.Longitude == null || address.Order.DeliveryPoint.Latitude == null)
                {
                    continue;
                }

                calculatedOrders.Add(new CalculatedOrder(address.Order, null));
            }
            Nodes = calculatedOrders.ToArray();

            distanceCalculator = new ExtDistanceCalculator(DistanceProvider.Osrm, Nodes.Select(x => x.Order.DeliveryPoint).ToArray(), StatisticsTxtAction);

            PerformanceHelper.AddTimePoint(logger, $"Подготовка заказов");

            logger.Info("Создаем модель...");
            RoutingModel routing = new RoutingModel(Nodes.Length + 1, 1, 0);

            int horizon = 24 * 3600;

            routing.AddDimension(new CallbackTime(Nodes, trip, distanceCalculator), 3 * 3600, horizon, false, "Time");
            var time_dimension = routing.GetDimensionOrDie("Time");

            var cumulTimeOnEnd   = routing.CumulVar(routing.End(0), "Time");
            var cumulTimeOnBegin = routing.CumulVar(routing.Start(0), "Time");

            if (route.Shift != null)
            {
                var shift = route.Shift;
                cumulTimeOnEnd.SetMax((long)shift.EndTime.TotalSeconds);
                cumulTimeOnBegin.SetMin((long)shift.StartTime.TotalSeconds);
            }

            routing.SetArcCostEvaluatorOfVehicle(new CallbackDistance(Nodes, distanceCalculator), 0);

            for (int ix = 0; ix < Nodes.Length; ix++)
            {
                var startWindow = Nodes[ix].Order.DeliverySchedule.From.TotalSeconds;
                var endWindow   = Nodes[ix].Order.DeliverySchedule.To.TotalSeconds - trip.Driver.TimeCorrection(Nodes[ix].Order.CalculateTimeOnPoint(route.Forwarder != null));
                if (endWindow < startWindow)
                {
                    logger.Warn("Время разгрузки на точке, не помещается в диапазон времени доставки. {0}-{1}", Nodes[ix].Order.DeliverySchedule.From, Nodes[ix].Order.DeliverySchedule.To);
                    endWindow = startWindow;
                }
                time_dimension.CumulVar(ix + 1).SetRange((long)startWindow, (long)endWindow);
                routing.AddDisjunction(new int[] { ix + 1 }, MaxDistanceAddressPenalty);
            }

            RoutingSearchParameters search_parameters = RoutingModel.DefaultSearchParameters();

            search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.ParallelCheapestInsertion;

            search_parameters.TimeLimitMs = MaxTimeSeconds * 1000;
            //search_parameters.FingerprintArcCostEvaluators = true;
            //search_parameters.OptimizationStep = 100;

            var solver = routing.solver();

            PerformanceHelper.AddTimePoint(logger, $"Настроили оптимизацию");
            logger.Info("Закрываем модель...");
            logger.Info("Рассчет расстояний между точками...");
            routing.CloseModelWithParameters(search_parameters);
            distanceCalculator.FlushCache();
            var lastSolution = solver.MakeLastSolutionCollector();

            lastSolution.AddObjective(routing.CostVar());
            routing.AddSearchMonitor(lastSolution);
            routing.AddSearchMonitor(new CallbackMonitor(solver, StatisticsTxtAction, lastSolution));

            PerformanceHelper.AddTimePoint(logger, $"Закрыли модель");
            logger.Info("Поиск решения...");

            Assignment solution = routing.SolveWithParameters(search_parameters);

            PerformanceHelper.AddTimePoint(logger, $"Получили решение.");
            logger.Info("Готово. Заполняем.");
            Console.WriteLine("Status = {0}", routing.Status());
            ProposedRoute proposedRoute = null;

            if (solution != null)
            {
                // Solution cost.
                Console.WriteLine("Cost = {0}", solution.ObjectiveValue());
                time_dimension = routing.GetDimensionOrDie("Time");

                int route_number = 0;

                proposedRoute = new ProposedRoute(null);
                long first_node  = routing.Start(route_number);
                long second_node = solution.Value(routing.NextVar(first_node));                 // Пропускаем первый узел, так как это наша база.
                proposedRoute.RouteCost = routing.GetCost(first_node, second_node, route_number);

                while (!routing.IsEnd(second_node))
                {
                    var time_var = time_dimension.CumulVar(second_node);
                    var rPoint   = new ProposedRoutePoint(
                        TimeSpan.FromSeconds(solution.Min(time_var)),
                        TimeSpan.FromSeconds(solution.Max(time_var)),
                        Nodes[second_node - 1].Order
                        );
                    rPoint.DebugMaxMin = string.Format("\n({0},{1})[{3}-{4}]-{2}",
                                                       new DateTime().AddSeconds(solution.Min(time_var)).ToShortTimeString(),
                                                       new DateTime().AddSeconds(solution.Max(time_var)).ToShortTimeString(),
                                                       second_node,
                                                       rPoint.Order.DeliverySchedule.From.ToString("hh\\:mm"),
                                                       rPoint.Order.DeliverySchedule.To.ToString("hh\\:mm")
                                                       );
                    proposedRoute.Orders.Add(rPoint);

                    first_node               = second_node;
                    second_node              = solution.Value(routing.NextVar(first_node));
                    proposedRoute.RouteCost += routing.GetCost(first_node, second_node, route_number);
                }
            }

            PerformanceHelper.Main.PrintAllPoints(logger);

            if (distanceCalculator.ErrorWays.Count > 0)
            {
                logger.Debug("Ошибок получения расстояний {0}", distanceCalculator.ErrorWays.Count);
                var uniqueFrom = distanceCalculator.ErrorWays.Select(x => x.FromHash).Distinct().ToList();
                var uniqueTo   = distanceCalculator.ErrorWays.Select(x => x.ToHash).Distinct().ToList();
                logger.Debug("Уникальных точек: отправки = {0}, прибытия = {1}", uniqueFrom.Count, uniqueTo.Count);
                logger.Debug("Проблемные точки отправки:\n{0}",
                             string.Join("; ", distanceCalculator.ErrorWays
                                         .GroupBy(x => x.FromHash)
                                         .Where(x => x.Count() > (uniqueTo.Count / 2))
                                         .Select(x => CachedDistance.GetText(x.Key)))
                             );
                logger.Debug("Проблемные точки прибытия:\n{0}",
                             string.Join("; ", distanceCalculator.ErrorWays
                                         .GroupBy(x => x.ToHash)
                                         .Where(x => x.Count() > (uniqueFrom.Count / 2))
                                         .Select(x => CachedDistance.GetText(x.Key)))
                             );
            }
            distanceCalculator.Dispose();
            return(proposedRoute);
        }
Exemplo n.º 8
0
    public static void Main(String[] args)
    {
        // Instantiate the data problem.
        DataModel data = new DataModel();

        // Create Routing Index Manager
        RoutingIndexManager manager = new RoutingIndexManager(
            data.DistanceMatrix.GetLength(0),
            data.VehicleNumber,
            data.Depot);

        // Create Routing Model.
        RoutingModel routing = new RoutingModel(manager);

        // Create and register a transit callback.
        int transitCallbackIndex = routing.RegisterTransitCallback(
            (long fromIndex, long toIndex) =>
        {
            // Convert from routing variable Index to distance matrix NodeIndex.
            var fromNode = manager.IndexToNode(fromIndex);
            var toNode   = manager.IndexToNode(toIndex);
            return(data.DistanceMatrix[fromNode, toNode]);
        }
            );

        // Define cost of each arc.
        routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);

        // Add Distance constraint.
        routing.AddDimension(
            transitCallbackIndex,
            0,
            3000,
            true, // start cumul to zero
            "Distance");
        RoutingDimension distanceDimension = routing.GetMutableDimension("Distance");

        distanceDimension.SetGlobalSpanCostCoefficient(100);

        // Define Transportation Requests.
        Solver solver = routing.solver();

        for (int i = 0; i < data.PickupsDeliveries.GetLength(0); i++)
        {
            long pickupIndex   = manager.NodeToIndex(data.PickupsDeliveries[i][0]);
            long deliveryIndex = manager.NodeToIndex(data.PickupsDeliveries[i][1]);
            routing.AddPickupAndDelivery(pickupIndex, deliveryIndex);
            solver.Add(solver.MakeEquality(
                           routing.VehicleVar(pickupIndex),
                           routing.VehicleVar(deliveryIndex)));
            solver.Add(solver.MakeLessOrEqual(
                           distanceDimension.CumulVar(pickupIndex),
                           distanceDimension.CumulVar(deliveryIndex)));
        }

        // Setting first solution heuristic.
        RoutingSearchParameters searchParameters =
            operations_research_constraint_solver.DefaultRoutingSearchParameters();

        searchParameters.FirstSolutionStrategy =
            FirstSolutionStrategy.Types.Value.PathCheapestArc;

        // Solve the problem.
        Assignment solution = routing.SolveWithParameters(searchParameters);

        // Print solution on console.
        PrintSolution(data, routing, manager, solution);
    }
Exemplo n.º 9
0
    /// <summary>
    ///   Solves the current routing problem.
    /// </summary>
    private void Solve(int number_of_orders, int number_of_vehicles)
    {
        Console.WriteLine("Creating model with " + number_of_orders + " orders and " + number_of_vehicles +
                          " vehicles.");
        // Finalizing model
        int number_of_locations = locations_.Length;

        RoutingIndexManager manager =
            new RoutingIndexManager(number_of_locations, number_of_vehicles, vehicle_starts_, vehicle_ends_);
        RoutingModel model = new RoutingModel(manager);

        // Setting up dimensions
        const int big_number         = 100000;
        Manhattan manhattan_callback = new Manhattan(manager, locations_, 1);

        model.AddDimension(model.RegisterTransitCallback(manhattan_callback.Call), big_number, big_number, false,
                           "time");
        RoutingDimension time_dimension = model.GetDimensionOrDie("time");

        Demand demand_callback = new Demand(manager, order_demands_);

        model.AddDimension(model.RegisterUnaryTransitCallback(demand_callback.Call), 0, vehicle_capacity_, true,
                           "capacity");
        RoutingDimension capacity_dimension = model.GetDimensionOrDie("capacity");

        // Setting up vehicles
        Manhattan[] cost_callbacks = new Manhattan[number_of_vehicles];
        for (int vehicle = 0; vehicle < number_of_vehicles; ++vehicle)
        {
            int       cost_coefficient        = vehicle_cost_coefficients_[vehicle];
            Manhattan manhattan_cost_callback = new Manhattan(manager, locations_, cost_coefficient);
            cost_callbacks[vehicle] = manhattan_cost_callback;
            int manhattan_cost_index = model.RegisterTransitCallback(manhattan_cost_callback.Call);
            model.SetArcCostEvaluatorOfVehicle(manhattan_cost_index, vehicle);
            time_dimension.CumulVar(model.End(vehicle)).SetMax(vehicle_end_time_[vehicle]);
        }

        // Setting up orders
        for (int order = 0; order < number_of_orders; ++order)
        {
            time_dimension.CumulVar(order).SetRange(order_time_windows_[order].start_, order_time_windows_[order].end_);
            long[] orders = { manager.NodeToIndex(order) };
            model.AddDisjunction(orders, order_penalties_[order]);
        }

        // Solving
        RoutingSearchParameters search_parameters =
            operations_research_constraint_solver.DefaultRoutingSearchParameters();

        search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.AllUnperformed;

        Console.WriteLine("Search...");
        Assignment solution = model.SolveWithParameters(search_parameters);

        if (solution != null)
        {
            String output = "Total cost: " + solution.ObjectiveValue() + "\n";
            // Dropped orders
            String dropped = "";
            for (int order = 0; order < number_of_orders; ++order)
            {
                if (solution.Value(model.NextVar(order)) == order)
                {
                    dropped += " " + order;
                }
            }
            if (dropped.Length > 0)
            {
                output += "Dropped orders:" + dropped + "\n";
            }
            // Routes
            for (int vehicle = 0; vehicle < number_of_vehicles; ++vehicle)
            {
                String route = "Vehicle " + vehicle + ": ";
                long   order = model.Start(vehicle);
                if (model.IsEnd(solution.Value(model.NextVar(order))))
                {
                    route += "Empty";
                }
                else
                {
                    for (; !model.IsEnd(order); order = solution.Value(model.NextVar(order)))
                    {
                        IntVar local_load = capacity_dimension.CumulVar(order);
                        IntVar local_time = time_dimension.CumulVar(order);
                        route += order + " Load(" + solution.Value(local_load) + ") " + "Time(" +
                                 solution.Min(local_time) + ", " + solution.Max(local_time) + ") -> ";
                    }
                    IntVar load = capacity_dimension.CumulVar(order);
                    IntVar time = time_dimension.CumulVar(order);
                    route += order + " Load(" + solution.Value(load) + ") " + "Time(" + solution.Min(time) + ", " +
                             solution.Max(time) + ")";
                }
                output += route + "\n";
            }
            Console.WriteLine(output);
        }
    }
Exemplo n.º 10
0
        public void Init()
        {
            if (DataModel != null)
            {
                // Create RoutingModel Index RoutingIndexManager
                if (DataModel.Starts != null && DataModel.Ends != null)
                {
                    RoutingIndexManager = new RoutingIndexManager(
                        DataModel.TravelTimes.GetLength(0),
                        DataModel.VehicleCapacities.Length,
                        DataModel.Starts, DataModel.Ends);
                }
                else
                {
                    throw new Exception("Starts or Ends in DataModel is null");
                }

                //Create routing model
                RoutingModel = new RoutingModel(RoutingIndexManager);
                // Create and register a transit callback.
                var transitCallbackIndex = RoutingModel.RegisterTransitCallback(
                    (long fromIndex, long toIndex) =>
                {
                    // Convert from routing variable Index to time matrix or distance matrix NodeIndex.
                    var fromNode = RoutingIndexManager.IndexToNode(fromIndex);
                    var toNode   = RoutingIndexManager.IndexToNode(toIndex);
                    return(DataModel.TravelTimes[fromNode, toNode]);
                }
                    );

                //Create and register demand callback
                var demandCallbackIndex = RoutingModel.RegisterUnaryTransitCallback(
                    (long fromIndex) => {
                    // Convert from routing variable Index to demand NodeIndex.
                    var fromNode = RoutingIndexManager.IndexToNode(fromIndex);
                    return(DataModel.Demands[fromNode]);
                }
                    );

                if (DropNodesAllowed)
                {
                    // Allow to drop nodes.
                    //The penalty should be larger than the sum of all travel times locations (excluding the depot).
                    //As a result, after dropping one location to make the problem feasible, the solver won't drop any additional locations,
                    //because the penalty for doing so would exceed any further reduction in travel time.
                    //If we want to make as many deliveries as possible, penalty value should be larger than the sum of all travel times between locations
                    long penalty = 99999999;
                    for (int j = 0; j < DataModel.Starts.GetLength(0); j++)
                    {
                        var startIndex = DataModel.Starts[j];
                        for (int i = 0; i < DataModel.TravelTimes.GetLength(0); ++i)
                        {
                            if (startIndex != i)
                            {
                                RoutingModel.AddDisjunction(new long[] { RoutingIndexManager.NodeToIndex(i) }, penalty);//adds disjunction to all stop besides start stops
                            }
                        }
                    }
                }


                var vehicleCost = 10000;
                RoutingModel.SetFixedCostOfAllVehicles(vehicleCost);                 //adds a penalty for using each vehicle

                RoutingModel.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); //Sets the cost function of the model such that the cost of a segment of a route between node 'from' and 'to' is evaluator(from, to), whatever the route or vehicle performing the route.

                //Adds capacity constraints
                RoutingModel.AddDimensionWithVehicleCapacity(
                    demandCallbackIndex, 0,      // null capacity slack
                    DataModel.VehicleCapacities, // vehicle maximum capacities
                    false,                       // start cumul to zero
                    "Capacity");
                RoutingDimension capacityDimension = RoutingModel.GetMutableDimension("Capacity");

                //Add Time window constraints
                RoutingModel.AddDimension(
                    transitCallbackIndex,       // transit callback
                    86400,                      // allow waiting time (24 hours in seconds)
                    86400,                      // maximum travel time per vehicle (24 hours in seconds)
                    DataModel.ForceCumulToZero, // start cumul to zero
                    "Time");
                RoutingDimension timeDimension = RoutingModel.GetMutableDimension("Time");
                //timeDimension.SetGlobalSpanCostCoefficient(10);
                var solver = RoutingModel.solver();
                // Add time window constraints for each location except depot.
                for (int i = 0; i < DataModel.TimeWindows.GetLength(0); i++)
                {
                    long index = RoutingIndexManager.NodeToIndex(i); //gets the node index
                    if (index != -1)
                    {
                        var lowerBound     = DataModel.TimeWindows[i, 0];                      //minimum time to be at current index (lower bound for the timeWindow of current Index)
                        var softUpperBound = DataModel.TimeWindows[i, 1];                      //soft maxUpperBound for the timeWindow at current index
                        var upperBound     = softUpperBound + MaximumDeliveryDelayTime;        //maxUpperBound to be at current index (upperbound for the timeWindow at current index)
                        //softupperbound and upperbound are different because the upperbound is usually bigger than the softuppberbound in order to soften the current timeWindows, enabling to generate a solution that accomodates more requests
                        timeDimension.CumulVar(index).SetRange(lowerBound, upperBound);        //sets the maximum upper bound and lower bound limit for the timeWindow at the current index
                        timeDimension.SetCumulVarSoftUpperBound(index, softUpperBound, 10000); //adds soft upper bound limit which is the requested time window
                        RoutingModel.AddToAssignment(timeDimension.SlackVar(index));           //add timeDimension slack var for current index to the assignment
                        RoutingModel.AddToAssignment(timeDimension.TransitVar(index));         // add timeDimension transit var for current index to the assignment
                        RoutingModel.AddToAssignment(capacityDimension.TransitVar(index));     //add transit capacity var for current index to assignment
                    }
                }


                // Add time window constraints for each vehicle start node, and add to assignment the slack and transit vars for both dimensions
                for (int i = 0; i < DataModel.VehicleCapacities.Length; i++)
                {
                    long index           = RoutingModel.Start(i);
                    var  startDepotIndex = DataModel.Starts[i];
                    timeDimension.CumulVar(index).SetRange(DataModel.TimeWindows[startDepotIndex, 0], DataModel.TimeWindows[startDepotIndex, 1]); //this guarantees that a vehicle must visit the location during its time
                    RoutingModel.AddToAssignment(timeDimension.SlackVar(index));                                                                  //add timeDimension slack var for depot index for vehicle i depotto assignment
                    RoutingModel.AddToAssignment(timeDimension.TransitVar(index));                                                                //add timeDimension  transit var for depot index for vehicle i depot to assignment
                    RoutingModel.AddToAssignment(capacityDimension.TransitVar(index));                                                            //add capacityDimension transit var for vehicle i depot
                }

                //Add client max ride time constraint, enabling better service quality
                for (int i = 0; i < DataModel.PickupsDeliveries.Length; i++) //iterates over each pickupDelivery pair
                {
                    int vehicleIndex = -1;
                    if (DataModel.PickupsDeliveries[i][0] == -1)                                                                                                           //if the pickupDelivery is a customer inside a vehicle
                    {
                        vehicleIndex = DataModel.CustomersVehicle[i];                                                                                                      //gets the vehicle index
                    }
                    var pickupIndex            = vehicleIndex == -1 ? RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][0]):RoutingModel.Start(vehicleIndex); //if is a customer inside a vehicle the pickupIndex will be the vehicle startIndex, otherwise its the customers real pickupIndex
                    var deliveryIndex          = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][1]);
                    var rideTime               = DataModel.CustomersRideTimes[i];
                    var directRideTimeDuration = DataModel.TravelTimes[pickupIndex, DataModel.PickupsDeliveries[i][1]];
                    var realRideTimeDuration   = rideTime + (timeDimension.CumulVar(deliveryIndex) - timeDimension.CumulVar(pickupIndex)); //adds the currentRideTime of the customer and subtracts cumulative value of the ride time of the delivery index with the current one of the current index to get the real ride time duration
                    solver.Add(realRideTimeDuration < directRideTimeDuration + DataModel.MaxCustomerRideTime);                             //adds the constraint so that the current ride time duration does not exceed the directRideTimeDuration + maxCustomerRideTimeDuration
                }
                //Add precedence and same vehicle Constraints
                for (int i = 0; i < DataModel.PickupsDeliveries.GetLength(0); i++)
                {
                    if (DataModel.PickupsDeliveries[i][0] != -1)
                    {
                        long pickupIndex   = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][0]);                        //pickup index
                        long deliveryIndex = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[i][1]);                        //delivery index
                        RoutingModel.AddPickupAndDelivery(pickupIndex, deliveryIndex);                                                  //Notifies that the pickupIndex and deliveryIndex form a pair of nodes which should belong to the same route.
                        solver.Add(solver.MakeEquality(RoutingModel.VehicleVar(pickupIndex), RoutingModel.VehicleVar(deliveryIndex)));  //Adds a constraint to the solver, that defines that both these pickup and delivery pairs must be picked up and delivered by the same vehicle (same route)
                        solver.Add(solver.MakeLessOrEqual(timeDimension.CumulVar(pickupIndex), timeDimension.CumulVar(deliveryIndex))); //Adds the precedence constraint to the solver, which defines that each item must be picked up at pickup index before it is delivered to the delivery index
                        //timeDimension.SlackVar(pickupIndex).SetMin(4);//mininimum slack will be 3 seconds (customer enter timer)
                        //timeDimension.SlackVar(deliveryIndex).SetMin(3); //minimum slack will be 3 seconds (customer leave time)
                    }
                }
                //Constraints to enforce that if there is a customer inside a vehicle, it has to be served by that vehicle
                for (int customerIndex = 0; customerIndex < DataModel.CustomersVehicle.GetLength(0); customerIndex++)
                {
                    var vehicleIndex = DataModel.CustomersVehicle[customerIndex];
                    if (vehicleIndex != -1)                                                                                                  //if the current customer is inside a vehicle
                    {
                        var vehicleStartIndex = RoutingModel.Start(vehicleIndex);                                                            //vehicle start depot index
                        var deliveryIndex     = RoutingIndexManager.NodeToIndex(DataModel.PickupsDeliveries[customerIndex][1]);              //gets the deliveryIndex
                        solver.Add(solver.MakeEquality(RoutingModel.VehicleVar(vehicleStartIndex), RoutingModel.VehicleVar(deliveryIndex))); //vehicle with vehicleIndex has to be the one that delivers customer with nodeDeliveryIndex;
                        //this constraint enforces that the vehicle indexed by vehicleIndex has to be the vehicle which services (goes to) the nodeDeliveryIndex as well
                    }
                }

                for (int i = 0; i < DataModel.VehicleCapacities.Length; i++)
                {
                    RoutingModel.AddVariableMinimizedByFinalizer(
                        timeDimension.CumulVar(RoutingModel.Start(i)));
                    RoutingModel.AddVariableMinimizedByFinalizer(
                        timeDimension.CumulVar(RoutingModel.End(i)));
                }
            }
        }
        /// <summary>
        /// requires data.SantaIds
        /// requires data.Visits
        /// requires data.HomeIndex
        /// requires data.Unavailable
        /// requires data.Start
        /// requires data.End
        /// </summary>
        public static OptimizationResult Solve(RoutingData data, long timeLimitMilliseconds, ITimeWindowStrategy strategy)
        {
            if (false ||
                data.SantaIds == null ||
                data.Visits == null ||
                data.Unavailable == null ||
                data.SantaStartIndex == null ||
                data.SantaEndIndex == null
                )
            {
                throw new ArgumentNullException();
            }

            var model = new RoutingModel(data.Visits.Length, data.SantaIds.Length, data.SantaStartIndex, data.SantaEndIndex);

            // setting up dimensions
            var maxTime      = GetMaxTime(data);
            var timeCallback = new TimeEvaluator(data);

            model.AddDimension(timeCallback, 0, maxTime, false, DimensionTime);
            var lengthCallback = new TimeEvaluator(data);

            model.AddDimension(lengthCallback, 0, maxTime, true, DimensionLength);

            // set additional cost of longest day
            {
                var dim = model.GetDimensionOrDie(DimensionLength);
                dim.SetGlobalSpanCostCoefficient(data.Cost.CostLongestDayPerHour);
            }

            // dimensions for breaks
            var breakCallbacks  = new List <BreakEvaluator>();
            var breakDimensions = new List <string>();

            for (int santa = 0; santa < data.NumberOfSantas; santa++)
            {
                var maxBreaks = GetNumberOfBreaks(data, santa);
                if (maxBreaks == 0)
                {
                    // no breaks
                    continue;
                }

                var evaluator = new BreakEvaluator(data, santa);
                var dimension = GetSantaBreakDimension(santa);
                model.AddDimension(evaluator, 0, maxBreaks, true, dimension);
                breakCallbacks.Add(evaluator);
                breakDimensions.Add(dimension);
            }

            // setting up santas (=vehicles)
            var costCallbacks = new NodeEvaluator2[data.NumberOfSantas];

            for (int santa = 0; santa < data.NumberOfSantas; santa++)
            {
                // must be a new instance per santa
                NodeEvaluator2 costCallback = data.Input.IsAdditionalSanta(data.SantaIds[santa])
                    ? new CostEvaluator(data, data.Cost.CostWorkPerHour + data.Cost.CostAdditionalSantaPerHour, data.Cost.CostAdditionalSanta)
                    : new CostEvaluator(data, data.Cost.CostWorkPerHour, 0);
                costCallbacks[santa] = costCallback;
                model.SetVehicleCost(santa, costCallback);

                // limit time per santa
                var day   = data.GetDayFromSanta(santa);
                var start = GetDayStart(data, day);
                var end   = GetDayEnd(data, day);
                model.CumulVar(model.End(santa), DimensionTime).SetRange(start, end);
                model.CumulVar(model.Start(santa), DimensionTime).SetRange(start, end);

                // avoid visiting breaks of other santas
                var breakDimension = GetSantaBreakDimension(santa);
                foreach (var dimension in breakDimensions.Except(new[] { breakDimension }))
                {
                    model.CumulVar(model.End(santa), dimension).SetMax(0);
                }
            }

            // setting up visits (=orders)
            for (int visit = 0; visit < data.NumberOfVisits; ++visit)
            {
                var cumulTimeVar = model.CumulVar(visit, DimensionTime);
                cumulTimeVar.SetRange(data.OverallStart, data.OverallEnd);
                model.AddDisjunction(new[] { visit }, data.Cost.CostNotVisitedVisit);

                // add desired / unavailable according to strategy
                var timeDimension = model.GetDimensionOrDie(DimensionTime);
                strategy.AddConstraints(data, model, cumulTimeVar, timeDimension, visit);
            }

            // Solving
            var searchParameters = RoutingModel.DefaultSearchParameters();

            searchParameters.FirstSolutionStrategy    = FirstSolutionStrategy.Types.Value.Automatic; // maybe try AllUnperformed or PathCheapestArc
            searchParameters.LocalSearchMetaheuristic = LocalSearchMetaheuristic.Types.Value.GuidedLocalSearch;
            searchParameters.TimeLimitMs = timeLimitMilliseconds;

            var solution = model.SolveWithParameters(searchParameters);

            // protect callbacks from the GC
            GC.KeepAlive(timeCallback);
            GC.KeepAlive(lengthCallback);
            foreach (var costCallback in costCallbacks)
            {
                GC.KeepAlive(costCallback);
            }
            foreach (var breakCallback in breakCallbacks)
            {
                GC.KeepAlive(breakCallback);
            }

            Debug.WriteLine($"obj={solution?.ObjectiveValue()}");

            return(CreateResult(data, model, solution));
        }
Exemplo n.º 12
0
        private static void VRP(int[,] locations, int[] demands, int num_vehicles)
        {
            int num_locations = locations.GetLength(0);
            int depot         = 0; // The depot is the start and end point of each route.


            // Create routing model
            if (locations.Length > 0)
            {
                RoutingModel routing           = new RoutingModel(num_locations, num_vehicles, depot);
                var          search_parameters = RoutingModel.DefaultSearchParameters();

                // Setting first solution heuristic: the
                // method for finding a first solution to the problem.
                search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;

                var distanceCallback = new DistanceLocationsCallback(locations);

                //  Display(distanceCallback.matrix);


                routing.SetArcCostEvaluatorOfAllVehicles(distanceCallback);


                //  Add a dimension for demand.

                long   slack_max               = 0;
                long   vehicle_capacity        = 100;
                bool   fix_start_cumul_to_zero = true;
                string demand = "Demand";

                routing.AddDimension(new DemandCallback(demands), slack_max, vehicle_capacity, fix_start_cumul_to_zero, demand);

                // Solve, displays a solution if any.
                var assignment = routing.SolveWithParameters(search_parameters);


                Console.WriteLine("Status = {0}", routing.Status());

                if (assignment != null)
                {
                    // Solution cost.
                    Console.WriteLine("Total distance of all routes: {0}", assignment.ObjectiveValue());
                    // Inspect solution.

                    // Only one route here; otherwise iterate from 0 to routing.vehicles() - 1

                    for (int vehicle_nbr = 0; vehicle_nbr < num_vehicles; vehicle_nbr++)
                    {
                        long   index        = routing.Start(vehicle_nbr);
                        long   index_next   = assignment.Value(routing.NextVar(index));
                        string route        = string.Empty;
                        long   route_dist   = 0;
                        long   route_demand = 0;

                        int node_index;
                        int node_index_next;

                        while (!routing.IsEnd(index_next))
                        {
                            // Convert variable indices to node indices in the displayed route.

                            node_index      = routing.IndexToNode(index);
                            node_index_next = routing.IndexToNode(index_next);

                            route += node_index + " -> ";

                            // Add the distance to the next node.

                            route_dist += distanceCallback.Run(node_index, node_index_next);
                            // # Add demand.
                            route_demand += demands[node_index_next];
                            index         = index_next;
                            index_next    = assignment.Value(routing.NextVar(index));
                        }

                        node_index      = routing.IndexToNode(index);
                        node_index_next = routing.IndexToNode(index_next);
                        route          += node_index + " -> " + node_index_next;
                        route_dist     += distanceCallback.Run(node_index, node_index_next);

                        Console.WriteLine("Route for vehicle " + vehicle_nbr + ":\n\n" + route + "\n");
                        Console.WriteLine("Distance of route " + vehicle_nbr + ": " + route_dist);
                        Console.WriteLine("Demand met by vehicle " + vehicle_nbr + ": " + route_demand + "\n");

                        // Console.WriteLine($"Route: {route}");
                    }
                }
                else
                {
                    Console.WriteLine("No solution found.");
                }
            }
        }
Exemplo n.º 13
0
        //IntVar x;
        //IntVar y;//Reduntant

        public void SolveVrpProblem(Day day, ConfigParams cfg, VrpProblem vrpProblem, IDataOutput dataOutput, int[] VCMinMax)
        {
            this.day = day;
            this.cfg = cfg;
            //Google Distance Matrix API (Duration matrix)


            // Create Routing Index Manager
            manager = new RoutingIndexManager(
                day.TimeMatrix.GetLength(0),
                day.Vehicles.Count,
                day.Depot);


            // Create Routing Model.
            routing = new RoutingModel(manager);

            // Create and register a transit callback.
            int transitCallbackIndex = routing.RegisterTransitCallback(
                (long fromIndex, long toIndex) =>
            {
                // Convert from routing variable Index to distance matrix NodeIndex.
                var fromNode = manager.IndexToNode(fromIndex);
                var toNode   = manager.IndexToNode(toIndex);
                return(day.TimeMatrix[fromNode, toNode]);
            }
                );

            // Define cost of each arc.
            routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);

            // Add Distance constraint.

            if (day.TimeWindowsActive != true)
            {
                routing.AddDimension(transitCallbackIndex, 0, 700000,
                                     true, // start cumul to zero
                                     "Distance");
                RoutingDimension distanceDimension = routing.GetMutableDimension("Distance");
                distanceDimension.SetGlobalSpanCostCoefficient(100);
            }
            else
            {
                routing.AddDimension(
                    transitCallbackIndex, // transit callback
                    1000,                 // allow waiting time
                    600,                  // vehicle maximum capacities
                    false,                // start cumul to zero
                    "Time");

                TimeWindowInit(day, routing, manager);//Set Time Window Constraints
            }
            if (day.MaxVisitsActive != 0)
            {
                int demandCallbackIndex = routing.RegisterUnaryTransitCallback(
                    (long fromIndex) => {
                    // Convert from routing variable Index to demand NodeIndex.
                    var fromNode = manager.IndexToNode(fromIndex);
                    return(day.Demands[fromNode]);
                }
                    );

                routing.AddDimensionWithVehicleCapacity(
                    demandCallbackIndex, 0,  // null capacity slack
                    day.VehicleCapacities,   // vehicle maximum capacities
                    true,                    // start cumul to zero
                    "Capacity");
            }

            // Allow to drop nodes.
            for (int i = 1; i < day.TimeMatrix.GetLength(0); ++i)
            {
                routing.AddDisjunction(
                    new long[] { manager.NodeToIndex(i) }, day.Locations.ElementAt(i).Penalty);
            }

            // Setting first solution heuristic.
            RoutingSearchParameters searchParameters =
                operations_research_constraint_solver.DefaultRoutingSearchParameters();


            searchParameters.FirstSolutionStrategy =
                FirstSolutionStrategy.Types.Value.PathMostConstrainedArc;

            //metaheuristic
            searchParameters.LocalSearchMetaheuristic = LocalSearchMetaheuristic.Types.Value.GuidedLocalSearch;
            searchParameters.TimeLimit = new Duration {
                Seconds = cfg.SolutionDuration
            };
            searchParameters.LogSearch = true;

            solver = routing.solver();

            //TODO
            //Some location must be on same route.
            //solver.Add(routing.VehicleVar(manager.NodeToIndex(2)) == routing.VehicleVar(manager.NodeToIndex(5)));
            //One node takes precedence over the another.
            //routing.AddPickupAndDelivery(manager.NodeToIndex(2), manager.NodeToIndex(5));

            //Constraint variable
            //x = solver.MakeIntVar(day.Vehicles.Count, day.Vehicles.Count, "x");

            //Number of vehicle restriction - old version
            //solver.Add(x < 7);

            //Number of vehicle restriction -new version
            //y = solver.MakeIntVar(routing.Vehicles(), routing.Vehicles(), "y");
            //solver.Add(y <= VCMinMax[1]);//Reduntant

            // Solve the problem.
            solution = routing.SolveWithParameters(searchParameters);



            day.LocationDropped = false;

            // Display dropped nodes.
            List <int> droppedNodes = new List <int>();

            for (int index = 0; index < routing.Size(); ++index)
            {
                if (routing.IsStart(index) || routing.IsEnd(index))
                {
                    continue;
                }
                if (solution.Value(routing.NextVar(index)) == index)
                {
                    droppedNodes.Add(manager.IndexToNode((int)index));
                    day.LocationDropped = true;
                }
            }
            day.DroppedLocations.Clear();
            Console.WriteLine(day.Locations.ElementAt(0).Name);
            if (droppedNodes != null)
            {
                foreach (var item in droppedNodes)
                {
                    Location location = LocationDB.Locations.Where(x => x.Position.strPos_ == day.Addresses[item]).ToList().ElementAt(0);

                    if (location != null)
                    {
                        Console.WriteLine(location.Name);
                        day.DroppedLocations.Add(location);
                    }
                }
            }
            List <int> AssignedNodes = new List <int>();

            Console.WriteLine(manager.GetNumberOfNodes());


            //Inspect Infeasable Nodes
            for (int i = 0; i < day.Vehicles.Count; i++)
            {
                var index = routing.Start(i);
                int j     = 0;
                while (routing.IsEnd(index) == false)
                {
                    j++;

                    index = solution.Value(routing.NextVar(index));
                }
                if (j == 1)
                {
                    day.InfeasibleNodes = true;
                    foreach (var item in day.DroppedLocations)
                    {
                        LocationDB.Locations.Where(x => x.ClientRef == item.ClientRef).ToList().ElementAt(0).Infeasible = true;
                    }
                    if (day.Vehicles.Count - 1 >= 1)
                    {
                        day.SetVehicleNumber(day.Vehicles.Count - 1);
                        day.ResetResults();

                        vrpProblem.SolveVrpProblem(day, cfg, vrpProblem, dataOutput, VCMinMax);
                    }
                    return;
                }
            }

            // Inspect solution.
            day.TotalDur = 0;
            day.MinDur   = 100000;
            for (int i = 0; i < day.Vehicles.Count; i++)
            {
                long routeDuration = 0;

                var index = routing.Start(i);

                while (routing.IsEnd(index) == false)
                {
                    var previousIndex = index;

                    index = solution.Value(routing.NextVar(index));

                    routeDuration += routing.GetArcCostForVehicle(previousIndex, index, 0);
                }
                day.TotalDur += routeDuration;
                day.MaxDur    = Math.Max(routeDuration, day.MaxDur);
                day.MinDur    = Math.Min(routeDuration, day.MinDur);
            }
            day.AvgDur = day.TotalDur / day.Vehicles.Count;
        }
Exemplo n.º 14
0
        protected RoutingModel ComposeRoutingModel(out List <int> failedNodes)
        {
            failedNodes = new List <int>();
            int numberOfSites = Data.GetTimeMatrix().GetLength(0);

            // Create Routing Model.
            // [START routing_model]
            RoutingModel routing = new RoutingModel(manager);
            // [END routing_model]

            // Define cost of each arc.
            // [START arc_cost]


            int transitCallbackIndex = routing.RegisterTransitCallback(timeCallback);

            routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
            // [END arc_cost]

            // Add Distance constraint.
            // [START time_constraint]
            // Documentation at: https://github.com/google/or-tools/blob/3494afff17d3dc60daf5ebe6ff2ab4cbc7777163/ortools/constraint_solver/routing.h#L383
            routing.AddDimension(
                transitCallbackIndex,            // transit callback
                Data.getAllowWaitingTime(),      // allow waiting time
                Data.getMaximumWorkerCapacity(), // vehicle maximum capacities
                false,                           // start cumul to zero
                "Time");
            RoutingDimension timeDimension = routing.GetMutableDimension("Time");

            // Add time window constraints for each location except depot
            // and 'copy' the slack var in the solution object (aka Assignment) to print it
            for (int i = 1; i < Data.GetTimeWindows().GetLength(0); ++i)
            {
                try
                {
                    long index = manager.NodeToIndex(i);
                    // TODO: To be replaced to allow mulible shifts similar to:
                    // https://gist.github.com/Muhammad-Altabba/5e52cc1aee98e88f11a01181341f630e#file-vrpsolver-py-L121
                    timeDimension.CumulVar(index).SetRange(
                        Data.GetTimeWindows()[i, 0],
                        Data.GetTimeWindows()[i, 1]);
                    routing.AddToAssignment(timeDimension.SlackVar(index));
                }
                catch (System.ApplicationException ex)
                {
                    //Possible cases: The site cannot be visited during the attendance time of the worker.
                    // Or the starting time is after the end time...
                    // Most likely a problem in timing for this node..
                    failedNodes.Add(i);
                    Console.WriteLine("(Note: " + ex.Message + " to add for node " + i + ". Could be because the site cannot be visited during the attendance time of the workers. Or there is a time inconsistency for this node.)");
                }
            }
            // Add time window constraints for each vehicle start node
            // and 'copy' the slack var in the solution object (aka Assignment) to print
            // it
            for (int i = 0; i < Data.GetVehicleNumber(); ++i)
            {
                long index = routing.Start(i);
                timeDimension.CumulVar(index).SetRange(
                    Data.GetTimeWindows()[0, 0],
                    Data.GetTimeWindows()[0, 1]);
                routing.AddToAssignment(timeDimension.SlackVar(index));
            }
            // [END time_constraint]

            for (int i = 0; i < numberOfSites; i++)
            {
                CpInt64Vector v = new CpInt64Vector();
                v.Add(manager.NodeToIndex(i));
                routing.AddDisjunction(v, Data.GetDemands()[i]);
            }
            return(routing);
        }
Exemplo n.º 15
0
        public static void Solve(int vehicles, int capacity, Distance distances, Demands demands)
        {
            /*
             * Generate constraint model
             */

            // Third argument defines depot, i.e. start-end node for round trip.
            var model = new RoutingModel(distances.MapSize(), vehicles, 0);

            // Node costs vs. Arc Costs
            model.SetArcCostEvaluatorOfAllVehicles(distances);

            /*
             * Capacity Constraints
             */

            if (distances.MapSize() != demands.MapSize())
            {
                throw new ArgumentException("Define demand for each city.");
            }

            model.AddDimension(demands, 0, capacity, true, "capacity");

            /*
             * Solve problem and display solution
             */

            Assignment assignment = model.Solve();

            if (assignment != null)
            {
                Console.WriteLine("Depot: " + model.GetDepot());
                Console.WriteLine("Total Distance: " + assignment.ObjectiveValue() + "\n");

                for (int i = 0; i < vehicles; i++)
                {
                    /*
                     * Display Trips:
                     */

                    Console.WriteLine("Round Trip for Vehicle " + i + ":");

                    long total  = 0;
                    var  source = model.Start(i);

                    while (!model.IsEnd(source))
                    {
                        var s = model.IndexToNode(source);
                        var t = model.IndexToNode(model.Next(assignment, source));

                        total += distances.Run(s, t);

                        Console.WriteLine(String.Format(" - From {0,-2} (demand: {1,-1}) travel to {2,-2} (demand: {3,-1}) with distance: {4,-2}",
                                                        distances.ToString(s),
                                                        demands.Demand(s),
                                                        distances.ToString(t),
                                                        demands.Demand(t),
                                                        distances.Run(s, t)));
                        source = model.Next(assignment, source);
                    }

                    Console.WriteLine("Total Distance for Vehicle " + i + ": " + total + "\n");
                }
            }

            Console.ReadKey();
        }