OR 工具 - VRP - 无法找到最佳解决方案的处理案例
OR Tools - VRP - Handling cases where no optimal solution can be found
我正在基于 Google 的 ORTools 构建车辆路径问题的求解器。
对于简单问题或高容量问题,它工作正常,但是对于大多数“真实”数据集,我最终得到的解决方案要么 运行 无限期地或超时。
经过一番思考,我意识到并非所有现实世界的问题都可以解决或优化。例如。我可能希望大多数车辆每天行驶不超过 500 公里。但是,如果我必须向 600 公里以外的人送货,整个解决方案就会失败。
我该如何处理这些情况?现在它似乎是二元的通过或失败。我很高兴某些情况被忽略或 return 一个次优的解决方案。
这是我的解决方案的代码
public List<OptimisedVehicleRoute> Start(Location depot, List<Location> locations, int numVehicles = 1, float maxDistanceKmPerVehicle = 1000f, float maxDistanceKmSlack = 5f)
{
// Create Routing Index Manager
var depotIndex = locations.IndexOf(depot);
var manager = new RoutingIndexManager(locations.Count, numVehicles, depotIndex);
Console.WriteLine($"Depot at {depot.Postcode}");
var routing = new RoutingModel(manager);
var numCalls = 0l;
int transitCallbackIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) =>
{
numCalls++;
// Convert from routing variable Index to distance matrix NodeIndex.
var fromNode = manager.IndexToNode(fromIndex);
var toNode = manager.IndexToNode(toIndex);
var fromLocation = locations[fromNode];
var toLocation = locations[toNode];
var mDistance = fromLocation.DistanceTo(toLocation);
return mDistance;
});
// The arc cost evaluator tells the solver how to calculate the cost of travel between any two locations
routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
long maxVehicleDistanceSlack = (long)Math.Round(maxDistanceKmSlack * 1000); // slack per day
long maxVehicleDistance = (long)Math.Round(maxDistanceKmPerVehicle * 1000); // 1000km max distance per day
routing.AddDimension(transitCallbackIndex, maxVehicleDistanceSlack, maxVehicleDistance, true, "Distance");
RoutingDimension distanceDimension = routing.GetMutableDimension("Distance");
distanceDimension.SetGlobalSpanCostCoefficient(100);
var searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters();
searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
var timer = new Stopwatch();
timer.Start();
searchParameters.LogSearch = true;
var solution = routing.SolveWithParameters(searchParameters);
timer.Stop();
Console.WriteLine(timer.Elapsed.TotalSeconds);
var optimisedVehicleRoutes = this.CreateOptimisedVehicleLocations(locations, numVehicles, routing, manager, solution);
this.OptimisedDistanceKm = optimisedVehicleRoutes.Sum(r => r.TotalDistanceKm);
routing.Dispose();
return optimisedVehicleRoutes;
}
P.s。如果有人能帮助我理解“Slack”的实际用途,我将不胜感激。我最初假设这是每辆车的公差(即 10 公里的间隙允许车辆在其最大路线距离上行驶 10 公里)。但是现在我不确定
如果你的位置在 600 公里处,最大允许距离为 500 公里,你的问题基本上是不可行的...
但是您可以允许求解器使用 AddDisjunction()
删除此位置,使您的问题可行...
请查看文档站点上的示例:https://developers.google.com/optimization/routing/penalties
我正在基于 Google 的 ORTools 构建车辆路径问题的求解器。
对于简单问题或高容量问题,它工作正常,但是对于大多数“真实”数据集,我最终得到的解决方案要么 运行 无限期地或超时。
经过一番思考,我意识到并非所有现实世界的问题都可以解决或优化。例如。我可能希望大多数车辆每天行驶不超过 500 公里。但是,如果我必须向 600 公里以外的人送货,整个解决方案就会失败。
我该如何处理这些情况?现在它似乎是二元的通过或失败。我很高兴某些情况被忽略或 return 一个次优的解决方案。
这是我的解决方案的代码
public List<OptimisedVehicleRoute> Start(Location depot, List<Location> locations, int numVehicles = 1, float maxDistanceKmPerVehicle = 1000f, float maxDistanceKmSlack = 5f)
{
// Create Routing Index Manager
var depotIndex = locations.IndexOf(depot);
var manager = new RoutingIndexManager(locations.Count, numVehicles, depotIndex);
Console.WriteLine($"Depot at {depot.Postcode}");
var routing = new RoutingModel(manager);
var numCalls = 0l;
int transitCallbackIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) =>
{
numCalls++;
// Convert from routing variable Index to distance matrix NodeIndex.
var fromNode = manager.IndexToNode(fromIndex);
var toNode = manager.IndexToNode(toIndex);
var fromLocation = locations[fromNode];
var toLocation = locations[toNode];
var mDistance = fromLocation.DistanceTo(toLocation);
return mDistance;
});
// The arc cost evaluator tells the solver how to calculate the cost of travel between any two locations
routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
long maxVehicleDistanceSlack = (long)Math.Round(maxDistanceKmSlack * 1000); // slack per day
long maxVehicleDistance = (long)Math.Round(maxDistanceKmPerVehicle * 1000); // 1000km max distance per day
routing.AddDimension(transitCallbackIndex, maxVehicleDistanceSlack, maxVehicleDistance, true, "Distance");
RoutingDimension distanceDimension = routing.GetMutableDimension("Distance");
distanceDimension.SetGlobalSpanCostCoefficient(100);
var searchParameters = operations_research_constraint_solver.DefaultRoutingSearchParameters();
searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
var timer = new Stopwatch();
timer.Start();
searchParameters.LogSearch = true;
var solution = routing.SolveWithParameters(searchParameters);
timer.Stop();
Console.WriteLine(timer.Elapsed.TotalSeconds);
var optimisedVehicleRoutes = this.CreateOptimisedVehicleLocations(locations, numVehicles, routing, manager, solution);
this.OptimisedDistanceKm = optimisedVehicleRoutes.Sum(r => r.TotalDistanceKm);
routing.Dispose();
return optimisedVehicleRoutes;
}
P.s。如果有人能帮助我理解“Slack”的实际用途,我将不胜感激。我最初假设这是每辆车的公差(即 10 公里的间隙允许车辆在其最大路线距离上行驶 10 公里)。但是现在我不确定
如果你的位置在 600 公里处,最大允许距离为 500 公里,你的问题基本上是不可行的...
但是您可以允许求解器使用 AddDisjunction()
删除此位置,使您的问题可行...
请查看文档站点上的示例:https://developers.google.com/optimization/routing/penalties