/// <summary> /// Tries to Solve the <paramref name="context"/> <see cref="RoutingContext.Model"/> /// given <paramref name="searchParams"/>. Receives the <paramref name="solution"/> /// prior to response. /// </summary> /// <param name="context">The Context whose Model is being Solved. Assumes that the /// <see cref="Visitors"/> have all been applied and any <see cref="Context"/> mutations /// that were going to occur have all occurred. So, should be safe now to add dimensions /// to the <see cref="RoutingContext.Model"/>.</param> /// <param name="searchParams">The SearchParameters influencing the /// solution.</param> /// <param name="solution">Receives the Solution on response.</param> /// <returns>Whether a <paramref name="solution"/> was properly received.</returns> protected virtual bool TrySolve(TContext context, RoutingSearchParameters searchParams, out Assignment solution) { this.AddDimensions(context); var model = context.Model; solution = null; try { // TODO: TBD: is there a way to probe for status during and/or before/after the search itself? solution = searchParams == null ? model.Solve() : model.SolveWithParameters(searchParams); /* TODO: TBD: we can capture "debug" output from the solver, * but as far as we can determine this requires/assumes there * was a solution obtained from the solver in the first place. * When solution is null, then what? */ } catch //(Exception ex) { // TODO: TBD: potentially log any exceptions... } return(solution != null); }
public Assignment TryGetSolution(RoutingSearchParameters searchParameters) { Assignment solution = null; if (searchParameters == null) { searchParameters = GetDefaultSearchParameters(); } //for loop that tries to find the earliest feasible solution (trying to minimize the maximum upper bound) within a maximum delay delivery time (upper bound), using the current customer requests for (int currentMaximumDelayTime = 0; currentMaximumDelayTime < DataModel.MaxAllowedDeliveryDelayTime; currentMaximumDelayTime = currentMaximumDelayTime + 60) //iterates adding 1 minute to maximum allowed timeWindow (60 seconds) if a feasible solution isnt found for the current upperbound { MaximumDeliveryDelayTime = currentMaximumDelayTime; Init(); //Get the solution of the problem try { solution = RoutingModel.SolveWithParameters(searchParameters); } catch (Exception) { solution = null; } if (solution != null) //if true, solution was found, breaks the cycle { break; } } Console.WriteLine("Solver status:" + GetSolverStatus()); return(solution); //retuns null if no solution is found, otherwise returns the solution }
/// <summary> /// Invokes the <see cref="ConfigureSearchParameters"/>. /// </summary> /// <param name="searchParams"></param> protected virtual void OnConfigureSearchParameters(ref RoutingSearchParameters searchParams) { var args = new RoutingSearchParametersEventArgs(searchParams); this.ConfigureSearchParameters?.Invoke(this, args); searchParams = args.Parameters; }
public void TestTransitMatrix() { // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager(5 /*locations*/, 1 /*vehicle*/, 0 /*depot*/); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); // Create a distance callback. long[][] matrix = new long[][] { new long[] { 1, 1, 1, 1, 1 }, new long[] { 1, 1, 1, 1, 1 }, new long[] { 1, 1, 1, 1, 1 }, new long[] { 1, 1, 1, 1, 1 }, new long[] { 1, 1, 1, 1, 1 }, }; int transitCallbackIndex = routing.RegisterTransitMatrix(matrix); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; Assignment solution = routing.SolveWithParameters(searchParameters); // 0 --(+1)-> 1 --(+1)-> 2 --(+1)-> 3 --(+1)-> 4 --(+1)-> 0 := +5 Assert.Equal(5, solution.ObjectiveValue()); }
private RoutingSearchParameters CreateSearchParameters() { RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; return(searchParameters); }
public void TestVectorDimension() { // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager(5 /*locations*/, 1 /*vehicle*/, 0 /*depot*/); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); // Create a distance callback. long[] vector = new long[] { 1, 1, 1, 1, 1 }; IntBoolPair result = routing.AddVectorDimension( vector, /*capacity=*/ 10, /*fix_start_cumul_to_zero=*/ true, "Dimension"); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(result.first); // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; Assignment solution = routing.SolveWithParameters(searchParameters); // 0 --(+1)-> 1 --(+1)-> 2 --(+1)-> 3 --(+1)-> 4 --(+1)-> 0 := +5 Assert.Equal(5, solution.ObjectiveValue()); }
public void SimpleLambdaCallback(bool callGC) { // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager( 5 /*locations*/, 1 /*vehicle*/, 0 /*depot*/); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); // Create a distance 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(Math.Abs(toNode - fromNode)); }); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); if (callGC) { GC.Collect(); } // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; Assignment solution = routing.SolveWithParameters(searchParameters); // 0 --(+1)-> 1 --(+1)-> 2 --(+1)-> 3 --(+1)-> 4 --(+4)-> 0 := +8 Assert.Equal(8, solution.ObjectiveValue()); }
private void SortUpdate() { var t0 = Stopwatch.GetTimestamp(); try { if (this.rdoNoSort.Checked) { this.Log("==== No Sort ===="); this.NoSort(); } else if (this.rdoNearestNeighbor.Checked) { this.Log("==== Nearest Neighbor ===="); this.SortNearestNeighbor(); } else if (this.rdo2Opt.Checked) { this.Log("==== 2-OPT ===="); this.NoSort(); this.Improve2Opt(); } else if (this.rdo2OptNative.Checked) { this.Log("==== 2-OPT ===="); this.NoSort(); AlgDll.Improve2Opt(this.visitOrder, this.visitOrder.Length, this.distTable); } else if (this.rdoNearestNeighbor2Opt.Checked) { this.Log("==== Nearest Neighbor + 2-OPT===="); this.SortNearestNeighbor(); this.Improve2Opt(); } else if (this.rdoNearestNeighbor2OptNative.Checked) { this.Log("==== Nearest Neighbor + 2-OPT===="); this.SortNearestNeighbor(); AlgDll.Improve2Opt(this.visitOrder, this.visitOrder.Length, this.distTable); } else if (this.rdoGoogleRoute.Checked) { string msg = string.Format("==== Google Route ===="); this.Log(msg); RoutingSearchParameters srcPrms = (RoutingSearchParameters)this.grdPrm.SelectedObject; this.SortGoogleRoute(srcPrms); } } catch (Exception ex) { this.visitOrder = new int[0]; this.Log(ex.ToString()); } var ms = (Stopwatch.GetTimestamp() - t0) / (double)Stopwatch.Frequency * 1000; float calcDist = CalcRouteDist(this.visitOrder); this.Log(string.Format("Route Dist : {0}", calcDist)); this.Log(string.Format("Calc Time : {0}ms", ms)); this.pbxDraw.Invalidate(); }
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"); } }
public FormMain() { InitializeComponent(); RoutingSearchParameters srcPrms = operations_research_constraint_solver.DefaultRoutingSearchParameters(); this.grdPrm.SelectedObject = srcPrms; this.pbxDraw.ZoomToRect(0, 0, bw, bh); }
void TimeLimits() { RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.TimeLimit = new Duration { Seconds = 10 }; }
public RoutingDataModel CreateInitialSimulationDataModel(bool allowDropNodes, Simulation.Simulation simulation) { var numberCustomers = simulation.Params.NumberInitialRequests; var numberVehicles = simulation.Params.VehicleNumber; Console.WriteLine(this.ToString() + "Creating new random DataModel for " + numberVehicles + " Vehicles and " + numberCustomers + " Customers, AllowDropNodes: " + allowDropNodes); GenerateNewDataModelLabel: List <Vehicle> dataModelVehicles = new List <Vehicle>(); List <long> startDepotsArrivalTime = new List <long>(numberVehicles); //Creates two available vehicles to be able to perform flexible routing for the pdtwdatamodel for (int i = 0; i < numberVehicles; i++) { var vehicle = new Vehicle(simulation.Params.VehicleSpeed, simulation.Params.VehicleCapacity, simulation.Context.Depot, simulation.Context.Depot); dataModelVehicles.Add(vehicle); startDepotsArrivalTime.Add(0);//startDepotArrival time = 0 for all the vehicles } var customersToBeServed = new List <Customer>(); List <Stop> excludedStops = new List <Stop>(); foreach (var vehicle in dataModelVehicles) { if (!excludedStops.Contains(vehicle.StartStop)) { excludedStops.Add(vehicle.StartStop); } if (!excludedStops.Contains(vehicle.EndStop)) { excludedStops.Add(vehicle.EndStop); } } for (int i = 0; i < numberCustomers; i++) //generate 5 customers with random timeWindows and random pickup and delivery stops { var requestTime = 0; var pickupTimeWindow = new int[] { requestTime, simulation.Params.SimulationTimeWindow[1] }; //the customer pickup time will be between the current request time and the end of simulation time var customer = CustomerFactory.Instance().CreateRandomCustomer(simulation.Context.Stops, excludedStops, requestTime, pickupTimeWindow, false, simulation.Params.VehicleSpeed); //Generates a random static customer customersToBeServed.Add(customer); } var indexManager = new DataModelIndexManager(dataModelVehicles, customersToBeServed, startDepotsArrivalTime); var routingDataModel = new RoutingDataModel(indexManager, simulation.Params.MaximumRelativeCustomerRideTime, simulation.Params.MaximumAllowedDeliveryDelay); var solver = new RoutingSolver(routingDataModel, allowDropNodes); RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.LocalSearchMetaheuristic = LocalSearchMetaheuristic.Types.Value.Automatic; searchParameters.SolutionLimit = 1; //until it finds 1 solution var solution = solver.TryGetSolution(searchParameters); if (solution == null) { goto GenerateNewDataModelLabel; } return(routingDataModel); }
private RoutingSearchParameters GetDefaultSearchParameters() { // Setting first solution heuristic. RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.ParallelCheapestInsertion; return(searchParameters); }
/// <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); }
private void Distancia() { long routeDistance = 0; RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; DataModel data = new DataModel(Distancias, 1, 0); RoutingIndexManager manager = new RoutingIndexManager( data.DistanceMatrix.GetLength(0), data.VehicleNumber, data.Depot); RoutingModel routing = new RoutingModel(manager); 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]); }); routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); Assignment solution = routing.SolveWithParameters(searchParameters); var index = routing.Start(0); int indice = 1; string CadenaR = ""; string c = ""; while (routing.IsEnd(index) == false) { //Recorrido[indice] = manager.IndexToNode((int)index); c = manager.IndexToNode((int)index).ToString(); CadenaR = CadenaR + " - " + c; var previousIndex = index; index = solution.Value(routing.NextVar(index)); routeDistance += routing.GetArcCostForVehicle(previousIndex, index, 0); indice++; } //Recorrido[indice] = manager.IndexToNode((int)index); c = manager.IndexToNode((int)index).ToString(); CadenaR = CadenaR + " - " + c; Km = routeDistance; CadenaRecorrido = CadenaR; }
public override Assignment GetSolution() { Assignment solution = null; if (AlgorithmValue is FirstSolutionStrategy.Types.Value firstSolutionAlgorithm) { RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = firstSolutionAlgorithm; //searchParameters.TimeLimit = new Duration { Seconds = SearchTimeLimitInSeconds }; solution = Solver.TryGetSolution(searchParameters); } else { throw new ArgumentException("algorithm value is invalid"); } return(solution); }
public void InitializeFlexibleSimulation(bool allowDropNodes) { var dataModel = DataModelFactory.Instance().CreateInitialSimulationDataModel(allowDropNodes, this); if (dataModel != null) { RoutingSolver routingSolver = new RoutingSolver(dataModel, false); var printableList = dataModel.GetSettingsPrintableList(); foreach (var tobePrinted in printableList) { Console.WriteLine(tobePrinted); } //dataModel.PrintDataStructures(); Assignment timeWindowSolution = null; RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.ParallelCheapestInsertion; searchParameters.LocalSearchMetaheuristic = LocalSearchMetaheuristic.Types.Value.TabuSearch; searchParameters.TimeLimit = new Duration { Seconds = 20 }; timeWindowSolution = routingSolver.TryGetSolution(searchParameters); RoutingSolutionObject routingSolutionObject = null; if (timeWindowSolution != null) { routingSolver.PrintSolution(timeWindowSolution); routingSolutionObject = routingSolver.GetSolutionObject(timeWindowSolution); for (int j = 0; j < routingSolutionObject.VehicleNumber; j++) //Initializes the flexible trips { var solutionVehicle = routingSolutionObject.IndexToVehicle(j); var solutionVehicleStops = routingSolutionObject.GetVehicleStops(solutionVehicle); var solutionTimeWindows = routingSolutionObject.GetVehicleTimeWindows(solutionVehicle); var solutionVehicleCustomers = routingSolutionObject.GetVehicleCustomers(solutionVehicle); InitializeVehicleFlexibleRoute(solutionVehicle, solutionVehicleStops, solutionVehicleCustomers, solutionTimeWindows); } } } Simulate(); }
public FileOutput Solve(FileInput input, RoutingSearchParameters searchParameters) { WorkData data = converter.ToWorkData(input); RoutingIndexManager manager = new RoutingIndexManager(data.DistanceMatrix.GetLength(0), data.VehiclesAmount, data.Starts, data.Ends); RoutingModel routing = new RoutingModel(manager); AddCapacityConstrains(data, manager, routing); AddTimeWindowConstrains(data, manager, routing); AddPenaltiesAndDroppingVisits(data, manager, routing); Assignment solution = routing.SolveWithParameters(searchParameters); if (solution == null) { return(null); } return(converter.ConvertToFileOutput(input, manager, routing, solution)); }
/// <summary> /// Print the solution. /// </summary> public static int[] Solve() { int[] result = new int[200]; int cnt = 0; // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager(Ranks, VehicleNumber, Depot); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); 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((long)distMat[fromNode, toNode]); } ); routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // 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); // Inspect solution. var index = routing.Start(0); while (routing.IsEnd(index) == false) { result[cnt++] = Convert.ToInt32(index); var previousIndex = index; index = solution.Value(routing.NextVar(index)); } return(result); }
// <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); }
// <summary> // Метод создаем маршруты на день основываясь на данных всесенных в поля <c>Routes</c>, <c>Orders</c>, // <c>Drivers</c> и <c>Forwarders</c>. // </summary> public void CreateRoutes(TimeSpan drvStartTime, TimeSpan drvEndTime) { WarningMessages.Clear(); ProposedRoutes.Clear(); //Очищаем сразу, так как можем выйти из метода ранее. logger.Info("Подготавливаем заказы..."); PerformanceHelper.StartMeasurement($"Строим оптимальные маршруты"); // Создаем список поездок всех водителей. Тут перебираем всех водителей с машинами // и создаем поездки для них, в зависимости от выбранного режима работы. var trips = Drivers.Where(x => x.Car != null) .OrderBy(x => x.PriorityAtDay) .SelectMany(drv => drv.DaySchedule != null ? drv.DaySchedule.Shifts.Where(s => s.StartTime >= drvStartTime && s.StartTime < drvEndTime) .Select(shift => new PossibleTrip(drv, shift)) : new[] { new PossibleTrip(drv, null) } ) .ToList(); // Стыкуем уже созданные маршрутные листы с возможными поездками, на основании водителя и смены. // Если уже созданный маршрут не найден в поездках, то создаем поездку для него. foreach (var existRoute in Routes) { var trip = trips.FirstOrDefault(x => x.Driver == existRoute.Driver && x.Shift == existRoute.Shift); if (trip != null) { trip.OldRoute = existRoute; } else { trips.Add(new PossibleTrip(existRoute)); } //Проверяем все ли заказы из МЛ присутствуют в списке заказов. Если их нет. Добавляем. foreach (var address in existRoute.Addresses) { if (Orders.All(x => x.Id != address.Order.Id)) { Orders.Add(address.Order); } } } var possibleRoutes = trips.ToArray(); if (!possibleRoutes.Any()) { AddWarning("Для построения маршрутов, нет водителей."); return; } TestCars(possibleRoutes); var areas = UoW.GetAll <District>().Where(x => x.DistrictsSet.Status == DistrictsSetStatus.Active).ToList(); List <District> unusedDistricts = new List <District>(); List <CalculatedOrder> calculatedOrders = new List <CalculatedOrder>(); // Перебираем все заказы, исключаем те которые без координат, определяем для каждого заказа район // на основании координат. И создавая экземпляр <c>CalculatedOrder</c>, происходит подсчет сумарной // информации о заказе. Всего бутылей, вес и прочее. foreach (var order in Orders) { if (order.DeliveryPoint.Longitude == null || order.DeliveryPoint.Latitude == null) { continue; } var point = new Point((double)order.DeliveryPoint.Latitude.Value, (double)order.DeliveryPoint.Longitude.Value); var area = areas.Find(x => x.DistrictBorder.Contains(point)); if (area != null) { var oldRoute = Routes.FirstOrDefault(r => r.Addresses.Any(a => a.Order.Id == order.Id)); if (oldRoute != null) { calculatedOrders.Add(new CalculatedOrder(order, area, false, oldRoute)); } else if (possibleRoutes.SelectMany(x => x.Districts).Any(x => x.District.Id == area.Id)) { var cOrder = new CalculatedOrder(order, area); //if(possibleRoutes.Any(r => r.GeographicGroup.Id == cOrder.ShippingBase.Id))//убрать, если в автоформировании должны учавствовать заказы из всех частей города вне зависимости от того какие части города выбраны в диалоге calculatedOrders.Add(cOrder); } else if (!unusedDistricts.Contains(area)) { unusedDistricts.Add(area); } } } Nodes = calculatedOrders.ToArray(); if (unusedDistricts.Any()) { AddWarning("Районы без водителей: {0}", string.Join(", ", unusedDistricts.Select(x => x.DistrictName))); } // Создаем калькулятор расчета расстояний. Он сразу запрашивает уже имеющиеся расстояния из кеша // и в фоновом режиме начинает считать недостающую матрицу. distanceCalculator = new ExtDistanceCalculator(DistanceProvider.Osrm, Nodes.Select(x => x.Order.DeliveryPoint).ToArray(), StatisticsTxtAction); logger.Info("Развозка по {0} районам.", calculatedOrders.Select(x => x.District).Distinct().Count()); PerformanceHelper.AddTimePoint(logger, $"Подготовка заказов"); // Пред запуском оптимизации мы должны создать модель и внести в нее все необходимые данные. logger.Info("Создаем модель..."); RoutingModel routing = new RoutingModel(Nodes.Length + 1, possibleRoutes.Length, 0); // Создаем измерение со временем на маршруте. // <c>horizon</c> - ограничивает максимально допустимое значение диапазона, чтобы не уйти за границы суток; // <c>maxWaitTime</c> - Максимальное время ожидания водителя. То есть водитель закончил разгрузку следующий // адрес в маршруте у него не должен быть позже чем на 4 часа ожидания. int horizon = 24 * 3600; int maxWaitTime = 4 * 3600; var timeEvaluators = possibleRoutes.Select(x => new CallbackTime(Nodes, x, distanceCalculator)).ToArray(); routing.AddDimensionWithVehicleTransits(timeEvaluators, maxWaitTime, horizon, false, "Time"); var time_dimension = routing.GetDimensionOrDie("Time"); // Ниже заполняем все измерения для учета бутылей, веса, адресов, объема. var bottlesCapacity = possibleRoutes.Select(x => (long)x.Car.MaxBottles).ToArray(); routing.AddDimensionWithVehicleCapacity(new CallbackBottles(Nodes), 0, bottlesCapacity, true, "Bottles"); var weightCapacity = possibleRoutes.Select(x => (long)x.Car.MaxWeight).ToArray(); routing.AddDimensionWithVehicleCapacity(new CallbackWeight(Nodes), 0, weightCapacity, true, "Weight"); var volumeCapacity = possibleRoutes.Select(x => (long)(x.Car.MaxVolume * 1000)).ToArray(); routing.AddDimensionWithVehicleCapacity(new CallbackVolume(Nodes), 0, volumeCapacity, true, "Volume"); var addressCapacity = possibleRoutes.Select(x => (long)(x.Driver.MaxRouteAddresses)).ToArray(); routing.AddDimensionWithVehicleCapacity(new CallbackAddressCount(Nodes.Length), 0, addressCapacity, true, "AddressCount"); var bottlesDimension = routing.GetDimensionOrDie("Bottles"); var addressDimension = routing.GetDimensionOrDie("AddressCount"); for (int ix = 0; ix < possibleRoutes.Length; ix++) { // Устанавливаем функцию получения стоимости маршрута. routing.SetArcCostEvaluatorOfVehicle(new CallbackDistanceDistrict(Nodes, possibleRoutes[ix], distanceCalculator), ix); // Добавляем фиксированный штраф за принадлежность водителя. if (possibleRoutes[ix].Driver.DriverType.HasValue) { routing.SetFixedCostOfVehicle(((int)possibleRoutes[ix].Driver.DriverType) * DriverPriorityPenalty, ix); } else { routing.SetFixedCostOfVehicle(DriverPriorityPenalty * 3, ix); } var cumulTimeOnEnd = routing.CumulVar(routing.End(ix), "Time"); var cumulTimeOnBegin = routing.CumulVar(routing.Start(ix), "Time"); // Устанавливаем минимальные(мягкие) границы для измерений. При значениях меньше минимальных, маршрут все таки принимается, // но вносятся некоторые штрафные очки на последнюю точку маршрута. //bottlesDimension.SetEndCumulVarSoftLowerBound(ix, possibleRoutes[ix].Car.MinBottles, MinBottlesInRoutePenalty); //addressDimension.SetEndCumulVarSoftLowerBound(ix, possibleRoutes[ix].Driver.MinRouteAddresses, MinAddressesInRoutePenalty); // Устанавливаем диапазон времени для движения по маршруту в зависимости от выбраной смены, // день, вечер и с учетом досрочного завершения водителем работы. if (possibleRoutes[ix].Shift != null) { var shift = possibleRoutes[ix].Shift; var endTime = possibleRoutes[ix].EarlyEnd.HasValue ? Math.Min(shift.EndTime.TotalSeconds, possibleRoutes[ix].EarlyEnd.Value.TotalSeconds) : shift.EndTime.TotalSeconds; cumulTimeOnEnd.SetMax((long)endTime); cumulTimeOnBegin.SetMin((long)shift.StartTime.TotalSeconds); } else if (possibleRoutes[ix].EarlyEnd.HasValue) //Устанавливаем время окончания рабочего дня у водителя. { cumulTimeOnEnd.SetMax((long)possibleRoutes[ix].EarlyEnd.Value.TotalSeconds); } } for (int ix = 0; ix < Nodes.Length; ix++) { // Проставляем на каждый адрес окно времени приезда. var startWindow = Nodes[ix].Order.DeliverySchedule.From.TotalSeconds; var endWindow = Nodes[ix].Order.DeliverySchedule.To.TotalSeconds - Nodes[ix].Order.CalculateTimeOnPoint(false); //FIXME Внимание здесь задаем время без экспедитора и без учета скорости водителя. Это не правильно, но другого варианта я придумать не смог. if (endWindow < startWindow) { AddWarning("Время разгрузки на {2}, не помещается в диапазон времени доставки. {0}-{1}", Nodes[ix].Order.DeliverySchedule.From, Nodes[ix].Order.DeliverySchedule.To, Nodes[ix].Order.DeliveryPoint.ShortAddress); endWindow = startWindow; } time_dimension.CumulVar(ix + 1).SetRange((long)startWindow, (long)endWindow); // Добавляем абсолютно все заказы в дизюкцию. Если бы заказы небыли вдобавлены в отдельные дизьюкции // то при не возможность доставить хоть один заказ. Все решение бы считаль не верным. Добавление каждого заказа // в отдельную дизьюкцию, позволяет механизму не вести какой то и заказов, и все таки формировать решение с недовезенными // заказами. Дизьюкция работает так. Он говорит, если хотя бы один заказ в этой группе(дизьюкции) доставлен, // то все хорошо, иначе штраф. Так как у нас в кадой дизьюкции по одному заказу. Мы получаем опциональную доставку каждого заказа. routing.AddDisjunction(new int[] { ix + 1 }, MaxDistanceAddressPenalty); } logger.Debug("Nodes.Length = {0}", Nodes.Length); logger.Debug("routing.Nodes() = {0}", routing.Nodes()); logger.Debug("GetNumberOfDisjunctions = {0}", routing.GetNumberOfDisjunctions()); RoutingSearchParameters search_parameters = RoutingModel.DefaultSearchParameters(); // Setting first solution heuristic (cheapest addition). // Указывается стратегия первоначального заполнения. Опытным путем было вычислено, что именно при // стратегиях вставки маршруты получаются с набором точек более близких к друг другу. То есть в большей // степени облачком. Что воспринималось человеком как более отпимальное. В отличии от большенства других // стратегий в которых маршруты, формируюся скорее по лентами ведущими через все обезжаемые раоны. То есть водители // чаще имели пересечения маршутов. search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.ParallelCheapestInsertion; search_parameters.TimeLimitMs = MaxTimeSeconds * 1000; // Отключаем внутреннего кеширования расчитанных значений. Опытным путем было проверено, что включение этого значения. // Значительно(на несколько секунд) увеличивает время закрытия модели и сокращает иногда не значительно время расчета оптимизаций. // И в принцепе становится целесообразно только на количествах заказов 300-400. При количестве заказов менее 200 // влючение отпечатков значений. Не уменьшало, а увеличивало общее время расчета. А при большом количестве заказов // время расчета уменьшалось не значительно. //search_parameters.FingerprintArcCostEvaluators = false; search_parameters.FingerprintArcCostEvaluators = true; //search_parameters.OptimizationStep = 100; var solver = routing.solver(); PerformanceHelper.AddTimePoint(logger, $"Настроили оптимизацию"); logger.Info("Закрываем модель..."); if ( WarningMessages.Any() && !interactiveService.Question( string.Join("\n", WarningMessages.Select(x => "⚠ " + x)), "При построении транспортной модели обнаружены следующие проблемы:\n{0}\nПродолжить?" ) ) { distanceCalculator.Canceled = true; distanceCalculator.Dispose(); return; } logger.Info("Рассчет расстояний между точками..."); routing.CloseModelWithParameters(search_parameters); #if DEBUG PrintMatrixCount(distanceCalculator.matrixcount); #endif //Записывем возможно не схраненый кеш в базу. distanceCalculator.FlushCache(); //Попытка хоть как то ослеживать что происходит в момент построения. Возможно не очень правильная. //Пришлось создавать 2 монитора. 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("Готово. Заполняем."); #if DEBUG PrintMatrixCount(distanceCalculator.matrixcount); #endif Console.WriteLine("Status = {0}", routing.Status()); if (solution != null) { // Solution cost. Console.WriteLine("Cost = {0}", solution.ObjectiveValue()); time_dimension = routing.GetDimensionOrDie("Time"); //Читаем полученные маршруты. for (int route_number = 0; route_number < routing.Vehicles(); route_number++) { var route = new ProposedRoute(possibleRoutes[route_number]); long first_node = routing.Start(route_number); long second_node = solution.Value(routing.NextVar(first_node)); // Пропускаем первый узел, так как это наша база. route.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} Cost:{5}", 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"), routing.GetCost(first_node, second_node, route_number) ); route.Orders.Add(rPoint); first_node = second_node; second_node = solution.Value(routing.NextVar(first_node)); route.RouteCost += routing.GetCost(first_node, second_node, route_number); } if (route.Orders.Count > 0) { ProposedRoutes.Add(route); logger.Debug("Маршрут {0}: {1}", route.Trip.Driver.ShortName, string.Join(" -> ", route.Orders.Select(x => x.DebugMaxMin)) ); } else { logger.Debug("Маршрут {0}: пустой", route.Trip.Driver.ShortName); } } } #if DEBUG logger.Debug("SGoToBase:{0}", string.Join(", ", CallbackDistanceDistrict.SGoToBase.Select(x => $"{x.Key.Driver.ShortName}={x.Value}"))); logger.Debug("SFromExistPenality:{0}", string.Join(", ", CallbackDistanceDistrict.SFromExistPenality.Select(x => $"{x.Key.Driver.ShortName}={x.Value}"))); logger.Debug("SUnlikeDistrictPenality:{0}", string.Join(", ", CallbackDistanceDistrict.SUnlikeDistrictPenality.Select(x => $"{x.Key.Driver.ShortName}={x.Value}"))); logger.Debug("SLargusPenality:{0}", string.Join(", ", CallbackDistanceDistrict.SLargusPenality.Select(x => $"{x.Key.Driver.ShortName}={x.Value}"))); #endif if (ProposedRoutes.Count > 0) { logger.Info($"Предложено {ProposedRoutes.Count} маршрутов."); } PerformanceHelper.Main.PrintAllPoints(logger); if (distanceCalculator.ErrorWays.Any()) { 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))) ); } }
public static int[] Run(long[] DistanceMatrix, int num, int VehicleNumber, int Depot, RoutingSearchParameters searchParameters) { // Instantiate the data problem. // Create Routing Index Manager RoutingIndexManager manager = new RoutingIndexManager( num, VehicleNumber, Depot); // Create Routing Model. RoutingModel routing = new RoutingModel(manager); 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(DistanceMatrix[fromNode * num + toNode]); } ); // Define cost of each arc. routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex); // Solve the problem. Assignment solution = routing.SolveWithParameters(searchParameters); // Print solution on console. return(GetOrder(routing, manager, solution)); }
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); }
/// <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); } }
public IList <string> GetShortestOptimizedRoute([FromBody] GeographicViewModel geographicVM) { // double[] latitude = { 13.121329, 13.065150, 13.024346, 13.027691, 12.913887, 12.915754, 12.962431, 12.890461, 12.907220, 12.954234, 13.026996, 13.041044, 13.001573 }; //double[] longitude = { 80.029049, 80.128613, 79.909573, 80.259762, 80.253067, 80.192041, 80.253839, 80.097198, 80.142088, 80.188437, 80.107756, 80.234957, 80.257616 }; string[] city_names = { "Thirunindravur", "Thiruverkadu", "Senkadu", "Milapore", "VGP Golden", "Medavakkam", "Palavakkam", "Vandalur", "Selaiyur", "Kelkattalai", "Mangadu", "TNagar", "Adyar" }; double[] latitudeandLongitude; var sCoordlatitudeandLongitude = new List <string>(); var finallatitudeandLongitude = new List <string>(); distanceArray = new double[geographicVM.Latitude.Length, geographicVM.Longitude.Length]; var k = 0; for (int i = 0; i < geographicVM.Latitude.Length; i++) { for (int j = 0; j < geographicVM.Longitude.Length; j++) { var sCoord = new GeoCoordinate(geographicVM.Latitude[i], geographicVM.Longitude[i]); var eCoord = new GeoCoordinate(geographicVM.Latitude[j], geographicVM.Longitude[j]); if (i == j) { if (i % 2 == 0) { sCoordlatitudeandLongitude.Add(sCoord.ToString() + ",D" + "," + k++); } else { sCoordlatitudeandLongitude.Add(sCoord.ToString() + ",P" + "," + k); } } var text = sCoord.GetDistanceTo(eCoord) / 1609.344; distanceArray[i, j] = Math.Round(text); } } double[,] costs = distanceArray; int num_locations = city_names.Length; RoutingModel routingModel = new RoutingModel(geographicVM.Latitude.Length, 1, 0); Solver solver = routingModel.solver(); string rank_name = "rank"; routingModel.AddConstantDimension(1, geographicVM.Latitude.Length, true, rank_name); var rank_dimension = routingModel.GetDimensionOrDie(rank_name); //Constraint MinneapolisBeforeNewYork = solver.MakeLess(routingModel.CumulVar(highPriorityVarIndex, rank_name), routingModel.CumulVar(lowPriorityVarIndex, rank_name)); /* Later needs to be worked on the Constraint for the Multiple Pickups before Delivery */ //Constraint test = routingModel.CumulVar(3, rank_name) < routingModel.CumulVar(13, rank_name); //solver.Add(test); RoutingSearchParameters search_parameters = RoutingModel.DefaultSearchParameters(); search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.LocalCheapestArc; NodeEvaluator2 cost_between_nodes = new Cost(costs); routingModel.SetArcCostEvaluatorOfAllVehicles(cost_between_nodes); //oder SetVehicleCost wenn Fahrzeuge unterschiedliche Kostenmatrix haben StringBuilder route = new StringBuilder(); Assignment assignment = routingModel.SolveWithParameters(search_parameters); if (assignment != null) { Console.WriteLine("Total distance: " + assignment.ObjectiveValue().ToString() + "miles"); long index = routingModel.Start(0); //vehicle 0 route.Append("Route: "); do { //route.Append(city_names[routingModel.IndexToNode(index)] + " -> "); finallatitudeandLongitude.Add(sCoordlatitudeandLongitude[routingModel.IndexToNode(index)]); index = assignment.Value(routingModel.NextVar(index)); }while (!routingModel.IsEnd(index)); // route.Append(city_names[routingModel.IndexToNode(index)]); finallatitudeandLongitude.Add(sCoordlatitudeandLongitude[routingModel.IndexToNode(index)]); } return(finallatitudeandLongitude); }
static void Main(string[] args) { List <string> Addresses = new List <string>() { "New York", "Los Angeles", "Chicago", "Minneapolis", "Denver", "Dallas", "Seattle", "Boston", "San Francisco", "St.Louis", "Houston", "Phoenix", "Salt Lake City" }; APIGoogle.Register("AIzaSyCkYDMEPLWCFvq3Oi-LJyEsMuh_06Fk62g"); List <LatLng> listLatLng = new List <LatLng>(); foreach (string item in Addresses) { listLatLng.Add(APIGoogle.GetLatLng(item)); } DirectionRequest directionRequest = new DirectionRequest(); DirectionService directionService = new DirectionService(); long[,] CityDistanceMatrix = new long[Addresses.Count, Addresses.Count]; for (int i = 0; i < Addresses.Count; i++) { for (int j = 0; j < Addresses.Count; j++) { directionRequest.Origin = Addresses[i]; directionRequest.Sensor = false; { directionRequest.Destination = Addresses[j]; var ttt = directionService.GetResponse(directionRequest); CityDistanceMatrix[i, j] = directionService.GetResponse(directionRequest).Routes[0].Legs[0].Distance.Value / 1000; }; } } int NumRoutes = 1; // The number of routes, which is 1 in the TSP. // Nodes are indexed from 0 to tsp_size - 1. The depot is the starting node of the route. int Depot = 0; int TspSize = Addresses.Count; if (TspSize > 0) { RoutingModel routing = new RoutingModel(TspSize, NumRoutes, Depot); RoutingSearchParameters search_parameters = RoutingModel.DefaultSearchParameters(); CityDistance dist_between_nodes = new CityDistance(CityDistanceMatrix, Addresses); routing.SetArcCostEvaluatorOfAllVehicles(dist_between_nodes); //routing.SetCost(dist_between_nodes); Demand demands_at_locations = new Demand(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); search_parameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; Assignment solution = routing.SolveWithParameters(search_parameters); Console.WriteLine("Status = {0}", routing.Status()); if (solution != null) { // Solution cost. Console.WriteLine("Suma [km]= {0}", solution.ObjectiveValue() / 1000); // 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} \n", Addresses[(int)node]); } Console.WriteLine(Addresses[0]); } } Console.ReadKey(); }
/// <summary> /// Solves the current routing problem. /// </summary> static void Solve() { // Instantiate the data problem. // [START data] const int num_location = 5; const int num_vehicles = 1; const int depot = 0; // [END data] // Create Routing Index Manager // [START index_manager] RoutingIndexManager manager = new RoutingIndexManager(num_location, num_vehicles, depot); // [END index_manager] // Create Routing Model. // [START routing_model] RoutingModel routing = new RoutingModel(manager); // [END routing_model] // Define cost of each arc. // [START arc_cost] routing.SetArcCostEvaluatorOfAllVehicles( routing.RegisterTransitCallback( (long FromIndex, long ToIndex) => { return(1L); } )); // [END arc_cost] // Setting first solution heuristic. // [START parameters] RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc; // [END parameters] // Solve the problem. // [START solve] Assignment solution = routing.SolveWithParameters(searchParameters); // [END solve] // Print solution on console. // [START print_solution] Console.WriteLine("Objective: {0}", solution.ObjectiveValue()); // Inspect solution. long index = routing.Start(0); Console.WriteLine("Route for Vehicle 0:"); long route_distance = 0; while (routing.IsEnd(index) == false) { Console.Write("{0} -> ", manager.IndexToNode((int)index)); long previousIndex = index; index = solution.Value(routing.NextVar(index)); route_distance += routing.GetArcCostForVehicle(previousIndex, index, 0); } Console.WriteLine("{0}", manager.IndexToNode(index)); Console.WriteLine("Distance of the route: {0}m", route_distance); // [END print_solution] }
/// <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> /// Constructs a new Event Arguments instance. /// </summary> /// <param name="searchParams"></param> internal RoutingSearchParametersEventArgs(RoutingSearchParameters searchParams) { this.Parameters = searchParams; }
/// <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 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); 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 parameters = new RoutingSearchParameters(); parameters.no_lns = true; parameters.first_solution = "AllUnperformed"; parameters.trace = true; Console.WriteLine("Search"); Assignment solution = model.SolveWithParameters(parameters, null); 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); } }
public override void Handle(Event evt) { //INSERTION OF EVENTS FOR THE NEWLY GENERATED ROUTE ( after a dynamic request has been accepted) if (evt.Category == 4 && evt is CustomerRequestEvent customerRequestEvent) { Log(evt); evt.AlreadyHandled = true; _consoleLogger.Log("New Customer (dynamic) request:" + customerRequestEvent.Customer + " - " + customerRequestEvent.Customer.PickupDelivery[0] + " -> " + customerRequestEvent.Customer.PickupDelivery[1] + ", TimeWindows: {" + customerRequestEvent.Customer.DesiredTimeWindow[0] + "," + customerRequestEvent.Customer.DesiredTimeWindow[1] + "} at " + TimeSpan.FromSeconds(evt.Time).ToString()); //Check if request can be served, if so the Simulation.Stats.TotalDynamicRequests++; var newCustomer = customerRequestEvent.Customer; RoutingSolutionObject solutionObject = null; if (Simulation.Context.VehicleFleet.FindAll(v => v.FlexibleRouting).Count > 0 && newCustomer != null) { var dataModel = DataModelFactory.Instance().CreateCurrentSimulationDataModel(Simulation, newCustomer, evt.Time); var solver = new RoutingSolver(dataModel, false); RoutingSearchParameters searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters(); searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.ParallelCheapestInsertion; searchParameters.LocalSearchMetaheuristic = LocalSearchMetaheuristic.Types.Value.TabuSearch; searchParameters.TimeLimit = new Duration { Seconds = 5 }; //change _consoleLogger.Log("Generating new Routing Solution..."); var solution = solver.TryGetSolution(searchParameters); if (solution != null) { //solver.PrintSolution(solution); Simulation.Stats.TotalServedDynamicRequests++; _consoleLogger.Log(newCustomer.ToString() + " request was inserted into a vehicle route at " + TimeSpan.FromSeconds(customerRequestEvent.Time).ToString()); solutionObject = solver.GetSolutionObject(solution); } else { _consoleLogger.Log(newCustomer.ToString() + " will not be able to be served by any of the available vehicles at " + TimeSpan.FromSeconds(customerRequestEvent.Time).ToString()); } } if (!Simulation.Context.DynamicCustomers.Contains(newCustomer)) { Simulation.Context.DynamicCustomers.Add(newCustomer); } if (solutionObject != null) { //solutionObject.MetricsContainer.PrintMetrics(); var vehicleFlexibleRouting = Simulation.Context.VehicleFleet.FindAll(v => v.FlexibleRouting); foreach (var vehicle in vehicleFlexibleRouting) { var solutionRoute = solutionObject.GetVehicleStops(vehicle); var solutionTimeWindows = solutionObject.GetVehicleTimeWindows(vehicle); var solutionCustomers = solutionObject.GetVehicleCustomers(vehicle); if (solutionRoute.Count >= 2 && solutionRoute[0] != solutionRoute[1])//check if current vehicle route is valid { if (vehicle.VisitedStops.Count > 1 && vehicle.CurrentStop == Simulation.Context.Depot) { _consoleLogger.Log("Vehicle " + vehicle.Id + " already performed a route and is currently idle at depot.");//debug } if (vehicle.TripIterator?.Current != null) { var currentStopIndex = vehicle.TripIterator.Current.StopsIterator.CurrentIndex; var customers = solutionObject.GetVehicleCustomers(vehicle); //contains all customers (already inside and not yet in vehicle) List <Stop> visitedStops = new List <Stop>(vehicle.VisitedStops); List <long[]> visitedTimeWindows = new List <long[]>(vehicle.StopsTimeWindows); if (currentStopIndex < vehicle.VisitedStops.Count) { visitedStops.RemoveAt(currentStopIndex); //remove current stop from the visitedStops list visitedTimeWindows.RemoveAt(currentStopIndex); //remove current timeWindow from the visitedTimeWindows list } //inserts the already visited stops at the beginning of the solutionRoute list for (int e = visitedStops.Count - 1; e >= 0; e--) { solutionRoute.Insert(0, visitedStops[e]); solutionTimeWindows.Insert(0, visitedTimeWindows[e]); } vehicle.TripIterator.Current.AssignStops(solutionRoute, solutionTimeWindows, currentStopIndex); vehicle.TripIterator.Current.ExpectedCustomers = customers.FindAll(c => !c.IsInVehicle); //the expected customers for the current vehicle are the ones that are not in that vehicle var vehicleEvents = Simulation.Events.FindAll(e => (e is VehicleStopEvent vse && vse.Vehicle == vehicle && e.Time >= evt.Time) || (e is CustomerVehicleEvent cve && cve.Vehicle == vehicle && e.Time >= evt.Time)).OrderBy(e => e.Time).ThenBy(e => e.Category).ToList(); //gets all next vehicle depart or arrive events if (vehicleEvents.Count > 0) { foreach (var vEvent in vehicleEvents) { if (vEvent is VehicleStopEvent vehicleStopArriveEvent && vEvent.Category == 0 ) //vehicle arrive stop event { //_consoleLogger.Log(vehicleStopArriveEvent.GetTraceMessage()); } if (vEvent is VehicleStopEvent vehicleStopDepartEvent && vEvent.Category == 1 ) //vehicle depart stop event { var departTime = vEvent.Time; if (vehicleStopDepartEvent.Stop == vehicle.CurrentStop) { departTime = (int)vehicle.TripIterator.Current.ScheduledTimeWindows[ vehicle.TripIterator.Current.StopsIterator.CurrentIndex][1] + 2; //recalculates new event depart time; vEvent.Time = departTime; } var allEnterLeaveEventsForCurrentVehicle = Simulation.Events .FindAll(e => e.Time >= evt.Time && (e is CustomerVehicleEvent cve && cve.Vehicle == vehicle)) .OrderBy(e => e.Time).ThenBy(e => e.Category).ToList(); foreach (var enterOrLeaveEvt in allEnterLeaveEventsForCurrentVehicle) { if (enterOrLeaveEvt.Time > departTime ) //if the event time is greater than the depart time removes those events, otherwise maintain the enter and leave events for current stop { Simulation.Events.Remove(enterOrLeaveEvt); } } } } } else { //if vehicle events is 0 it means the vehicle has no more generated events for it, need to generate a new depart event for the vehicle vehicle.TripIterator.Current.IsDone = false; //current trip is no longer completed var currentDepartureTime = (int)solutionTimeWindows[currentStopIndex][1]; if (currentDepartureTime == evt.Time) //if departure time is the same time as the event being handled adds 1 to its time { currentDepartureTime++; } var departEvt = Simulation.EventGenerator.GenerateVehicleDepartEvent(vehicle, currentDepartureTime); Simulation.Events.Add(departEvt); } } else { //trip assignment for vehicles that are have not yet performed a route Simulation.InitializeVehicleFlexibleRoute(vehicle, solutionRoute, solutionCustomers, solutionTimeWindows); } } } } } else { Successor?.Handle(evt); } }