Add Java samples
This commit is contained in:
136
examples/java/RandomTsp.java
Normal file
136
examples/java/RandomTsp.java
Normal file
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// Copyright 2010-2017 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.
|
||||
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.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
class RandomTsp {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
|
||||
static class RandomManhattan extends LongLongToLong {
|
||||
public RandomManhattan(RoutingIndexManager manager, int size, int seed) {
|
||||
this.xs = new int[size];
|
||||
this.ys = new int[size];
|
||||
this.indexManager = manager;
|
||||
Random generator = new Random(seed);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
xs[i] = generator.nextInt(1000);
|
||||
ys[i] = generator.nextInt(1000);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long run(long firstIndex, long secondIndex) {
|
||||
int firstNode = indexManager.indexToNode(firstIndex);
|
||||
int secondNode = indexManager.indexToNode(secondIndex);
|
||||
return Math.abs(xs[firstNode] - xs[secondNode]) + Math.abs(ys[firstNode] - ys[secondNode]);
|
||||
}
|
||||
|
||||
private int[] xs;
|
||||
private int[] ys;
|
||||
private RoutingIndexManager indexManager;
|
||||
}
|
||||
|
||||
static class ConstantCallback extends LongToLong {
|
||||
@Override
|
||||
public long run(long index) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
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, int64, int64>.
|
||||
// The two arguments are the from and to node inidices.
|
||||
LongLongToLong distances = new RandomManhattan(manager, size, seed);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(routing.registerTransitCallback(distances));
|
||||
|
||||
// Forbid node connections (randomly).
|
||||
Random randomizer = new Random();
|
||||
long forbidden_connections = 0;
|
||||
while (forbidden_connections < forbidden) {
|
||||
long from = randomizer.nextInt(size - 1);
|
||||
long to = randomizer.nextInt(size - 1) + 1;
|
||||
if (routing.nextVar(from).contains(to)) {
|
||||
System.out.println("Forbidding connection " + from + " -> " + to);
|
||||
routing.nextVar(from).removeValue(to);
|
||||
++forbidden_connections;
|
||||
}
|
||||
}
|
||||
|
||||
// Add dummy dimension to test API.
|
||||
routing.addDimension(
|
||||
routing.registerUnaryTransitCallback(new ConstantCallback()),
|
||||
size + 1,
|
||||
size + 1,
|
||||
true,
|
||||
"dummy");
|
||||
|
||||
// Solve, returns a solution if any (owned by RoutingModel).
|
||||
RoutingSearchParameters search_parameters =
|
||||
RoutingSearchParameters.newBuilder()
|
||||
.mergeFrom(main.defaultRoutingSearchParameters())
|
||||
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
|
||||
.build();
|
||||
|
||||
Assignment solution = routing.solveWithParameters(search_parameters);
|
||||
if (solution != null) {
|
||||
// Solution cost.
|
||||
System.out.println("Cost = " + 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))) {
|
||||
System.out.print("" + node + " -> ");
|
||||
}
|
||||
System.out.println("0");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int size = 10;
|
||||
if (args.length > 0) {
|
||||
size = Integer.parseInt(args[0]);
|
||||
}
|
||||
|
||||
int forbidden = 0;
|
||||
if (args.length > 1) {
|
||||
forbidden = Integer.parseInt(args[1]);
|
||||
}
|
||||
|
||||
int seed = 0;
|
||||
if (args.length > 2) {
|
||||
seed = Integer.parseInt(args[2]);
|
||||
}
|
||||
|
||||
solve(size, forbidden, seed);
|
||||
}
|
||||
}
|
||||
@@ -375,8 +375,13 @@ test_java_algorithms_samples: \
|
||||
test_java_constraint_solver_samples: \
|
||||
rjava_SimpleRoutingProgram \
|
||||
rjava_Tsp \
|
||||
rjava_TspDistanceMatrix \
|
||||
rjava_Vrp \
|
||||
rjava_VrpCapacity \
|
||||
rjava_VrpDropNodes \
|
||||
rjava_VrpGlobalSpan \
|
||||
rjava_VrpStartsEnds \
|
||||
rjava_VrpTimeWindows \
|
||||
|
||||
.PHONY: test_java_graph_samples # Build and Run all Java Graph Samples (located in ortools/graph/samples)
|
||||
test_java_graph_samples: \
|
||||
@@ -477,8 +482,7 @@ test_java_java: \
|
||||
rjava_LinearProgramming \
|
||||
rjava_LsApi \
|
||||
rjava_RabbitsPheasants \
|
||||
rjava_Tsp \
|
||||
rjava_Vrp
|
||||
rjava_RandomTsp
|
||||
|
||||
.PHONY: test_java_pimpl
|
||||
test_java_pimpl: \
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
// [START program]
|
||||
// [START import]
|
||||
import java.util.logging.Logger;
|
||||
import com.google.ortools.constraintsolver.Assignment;
|
||||
import com.google.ortools.constraintsolver.FirstSolutionStrategy;
|
||||
import com.google.ortools.constraintsolver.LongLongToLong;
|
||||
@@ -21,12 +20,11 @@ import com.google.ortools.constraintsolver.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
class SimpleRoutingProgram {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
static { System.loadLibrary("jniortools");}
|
||||
|
||||
private static Logger logger =
|
||||
Logger.getLogger(SimpleRoutingProgram.class.getName());
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
//
|
||||
// Copyright 2010-2017 Google LLC
|
||||
//
|
||||
// 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
|
||||
@@ -12,125 +10,161 @@
|
||||
// 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 static java.lang.Math.abs;
|
||||
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.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
class Tsp {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
/** Minimal TSP.*/
|
||||
public class Tsp {
|
||||
static { System.loadLibrary("jniortools"); }
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Tsp.class.getName());
|
||||
|
||||
// [START data_model]
|
||||
static class DataModel {
|
||||
public DataModel() {
|
||||
locations = new int[][] {
|
||||
{4, 4},
|
||||
{2, 0},
|
||||
{8, 0},
|
||||
{0, 1},
|
||||
{1, 1},
|
||||
{5, 2},
|
||||
{7, 2},
|
||||
{3, 3},
|
||||
{6, 3},
|
||||
{5, 5},
|
||||
{8, 5},
|
||||
{1, 6},
|
||||
{2, 6},
|
||||
{3, 7},
|
||||
{6, 7},
|
||||
{0, 8},
|
||||
{7, 8},
|
||||
};
|
||||
// Convert locations in meters using a city block dimension of 114m x 80m.
|
||||
for (int i = 0; i < locations.length; i++) {
|
||||
locations[i][0] *= 114;
|
||||
locations[i][1] *= 80;
|
||||
}
|
||||
vehicleNumber = 1;
|
||||
depot = 0;
|
||||
}
|
||||
public final int[][] locations;
|
||||
public final int vehicleNumber;
|
||||
public final int depot;
|
||||
}
|
||||
// [END data_model]
|
||||
|
||||
static class RandomManhattan extends LongLongToLong {
|
||||
public RandomManhattan(RoutingIndexManager manager, int size, int seed) {
|
||||
this.xs = new int[size];
|
||||
this.ys = new int[size];
|
||||
this.indexManager = manager;
|
||||
Random generator = new Random(seed);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
xs[i] = generator.nextInt(1000);
|
||||
ys[i] = generator.nextInt(1000);
|
||||
// [START manhattan_distance]
|
||||
/// @brief Manhattan distance implemented as a 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_ = new long[data.locations.length][data.locations.length];
|
||||
indexManager_ = manager;
|
||||
for (int fromNode = 0; fromNode < data.locations.length; ++fromNode) {
|
||||
for (int toNode = 0; toNode < data.locations.length; ++toNode) {
|
||||
if (fromNode == toNode) {
|
||||
distanceMatrix_[fromNode][toNode] = 0;
|
||||
} else {
|
||||
distanceMatrix_[fromNode][toNode] =
|
||||
(long) abs(data.locations[toNode][0] - data.locations[fromNode][0])
|
||||
+ (long) abs(data.locations[toNode][1] - data.locations[fromNode][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long run(long firstIndex, long secondIndex) {
|
||||
int firstNode = indexManager.indexToNode(firstIndex);
|
||||
int secondNode = indexManager.indexToNode(secondIndex);
|
||||
return Math.abs(xs[firstNode] - xs[secondNode]) + Math.abs(ys[firstNode] - ys[secondNode]);
|
||||
public long run(long fromIndex, long toIndex) {
|
||||
int fromNode = indexManager_.indexToNode(fromIndex);
|
||||
int toNode = indexManager_.indexToNode(toIndex);
|
||||
return distanceMatrix_[fromNode][toNode];
|
||||
}
|
||||
|
||||
private int[] xs;
|
||||
private int[] ys;
|
||||
private RoutingIndexManager indexManager;
|
||||
private long[][] distanceMatrix_;
|
||||
private RoutingIndexManager indexManager_;
|
||||
}
|
||||
// [END manhattan_distance]
|
||||
|
||||
static class ConstantCallback extends LongToLong {
|
||||
@Override
|
||||
public long run(long index) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
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, int64, int64>.
|
||||
// The two arguments are the from and to node inidices.
|
||||
LongLongToLong distances = new RandomManhattan(manager, size, seed);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(routing.registerTransitCallback(distances));
|
||||
|
||||
// Forbid node connections (randomly).
|
||||
Random randomizer = new Random();
|
||||
long forbidden_connections = 0;
|
||||
while (forbidden_connections < forbidden) {
|
||||
long from = randomizer.nextInt(size - 1);
|
||||
long to = randomizer.nextInt(size - 1) + 1;
|
||||
if (routing.nextVar(from).contains(to)) {
|
||||
System.out.println("Forbidding connection " + from + " -> " + to);
|
||||
routing.nextVar(from).removeValue(to);
|
||||
++forbidden_connections;
|
||||
}
|
||||
}
|
||||
|
||||
// Add dummy dimension to test API.
|
||||
routing.addDimension(
|
||||
routing.registerUnaryTransitCallback(new ConstantCallback()),
|
||||
size + 1,
|
||||
size + 1,
|
||||
true,
|
||||
"dummy");
|
||||
|
||||
// Solve, returns a solution if any (owned by RoutingModel).
|
||||
RoutingSearchParameters search_parameters =
|
||||
RoutingSearchParameters.newBuilder()
|
||||
.mergeFrom(main.defaultRoutingSearchParameters())
|
||||
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
|
||||
.build();
|
||||
|
||||
Assignment solution = routing.solveWithParameters(search_parameters);
|
||||
if (solution != null) {
|
||||
// Solution cost.
|
||||
System.out.println("Cost = " + 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))) {
|
||||
System.out.print("" + node + " -> ");
|
||||
}
|
||||
System.out.println("0");
|
||||
// [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.
|
||||
logger.info("Route for Vehicle 0:");
|
||||
long routeDistance = 0;
|
||||
String route = "";
|
||||
long index = routing.start(0);
|
||||
while (!routing.isEnd(index)) {
|
||||
route += manager.indexToNode(index) + " -> ";
|
||||
long previousIndex = index;
|
||||
index = solution.value(routing.nextVar(index));
|
||||
routeDistance += routing.getArcCostForVehicle(previousIndex, index, 0);
|
||||
}
|
||||
route += manager.indexToNode(routing.end(0));
|
||||
logger.info(route);
|
||||
logger.info("Distance of the route: " + routeDistance + "m");
|
||||
}
|
||||
// [END solution_printer]
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int size = 10;
|
||||
if (args.length > 0) {
|
||||
size = Integer.parseInt(args[0]);
|
||||
}
|
||||
// Instantiate the data problem.
|
||||
// [START data]
|
||||
final DataModel data = new DataModel();
|
||||
// [END data]
|
||||
|
||||
int forbidden = 0;
|
||||
if (args.length > 1) {
|
||||
forbidden = Integer.parseInt(args[1]);
|
||||
}
|
||||
// Create Routing Index Manager
|
||||
// [START index_manager]
|
||||
RoutingIndexManager manager =
|
||||
new RoutingIndexManager(data.locations.length, data.vehicleNumber, data.depot);
|
||||
// [END index_manager]
|
||||
|
||||
int seed = 0;
|
||||
if (args.length > 2) {
|
||||
seed = Integer.parseInt(args[2]);
|
||||
}
|
||||
// Create Routing Model.
|
||||
// [START routing_model]
|
||||
RoutingModel routing = new RoutingModel(manager);
|
||||
// [END routing_model]
|
||||
|
||||
solve(size, forbidden, seed);
|
||||
// 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]
|
||||
|
||||
// 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]
|
||||
|
||||
152
ortools/constraint_solver/samples/TspDistanceMatrix.java
Normal file
152
ortools/constraint_solver/samples/TspDistanceMatrix.java
Normal file
@@ -0,0 +1,152 @@
|
||||
// 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.FirstSolutionStrategy;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.Assignment;
|
||||
import com.google.ortools.constraintsolver.LongLongToLong;
|
||||
import com.google.ortools.constraintsolver.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
/** Minimal TSP using distance matrix.*/
|
||||
public class TspDistanceMatrix {
|
||||
static { System.loadLibrary("jniortools"); }
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TspDistanceMatrix.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},
|
||||
};
|
||||
vehicleNumber = 1;
|
||||
depot = 0;
|
||||
}
|
||||
public final long[][] distanceMatrix;
|
||||
public final int vehicleNumber;
|
||||
public final int depot;
|
||||
}
|
||||
// [END data_model]
|
||||
|
||||
// [START manhattan_distance]
|
||||
/// @brief Manhattan distance implemented as a 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 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.
|
||||
logger.info("Route for Vehicle 0:");
|
||||
long routeDistance = 0;
|
||||
String route = "";
|
||||
long index = routing.start(0);
|
||||
while (!routing.isEnd(index)) {
|
||||
route += manager.indexToNode(index) + " -> ";
|
||||
long previousIndex = index;
|
||||
index = solution.value(routing.nextVar(index));
|
||||
routeDistance += routing.getArcCostForVehicle(previousIndex, index, 0);
|
||||
}
|
||||
route += manager.indexToNode(routing.end(0));
|
||||
logger.info(route);
|
||||
logger.info("Distance of the route: " + routeDistance + "m");
|
||||
}
|
||||
// [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]
|
||||
|
||||
// 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]
|
||||
@@ -10,161 +10,148 @@
|
||||
// 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.
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
// [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.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.io.*;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
class DataProblem {
|
||||
private int[][] locations_;
|
||||
/** Minimal VRP.*/
|
||||
public class Vrp {
|
||||
static { System.loadLibrary("jniortools"); }
|
||||
|
||||
public DataProblem() {
|
||||
locations_ =
|
||||
new int[][] {
|
||||
{4, 4}, {2, 0}, {8, 0}, {0, 1}, {1, 1}, {5, 2}, {7, 2}, {3, 3}, {6, 3}, {5, 5}, {8, 5},
|
||||
{1, 6}, {2, 6}, {3, 7}, {6, 7}, {0, 8}, {7, 8}
|
||||
};
|
||||
private static final Logger logger = Logger.getLogger(Vrp.class.getName());
|
||||
|
||||
// Compute locations in meters using the block dimension defined as follow
|
||||
// Manhattan average block: 750ft x 264ft -> 228m x 80m
|
||||
// here we use: 114m x 80m city block
|
||||
// src: https://nyti.ms/2GDoRIe "NY Times: Know Your distance"
|
||||
int[] cityBlock = {228 / 2, 80};
|
||||
for (int i = 0; i < locations_.length; i++) {
|
||||
locations_[i][0] = locations_[i][0] * cityBlock[0];
|
||||
locations_[i][1] = locations_[i][1] * cityBlock[1];
|
||||
// [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},
|
||||
};
|
||||
vehicleNumber = 4;
|
||||
depot = 0;
|
||||
}
|
||||
public final long[][] distanceMatrix;
|
||||
public final int vehicleNumber;
|
||||
public final int depot;
|
||||
}
|
||||
// [END data_model]
|
||||
|
||||
/// @brief Gets the number of vehicles.
|
||||
public int getVehicleNumber() {
|
||||
return 4;
|
||||
}
|
||||
/// @brief Gets the locations.
|
||||
public int[][] getLocations() {
|
||||
return locations_;
|
||||
}
|
||||
/// @brief Gets the number of locations.
|
||||
public int getLocationNumber() {
|
||||
return locations_.length;
|
||||
}
|
||||
/// @brief Gets the depot NodeIndex.
|
||||
public int getDepot() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Manhattan distance implemented as a callback.
|
||||
/// @details It uses an array of positions and computes
|
||||
/// the Manhattan distance between the two positions of
|
||||
/// two different indices.
|
||||
class ManhattanDistance extends LongLongToLong {
|
||||
private int[][] distances;
|
||||
private RoutingIndexManager indexManager;
|
||||
|
||||
public ManhattanDistance(DataProblem data, RoutingIndexManager manager) {
|
||||
// precompute distance between location to have distance callback in O(1)
|
||||
distances = new int[data.getLocationNumber()][data.getLocationNumber()];
|
||||
indexManager = manager;
|
||||
for (int fromNode = 0; fromNode < data.getLocationNumber(); ++fromNode) {
|
||||
for (int toNode = 0; toNode < data.getLocationNumber(); ++toNode) {
|
||||
if (fromNode == toNode) distances[fromNode][toNode] = 0;
|
||||
else
|
||||
distances[fromNode][toNode] =
|
||||
abs(data.getLocations()[toNode][0] - data.getLocations()[fromNode][0])
|
||||
+ abs(data.getLocations()[toNode][1] - data.getLocations()[fromNode][1]);
|
||||
}
|
||||
// [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]
|
||||
|
||||
@Override
|
||||
/// @brief Returns the manhattan distance between the two nodes.
|
||||
public long run(long fromIndex, long toIndex) {
|
||||
int fromNode = indexManager.indexToNode(fromIndex);
|
||||
int toNode = indexManager.indexToNode(toIndex);
|
||||
return distances[fromNode][toNode];
|
||||
}
|
||||
}
|
||||
|
||||
class Vrp {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
|
||||
/// @brief Add Global Span constraint.
|
||||
static void addDistanceDimension(RoutingModel routing, DataProblem data, int distanceIndex) {
|
||||
String distance = "Distance";
|
||||
routing.addDimension(
|
||||
distanceIndex,
|
||||
0, // null slack
|
||||
3000, // maximum distance per vehicle
|
||||
true, // start cumul to zero
|
||||
distance);
|
||||
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);
|
||||
}
|
||||
|
||||
/// @brief Print the solution
|
||||
// [START solution_printer]
|
||||
/// @brief Print the solution.
|
||||
static void printSolution(
|
||||
DataProblem data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
|
||||
DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
|
||||
// Solution cost.
|
||||
System.out.println("Objective : " + solution.objectiveValue());
|
||||
logger.info("Objective : " + solution.objectiveValue());
|
||||
// Inspect solution.
|
||||
for (int i = 0; i < data.getVehicleNumber(); ++i) {
|
||||
System.out.println("Route for Vehicle " + i + ":");
|
||||
long distance = 0;
|
||||
for (long index = routing.start(i); !routing.isEnd(index); ) {
|
||||
System.out.print(manager.indexToNode((int) index) + " -> ");
|
||||
|
||||
long totalDistance = 0;
|
||||
for (int i = 0; i < data.vehicleNumber; ++i) {
|
||||
logger.info("Route for Vehicle " + i + ":");
|
||||
long routeDistance = 0;
|
||||
String route = "";
|
||||
long index = routing.start(i);
|
||||
while (!routing.isEnd(index)) {
|
||||
route += manager.indexToNode(index) + " -> ";
|
||||
long previousIndex = index;
|
||||
index = solution.value(routing.nextVar(index));
|
||||
distance += routing.getArcCostForVehicle(previousIndex, index, i);
|
||||
routeDistance += routing.getArcCostForVehicle(previousIndex, index, i);
|
||||
}
|
||||
System.out.println(manager.indexToNode((int) routing.end(i)));
|
||||
System.out.println("Distance of the route: " + distance + "m");
|
||||
route += manager.indexToNode(routing.end(i));
|
||||
logger.info(route);
|
||||
logger.info("Distance of the route: " + routeDistance + "m");
|
||||
totalDistance += routeDistance;
|
||||
}
|
||||
logger.info("Total Distance of all routes: " + totalDistance + "m");
|
||||
}
|
||||
// [END solution_printer]
|
||||
|
||||
/// @brief Solves the current routing problem.
|
||||
static void solve() {
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Instantiate the data problem.
|
||||
DataProblem data = new DataProblem();
|
||||
// [START data]
|
||||
final DataModel data = new DataModel();
|
||||
// [END data]
|
||||
|
||||
// Create Routing Model
|
||||
// Create Routing Index Manager
|
||||
// [START index_manager]
|
||||
RoutingIndexManager manager =
|
||||
new RoutingIndexManager(data.getLocationNumber(), data.getVehicleNumber(), data.getDepot());
|
||||
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]
|
||||
|
||||
// Setting the cost function.
|
||||
// [todo]: protect callback from the GC
|
||||
// Define cost of each arc.
|
||||
// [START arc_cost]
|
||||
LongLongToLong distanceEvaluator = new ManhattanDistance(data, manager);
|
||||
int distanceIndex = routing.registerTransitCallback(distanceEvaluator);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(distanceIndex);
|
||||
addDistanceDimension(routing, data, distanceIndex);
|
||||
int transitCostIndex = routing.registerTransitCallback(distanceEvaluator);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(transitCostIndex);
|
||||
// [END arc_cost]
|
||||
|
||||
// Setting first solution heuristic (cheapest addition).
|
||||
RoutingSearchParameters search_parameters =
|
||||
RoutingSearchParameters.newBuilder()
|
||||
.mergeFrom(main.defaultRoutingSearchParameters())
|
||||
// Setting first solution heuristic.
|
||||
// [START parameters]
|
||||
RoutingSearchParameters searchParameters =
|
||||
main.defaultRoutingSearchParameters()
|
||||
.toBuilder()
|
||||
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
|
||||
.build();
|
||||
// [END parameters]
|
||||
|
||||
Assignment solution = routing.solveWithParameters(search_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);
|
||||
}
|
||||
|
||||
/// @brief Entry point of the program.
|
||||
public static void main(String[] args) throws Exception {
|
||||
solve();
|
||||
// [END print_solution]
|
||||
}
|
||||
}
|
||||
// [END program]
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
// 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;
|
||||
|
||||
213
ortools/constraint_solver/samples/VrpDropNodes.java
Normal file
213
ortools/constraint_solver/samples/VrpDropNodes.java
Normal file
@@ -0,0 +1,213 @@
|
||||
// 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.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
/** Minimal VRP.*/
|
||||
public class VrpDropNodes {
|
||||
static { System.loadLibrary("jniortools"); }
|
||||
|
||||
private static final Logger logger = Logger.getLogger(VrpDropNodes.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, 3, 6, 3, 6, 8, 8, 1, 2, 1, 2, 6, 6, 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());
|
||||
// Display dropped nodes.
|
||||
String droppedNodes = "Dropped nodes:";
|
||||
for (int node = 0; node < routing.size(); ++node) {
|
||||
if (routing.isStart(node) || routing.isEnd(node)) {
|
||||
continue;
|
||||
}
|
||||
if (solution.value(routing.nextVar(node)) == node) {
|
||||
droppedNodes += " " + manager.indexToNode(node);
|
||||
}
|
||||
}
|
||||
logger.info(droppedNodes);
|
||||
// Display routes
|
||||
// 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");
|
||||
// Allow to drop nodes.
|
||||
long penalty = 1000;
|
||||
for (int i = 1; i < data.distanceMatrix.length; ++i) {
|
||||
routing.addDisjunction(
|
||||
new long[] {manager.nodeToIndex(i)}, penalty);
|
||||
}
|
||||
// [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]
|
||||
170
ortools/constraint_solver/samples/VrpGlobalSpan.java
Normal file
170
ortools/constraint_solver/samples/VrpGlobalSpan.java
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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.RoutingDimension;
|
||||
import com.google.ortools.constraintsolver.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
/** Minimal VRP.*/
|
||||
public class VrpGlobalSpan {
|
||||
static { System.loadLibrary("jniortools"); }
|
||||
|
||||
private static final Logger logger = Logger.getLogger(VrpGlobalSpan.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 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;
|
||||
for (int i = 0; i < data.vehicleNumber; ++i) {
|
||||
long index = routing.start(i);
|
||||
logger.info("Route for Vehicle " + i + ":");
|
||||
long routeDistance = 0;
|
||||
String route = "";
|
||||
while (!routing.isEnd(index)) {
|
||||
route += manager.indexToNode(index) + " -> ";
|
||||
long previousIndex = index;
|
||||
index = solution.value(routing.nextVar(index));
|
||||
routeDistance += routing.getArcCostForVehicle(previousIndex, index, i);
|
||||
}
|
||||
logger.info(route + manager.indexToNode(index));
|
||||
logger.info("Distance of the route: " + routeDistance + "m");
|
||||
totalDistance += routeDistance;
|
||||
}
|
||||
logger.info("Total Distance of all routes: " + totalDistance + "m");
|
||||
}
|
||||
// [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 Distance constraint.
|
||||
// [START distance_constraint]
|
||||
routing.addDimension(transitCostIndex, 0, 3000,
|
||||
true, // start cumul to zero
|
||||
"Distance");
|
||||
RoutingDimension distanceDimension = routing.getMutableDimension("Distance");
|
||||
distanceDimension.setGlobalSpanCostCoefficient(100);
|
||||
// [END distance_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]
|
||||
170
ortools/constraint_solver/samples/VrpStartsEnds.java
Normal file
170
ortools/constraint_solver/samples/VrpStartsEnds.java
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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.RoutingDimension;
|
||||
import com.google.ortools.constraintsolver.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
/** Minimal VRP.*/
|
||||
public class VrpStartsEnds {
|
||||
static { System.loadLibrary("jniortools"); }
|
||||
|
||||
private static final Logger logger = Logger.getLogger(VrpStartsEnds.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},
|
||||
};
|
||||
vehicleNumber = 4;
|
||||
starts = new int[] {1, 2, 15, 16};
|
||||
ends = new int[] {0, 0, 0, 0};
|
||||
}
|
||||
public final long[][] distanceMatrix;
|
||||
public final int vehicleNumber;
|
||||
public final int[] starts;
|
||||
public final int[] ends;
|
||||
}
|
||||
// [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 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;
|
||||
for (int i = 0; i < data.vehicleNumber; ++i) {
|
||||
logger.info("Route for Vehicle " + i + ":");
|
||||
long routeDistance = 0;
|
||||
String route = "";
|
||||
long index = routing.start(i);
|
||||
while (!routing.isEnd(index)) {
|
||||
route += manager.indexToNode(index) + " -> ";
|
||||
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;
|
||||
}
|
||||
logger.info("Total Distance of all routes: " + totalDistance + "m");
|
||||
}
|
||||
// [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.starts, data.ends);
|
||||
// [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 Distance constraint.
|
||||
// [START distance_constraint]
|
||||
routing.addDimension(transitCostIndex, 0, 2000,
|
||||
true, // start cumul to zero
|
||||
"Distance");
|
||||
RoutingDimension distanceDimension = routing.getMutableDimension("Distance");
|
||||
distanceDimension.setGlobalSpanCostCoefficient(100);
|
||||
// [END distance_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]
|
||||
205
ortools/constraint_solver/samples/VrpTimeWindows.java
Normal file
205
ortools/constraint_solver/samples/VrpTimeWindows.java
Normal file
@@ -0,0 +1,205 @@
|
||||
// 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.IntVar;
|
||||
import com.google.ortools.constraintsolver.LongLongToLong;
|
||||
import com.google.ortools.constraintsolver.RoutingDimension;
|
||||
import com.google.ortools.constraintsolver.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.util.logging.Logger;
|
||||
// [END import]
|
||||
|
||||
/** Minimal VRP.*/
|
||||
public class VrpTimeWindows {
|
||||
static { System.loadLibrary("jniortools"); }
|
||||
|
||||
private static final Logger logger = Logger.getLogger(VrpTimeWindows.class.getName());
|
||||
|
||||
// [START data_model]
|
||||
static class DataModel {
|
||||
public DataModel() {
|
||||
timeMatrix = new long[][] {
|
||||
{0, 6, 9, 8, 7, 3, 6, 2, 3, 2, 6, 6, 4, 4, 5, 9, 7},
|
||||
{6, 0, 8, 3, 2, 6, 8, 4, 8, 8, 13, 7, 5, 8, 12, 10, 14},
|
||||
{9, 8, 0, 11, 10, 6, 3, 9, 5, 8, 4, 15, 14, 13, 9, 18, 9},
|
||||
{8, 3, 11, 0, 1, 7, 10, 6, 10, 10, 14, 6, 7, 9, 14, 6, 16},
|
||||
{7, 2, 10, 1, 0, 6, 9, 4, 8, 9, 13, 4, 6, 8, 12, 8, 14},
|
||||
{3, 6, 6, 7, 6, 0, 2, 3, 2, 2, 7, 9, 7, 7, 6, 12, 8},
|
||||
{6, 8, 3, 10, 9, 2, 0, 6, 2, 5, 4, 12, 10, 10, 6, 15, 5},
|
||||
{2, 4, 9, 6, 4, 3, 6, 0, 4, 4, 8, 5, 4, 3, 7, 8, 10},
|
||||
{3, 8, 5, 10, 8, 2, 2, 4, 0, 3, 4, 9, 8, 7, 3, 13, 6},
|
||||
{2, 8, 8, 10, 9, 2, 5, 4, 3, 0, 4, 6, 5, 4, 3, 9, 5},
|
||||
{6, 13, 4, 14, 13, 7, 4, 8, 4, 4, 0, 10, 9, 8, 4, 13, 4},
|
||||
{6, 7, 15, 6, 4, 9, 12, 5, 9, 6, 10, 0, 1, 3, 7, 3, 10},
|
||||
{4, 5, 14, 7, 6, 7, 10, 4, 8, 5, 9, 1, 0, 2, 6, 4, 8},
|
||||
{4, 8, 13, 9, 8, 7, 10, 3, 7, 4, 8, 3, 2, 0, 4, 5, 6},
|
||||
{5, 12, 9, 14, 12, 6, 6, 7, 3, 3, 4, 7, 6, 4, 0, 9, 2},
|
||||
{9, 10, 18, 6, 8, 12, 15, 8, 13, 9, 13, 3, 4, 5, 9, 0, 9},
|
||||
{7, 14, 9, 16, 14, 8, 5, 10, 6, 5, 4, 10, 8, 6, 2, 9, 0},
|
||||
};
|
||||
timeWindows = new long[][] {
|
||||
{0, 0},
|
||||
{10, 15},
|
||||
{10, 15},
|
||||
{5, 10},
|
||||
{5, 10},
|
||||
{0, 5},
|
||||
{5, 10},
|
||||
{0, 5},
|
||||
{5, 10},
|
||||
{0, 5},
|
||||
{10, 15},
|
||||
{10, 15},
|
||||
{0, 5},
|
||||
{5, 10},
|
||||
{5, 10},
|
||||
{10, 15},
|
||||
{5, 10},
|
||||
};
|
||||
vehicleNumber = 4;
|
||||
depot = 0;
|
||||
}
|
||||
public final long[][] timeMatrix;
|
||||
public final long[][] timeWindows;
|
||||
public final int vehicleNumber;
|
||||
public final int depot;
|
||||
}
|
||||
// [END data_model]
|
||||
|
||||
// [START times]
|
||||
static class TimeCallback extends LongLongToLong {
|
||||
public TimeCallback(DataModel data, RoutingIndexManager manager) {
|
||||
// precompute distance between location to have distance callback in O(1)
|
||||
timeMatrix_ = data.timeMatrix;
|
||||
indexManager_ = manager;
|
||||
}
|
||||
@Override
|
||||
public long run(long fromIndex, long toIndex) {
|
||||
int fromNode = indexManager_.indexToNode(fromIndex);
|
||||
int toNode = indexManager_.indexToNode(toIndex);
|
||||
return timeMatrix_[fromNode][toNode];
|
||||
}
|
||||
private long[][] timeMatrix_;
|
||||
private RoutingIndexManager indexManager_;
|
||||
}
|
||||
// [END times]
|
||||
|
||||
// [START solution_printer]
|
||||
/// @brief Print the solution.
|
||||
static void printSolution(
|
||||
DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
|
||||
logger.info("Objective : " + solution.objectiveValue());
|
||||
RoutingDimension timeDimension = routing.getMutableDimension("Time");
|
||||
long totalTime = 0;
|
||||
for (int i = 0; i < data.vehicleNumber; ++i) {
|
||||
long index = routing.start(i);
|
||||
logger.info("Route for Vehicle " + i + ":");
|
||||
long routeTime = 0;
|
||||
String route = "";
|
||||
while (!routing.isEnd(index)) {
|
||||
IntVar timeVar = timeDimension.cumulVar(index);
|
||||
IntVar slackVar = timeDimension.slackVar(index);
|
||||
route += manager.indexToNode(index) + " Time(" + solution.min(timeVar) + ","
|
||||
+ solution.max(timeVar) + ") Slack(" + solution.min(slackVar) + ","
|
||||
+ solution.max(slackVar) + ") -> ";
|
||||
long previousIndex = index;
|
||||
index = solution.value(routing.nextVar(index));
|
||||
routeTime += routing.getArcCostForVehicle(previousIndex, index, i);
|
||||
}
|
||||
IntVar timeVar = timeDimension.cumulVar(index);
|
||||
route += manager.indexToNode(index) + " Time(" + solution.min(timeVar) + ","
|
||||
+ solution.max(timeVar) + ")";
|
||||
logger.info(route);
|
||||
logger.info("Time of the route: " + routeTime + "m");
|
||||
totalTime += routeTime;
|
||||
}
|
||||
logger.info("Total Time of all routes: " + totalTime + "m");
|
||||
}
|
||||
// [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.timeMatrix.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 timeCallback = new TimeCallback(data, manager);
|
||||
int transitCostIndex = routing.registerTransitCallback(timeCallback);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(transitCostIndex);
|
||||
// [END arc_cost]
|
||||
|
||||
// Add Time constraint.
|
||||
// [START time_constraint]
|
||||
routing.addDimension(transitCostIndex, // transit callback
|
||||
30, // allow waiting time
|
||||
30, // vehicle maximum capacities
|
||||
false, // start cumul to zero
|
||||
"Time");
|
||||
RoutingDimension timeDimension = routing.getMutableDimension("Time");
|
||||
// Add time window constraints for each location except depot
|
||||
// and 'copy' the slack var in the solution object (aka Assignment) to print it
|
||||
for (int i = 1; i < data.timeWindows.length; ++i) {
|
||||
long index = manager.nodeToIndex(i);
|
||||
timeDimension.cumulVar(index).setRange(data.timeWindows[i][0], data.timeWindows[i][1]);
|
||||
routing.addToAssignment(timeDimension.slackVar(index));
|
||||
}
|
||||
// Add time window constraints for each vehicle start node
|
||||
// and 'copy' the slack var in the solution object (aka Assignment) to print
|
||||
// it
|
||||
for (int i = 0; i < data.vehicleNumber; ++i) {
|
||||
long index = routing.start(i);
|
||||
timeDimension.cumulVar(index).setRange(data.timeWindows[0][0], data.timeWindows[0][1]);
|
||||
routing.addToAssignment(timeDimension.slackVar(index));
|
||||
}
|
||||
// [END time_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]
|
||||
Reference in New Issue
Block a user