【问题标题】:OR tools CVRP reload using single vehicle使用单车或工具 CVRP 重新加载
【发布时间】:2021-12-05 09:42:18
【问题描述】:

跟随python示例here

我正在尝试在 java 中构建相同的功能 - 加载东西并交付给客户,如果下一个需求超过剩余容量,那么去仓库并重新加载。所有这一切都在没有任何时间限制的情况下发生,但是在我的情况下只有一辆车。问题是解决方案在很多情况下都是空的。

例如:需求:[0, -30, -30, -30, 17, 17, 18, 18, 18, 18] 车辆容量为 30 的结果为 null。但是,不同车辆容量的相同需求可以正常工作,例如-18364896

第一个要求是 0,因为这是起始位置。

这是我正在使用的代码:

final OrDataModel data = buildDataModel();

RoutingIndexManager manager = new RoutingIndexManager(data.distanceMatrix.length, data.vehicleNumber, data.depot);

RoutingModel routing = new RoutingModel(manager);

final int transitCallbackIndex =
routing.registerTransitCallback((long fromIndex, long toIndex) -> {
  int fromNode = manager.indexToNode(fromIndex);
  int toNode = manager.indexToNode(toIndex);
  return data.distanceMatrix[fromNode][toNode];
});

routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
routing.addDimension(transitCallbackIndex, 0, 1000000, true, "Distance");
RoutingDimension distanceDimension = routing.getDimensionOrDie("Distance");
distanceDimension.setGlobalSpanCostCoefficient(100);

final int demandCallbackIndex = routing.registerUnaryTransitCallback(
  (long fromIndex) -> {
  // Convert from routing variable Index to user NodeIndex.
  int fromNode = manager.indexToNode(fromIndex);
  return data.demands[fromNode];
});

routing.addDimension(demandCallbackIndex, data.vehicleCapacity, data.vehicleCapacity, true, "Capacity");
RoutingDimension capacityDimension = routing.getDimensionOrDie("Capacity");

//No penalty in case multi-trip visit is skipped when not required
for(int i = 1; i <= data.multiTrips - 1; i++) {
  int fromNode = manager.indexToNode(i);
  routing.addDisjunction(new long[] { fromNode }, 0);
}

// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
  main.defaultRoutingSearchParameters()
  .toBuilder()
  .setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
  .setLocalSearchMetaheuristic(LocalSearchMetaheuristic.Value.GUIDED_LOCAL_SEARCH)
  .setTimeLimit(Duration.newBuilder().setSeconds(1).build())
  .build();

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

if(solution != null) {
   printSolution(data, routing, manager, solution);
} else {
  System.out.print("no results");
}
private static OrDataModel buildDataModel() {
    
    List<Long> volumes = new ArrayList<>();
    List<double[]> locations = new ArrayList<>();
    readCsvFile(volumes, locations);
    
    double totalVolume = LCollectionUtils.sumDoubleProperty(volumes, volume -> volume);
    
    int maxCapacity = 30;
    
    int multiTrips = calculateMultiTrips(totalVolume, maxCapacity);
    
    List<double[]> multiTripLocations = new ArrayList<>();
    for(int i = 0; i < multiTrips; i++) {
        multiTripLocations.add(new double[] { 24.3653, 54.7136 });
    }
    
    List<double[]> allLocations = new ArrayList<double[]>(multiTripLocations);
    allLocations.addAll(locations);
    double[][] matrix = new double[allLocations.size()][];
    matrix = allLocations.toArray(matrix);
    
    long[][] distanceMatrix = buildDistanceMatrix(matrix, multiTrips);
    long[][] timeMatrix = buildTimeMatrix(matrix, multiTrips);
    long[] demands = fillDemands(multiTrips, matrix.length, volumes, maxCapacity);
    
    long[][] timeWindows = fillTimeWindow(allLocations.size(), multiTrips);
    
    return OrDataModel.from(matrix, distanceMatrix, timeMatrix, demands, allLocations.size(), multiTrips, maxCapacity, timeWindows, totalVolume);
}

private static long[] fillDemands(int minimumMultiTrips, int numberOfLocations, List<Long> allVolumes, long vehicleCapacity) {
    
    long[] demands = new long[numberOfLocations];
    
    //first demand is at depot so 0
    demands[0] = 0;
    
    int index;
    for(index = 1; index < minimumMultiTrips; index++) {
        demands[index] = (long)-vehicleCapacity;
    }
    
    for(int j = 0; j < allVolumes.size(); j++) {
        demands[index] = allVolumes.get(j);
        index++;
    }
    
    return demands;
}


private static int calculateMultiTrips(double totalVolume, int capacity) {
    double remainder = totalVolume % capacity;
    double quotient = totalVolume / capacity;
    double multiTrip = remainder == 0 ? quotient : quotient + 1;
    return (int)multiTrip;
}

private static long[][] buildDistanceMatrix(double[][] locations, int minimumMultiTrips) {

    long[][] distanceData = new long[locations.length][locations.length];

    for (int i = 0; i < locations.length; i++) {
        
        LatLng fromLatLng = new LatLng().lat(locations[i][0]).lng(locations[i][1]);

        for (int j = 0; j < locations.length; j++) {

            if (i == j) {
                distanceData[i][j] = 0;
            }
            
            else if(i < minimumMultiTrips && j < minimumMultiTrips) {
                distanceData[i][j] = 100000;
            }
            
            else {
                LatLng toLatLng = new LatLng().lat(locations[j][0]).lng(locations[j][1]);
                LatLngQueryDataFetcher distanceFetcher = new HaversineDistanceFetcher(30, 1.25);
                sh.locus.pjp.server.model.distance.TimeDistancePair response = distanceFetcher.fetch(fromLatLng, toLatLng);
                distanceData[i][j] = response.getDistance();
            }
        }
    }

    return distanceData;
}

代码很简单。从 csv 文件读取需求,经纬度。硬编码此示例的 homebase 位置。构建距离和时间矩阵,但仅使用距离矩阵。我可能错过了什么?

【问题讨论】:

    标签: java or-tools


    【解决方案1】:

    注意 AddDisjunction 采用索引而不是节点,所以基本上你的代码:

        //No penalty in case multi-trip visit is skipped when not required
        for(int i = 1; i <= data.multiTrips - 1; i++) {
            int fromNode = manager.indexToNode(i);
            routing.addDisjunction(new long[] { fromNode }, 0);
        }
    

    错了,你需要相反

        //No penalty in case multi-trip visit is skipped when not required
        for(int i = 1; i <= data.multiTrips - 1; i++) {
            int fromIndex = manager.nodeToIndex(i);
            routing.addDisjunction(new long[] { fromIndex }, 0);
        }
    

    【讨论】:

    • 没有帮助。不过谢谢!
    猜你喜欢
    • 1970-01-01
    • 2013-06-28
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 2022-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多