Ejemplo n.º 1
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);
        }
    }
        /// <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));
        }