diff --git a/makefiles/Makefile.java.mk b/makefiles/Makefile.java.mk index 03f44c6a66..3d36ee1425 100755 --- a/makefiles/Makefile.java.mk +++ b/makefiles/Makefile.java.mk @@ -376,6 +376,7 @@ test_java_constraint_solver_samples: \ rjava_SimpleRoutingProgram \ rjava_Tsp \ rjava_Vrp \ + rjava_VrpCapacity \ .PHONY: test_java_graph_samples # Build and Run all Java Graph Samples (located in ortools/graph/samples) test_java_graph_samples: \ diff --git a/ortools/constraint_solver/samples/VrpCapacity.java b/ortools/constraint_solver/samples/VrpCapacity.java new file mode 100644 index 0000000000..6b4244ebd6 --- /dev/null +++ b/ortools/constraint_solver/samples/VrpCapacity.java @@ -0,0 +1,198 @@ +// Copyright 2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// [START program] +// [START import] +import com.google.ortools.constraintsolver.Assignment; +import com.google.ortools.constraintsolver.FirstSolutionStrategy; +import com.google.ortools.constraintsolver.LongLongToLong; +import com.google.ortools.constraintsolver.LongToLong; +import com.google.ortools.constraintsolver.RoutingDimension; +import com.google.ortools.constraintsolver.RoutingIndexManager; +import com.google.ortools.constraintsolver.RoutingModel; +import com.google.ortools.constraintsolver.RoutingDimension; +import com.google.ortools.constraintsolver.RoutingSearchParameters; +import com.google.ortools.constraintsolver.main; +import java.util.logging.Logger; +// [END import] + +/** Minimal VRP.*/ +public class VrpCapacity { + static { System.loadLibrary("jniortools"); } + + private static final Logger logger = Logger.getLogger(VrpCapacity.class.getName()); + + // [START data_model] + static class DataModel { + public DataModel() { + distanceMatrix = new long[][] { + {0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662}, + {548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210}, + {776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754}, + {696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358}, + {582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244}, + {274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708}, + {502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480}, + {194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856}, + {308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514}, + {194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468}, + {536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354}, + {502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844}, + {388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730}, + {354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536}, + {468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194}, + {776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798}, + {662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0}, + }; + demands = new long[] {0, 1, 1, 2, 4, 2, 4, 8, 8, 1, 2, 1, 2, 4, 4, 8, 8}; + vehicleNumber = 4; + vehicleCapacities = new long[] {15, 15, 15, 15}; + depot = 0; + } + public final long[][] distanceMatrix; + public final long[] demands; + public final int vehicleNumber; + public final long[] vehicleCapacities; + public final int depot; + } + // [END data_model] + + // [START manhattan_distance] + /// @brief Manhattan distance implemented as a transit callback. + /// @details It uses an array of positions and computes + /// the Manhattan distance between the two positions of + /// two different indices. + static class ManhattanDistance extends LongLongToLong { + public ManhattanDistance(DataModel data, RoutingIndexManager manager) { + // precompute distance between location to have distance callback in O(1) + distanceMatrix_ = data.distanceMatrix; + indexManager_ = manager; + } + @Override + public long run(long fromIndex, long toIndex) { + int fromNode = indexManager_.indexToNode(fromIndex); + int toNode = indexManager_.indexToNode(toIndex); + return distanceMatrix_[fromNode][toNode]; + } + private long[][] distanceMatrix_; + private RoutingIndexManager indexManager_; + } + // [END manhattan_distance] + + + // [START demands] + static class DemandCallback extends LongToLong { + public DemandCallback(DataModel data, RoutingIndexManager manager) { + // precompute distance between location to have distance callback in O(1) + demands_ = data.demands; + indexManager_ = manager; + } + @Override + public long run(long fromIndex) { + int fromNode = indexManager_.indexToNode(fromIndex); + return demands_[fromNode]; + } + private long[] demands_; + private RoutingIndexManager indexManager_; + } + // [END demands] + + // [START solution_printer] + /// @brief Print the solution. + static void printSolution( + DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) { + // Solution cost. + logger.info("Objective : " + solution.objectiveValue()); + // Inspect solution. + long totalDistance = 0; + long totalLoad = 0; + for (int i = 0; i < data.vehicleNumber; ++i) { + long index = routing.start(i); + logger.info("Route for Vehicle " + i + ":"); + long routeDistance = 0; + long routeLoad = 0; + String route = ""; + while (!routing.isEnd(index)) { + long nodeIndex = manager.indexToNode(index); + routeLoad += data.demands[(int) nodeIndex]; + route += nodeIndex + " Load(" + routeLoad + ") -> "; + long previousIndex = index; + index = solution.value(routing.nextVar(index)); + routeDistance += routing.getArcCostForVehicle(previousIndex, index, i); + } + route += manager.indexToNode(routing.end(i)); + logger.info(route); + logger.info("Distance of the route: " + routeDistance + "m"); + totalDistance += routeDistance; + totalLoad += routeLoad; + } + logger.info("Total Distance of all routes: " + totalDistance + "m"); + logger.info("Total Load of all routes: " + totalLoad); + } + // [END solution_printer] + + public static void main(String[] args) throws Exception { + // Instantiate the data problem. + // [START data] + final DataModel data = new DataModel(); + // [END data] + + // Create Routing Index Manager + // [START index_manager] + RoutingIndexManager manager = + new RoutingIndexManager(data.distanceMatrix.length, data.vehicleNumber, data.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] + LongLongToLong distanceEvaluator = new ManhattanDistance(data, manager); + int transitCostIndex = routing.registerTransitCallback(distanceEvaluator); + routing.setArcCostEvaluatorOfAllVehicles(transitCostIndex); + // [END arc_cost] + + // Add Capacity constraint. + // [START capacity_constraint] + LongToLong demandEvaluator = new DemandCallback(data, manager); + int demandCostIndex = routing.registerUnaryTransitCallback(demandEvaluator); + routing.addDimensionWithVehicleCapacity( + demandCostIndex, 0, // null capacity slack + data.vehicleCapacities, // vehicle maximum capacities + true, // start cumul to zero + "Capacity"); + // [END capacity_constraint] + + // Setting first solution heuristic. + // [START parameters] + RoutingSearchParameters searchParameters = + main.defaultRoutingSearchParameters() + .toBuilder() + .setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC) + .build(); + // [END parameters] + + // Solve the problem. + // [START solve] + Assignment solution = routing.solveWithParameters(searchParameters); + // [END solve] + + // Print solution on console. + // [START print_solution] + printSolution(data, routing, manager, solution); + // [END print_solution] + } +} +// [END program]