Add Java samples

This commit is contained in:
Corentin Le Molgat
2019-01-09 11:28:14 +01:00
parent 5827eadbcc
commit 38c03c4df6
11 changed files with 1294 additions and 224 deletions

View 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);
}
}

View File

@@ -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: \

View File

@@ -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());

View File

@@ -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]

View 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]

View File

@@ -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]

View File

@@ -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;

View 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]

View 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]

View 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]

View 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]