Проблема маршрутизации транспортных средств в Google или-Tools — решение равно нулю

#c# #or-tools

#c# #или-tools

Вопрос:

Я не могу понять, почему объект solution всегда равен null. Я пытаюсь изменить пример C # для проблемы маршрутизации транспортных средств Google ИЛИ-Tools. В примере используются местоположения, и я пытаюсь использовать матрицу расстояний. Мой код очень похож на пример Python, поэтому он должен работать. Проблема, похоже, заключается в методе AddDistanceDimension.

 using System;
using System.Collections.Generic;
using System.Text;
using Google.OrTools.ConstraintSolver;

namespace ConsoleApp1
{
    /// <summary>
    ///   This is a sample using the routing library .Net wrapper to solve a VRP problem.
    ///   A description of the problem can be found here:
    ///   http://en.wikipedia.org/wiki/Vehicle_routing_problem.
    /// </summary>
    class Program3
    {
        public class DataProblem
        {
            private int[,] distances_;

            // Constructor:
            public DataProblem()
            {
                distances_ = new int[,] {
                            { 0, 6177, 17282, 7866, 25029, 4511, 6120}, 
                            { 8469, 0, 9517, 1018, 17264, 6101, 615}, 
                            { 17504, 9865, 0, 10445, 9319, 15136, 10464}, 
                            { 7533, 1315, 9699, 0, 17446, 5165, 534}, 
                            { 25351, 17712, 10199, 18291, 0, 22983, 18310}, 
                            { 4993, 5221, 16381, 4620, 24128, 0, 4516}, 
                            { 5969, 958, 10309, 762, 18056, 4538, 0}
                    };
             }

            public int GetVehicleNumber() { return 4; }
            public ref readonly int[,] GetLocations() { return ref distances_; }
            public int GetLocationNumber() { return distances_.GetLength(0); }
            public int GetDepot() { return 0; }
        };


        public class DistanceMatrix : NodeEvaluator2
        {
            private int[,] distances;

            public DistanceMatrix(in DataProblem data)
            {
                distances = data.GetLocations();
            }

            public override long Run(int FromNode, int ToNode)
            {
                return distances[FromNode, ToNode];
            }
        };

        /// <summary>
        ///   Add distance Dimension
        /// </summary>
        static void AddDistanceDimension(in DataProblem data, in RoutingModel routing)
        {
            // public bool AddDimension(NodeEvaluator2 evaluator, long slack_max, long capacity, bool fix_start_cumul_to_zero, string name);
            // Returns false if a dimension with the same name has already been created (and doesn't create the new dimension).
            bool bResult = routing.AddDimension(
                new DistanceMatrix(data),
                0,  // null slack
                7000, // maximum distance per vehicle
                true, // start cumul to zero
                "Distance");
            Console.WriteLine("Was dimension dreated? "   bResult);
            RoutingDimension distanceDimension = routing.GetDimensionOrDie("Distance");
            // Try to minimize the max distance among vehicles.
            // /! It doesn't mean the standard deviation is minimized
            distanceDimension.SetGlobalSpanCostCoefficient(100);
        }

        /// <summary>
        ///   Print the solution
        /// </summary>
        static void PrintSolution(
            in DataProblem data,
            in RoutingModel routing,
            in Assignment solution)
        {
            Console.WriteLine("Objective: {0}", solution.ObjectiveValue());
            // Inspect solution.
            for (int i = 0; i < data.GetVehicleNumber();   i)
            {
                Console.WriteLine("Route for Vehicle "   i   ":");
                long distance = 0;
                var index = routing.Start(i);
                while (routing.IsEnd(index) == false)
                {
                    Console.Write("{0} -> ", routing.IndexToNode(index));
                    var previousIndex = index;
                    index = solution.Value(routing.NextVar(index));
                    distance  = routing.GetArcCostForVehicle(previousIndex, index, i);
                }
                Console.WriteLine("{0}", routing.IndexToNode(index));
                Console.WriteLine("Distance of the route: {0}m", distance);
            }
            Console.ReadLine();
        }

        /// <summary>
        ///   Solves the current routing problem.
        /// </summary>
        static void Solve()
        {
            // Instantiate the data problem.
            DataProblem data = new DataProblem();

            // Create Routing Model
            RoutingModel routing = new RoutingModel(
                data.GetLocationNumber(),
                data.GetVehicleNumber(),
                data.GetDepot());

            // Debugging 
            Console.WriteLine("Number of locations: {0}", data.GetLocationNumber());
            Console.WriteLine("Number of vehicles: {0}", data.GetVehicleNumber());
            Console.WriteLine("Get depot: {0}", data.GetDepot());

            // Define weight cost of each edge
            NodeEvaluator2 distanceEvaluator = new DistanceMatrix(data);
            //protect callbacks from the GC
            GC.KeepAlive(distanceEvaluator);
            routing.SetArcCostEvaluatorOfAllVehicles(distanceEvaluator);
            AddDistanceDimension(data, routing);

            // Setting first solution heuristic (cheapest addition).
            RoutingSearchParameters searchParameters = RoutingModel.DefaultSearchParameters();
            searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;

            Assignment solution = routing.SolveWithParameters(searchParameters);
            PrintSolution(data, routing, solution);
        }

        public static void Main(String[] args)
        {
            Solve();
        }
    }
}
  

Комментарии:

1. ваш GC.KeepAlive(distanceEvaluator); должен быть ПОСЛЕ SolveWithParameter() , чтобы сохранить объект живым до тех пор, пока он не появится.

2. ваша матрица должна быть длинной[,] обратный вызов должен возвращать значение long …

3. На master у нас есть пример с матрицей расстояний, см. github.com/google/or-tools/blob/master/ortools /…

4. Спасибо Mizux. Ваши предложения помогли мне решить проблему. Я смог получить ожидаемое решение. Это соответствует моим выводам на Python.

Ответ №1:

Когда вы создаете свой, DistanceDimension вы устанавливаете horizon равным 7000 , в то время как ваша матрица содержит 25000, 10000 и т.д…

Вы уверены, что ваши данные верны? Попробуйте увеличить горизонт (7000)…