Files

190 lines
6.1 KiB
Java
Raw Permalink Normal View History

2025-01-10 11:35:44 +01:00
// Copyright 2010-2025 Google LLC
2012-05-02 20:00:03 +00:00
// 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.
2019-01-09 11:28:14 +01:00
// [START program]
2020-05-26 09:30:42 +02:00
package com.google.ortools.constraintsolver.samples;
2019-01-09 11:28:14 +01:00
// [START import]
import static java.lang.Math.abs;
2019-01-10 10:53:01 +01:00
import com.google.ortools.Loader;
2012-05-02 20:00:03 +00:00
import com.google.ortools.constraintsolver.Assignment;
2019-03-12 14:51:01 +01:00
import com.google.ortools.constraintsolver.FirstSolutionStrategy;
dotnet: Remove reference to dotnet release command - Currently not implemented... Add abseil patch - Add patches/absl-config.cmake Makefile: Add abseil-cpp on unix - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake Makefile: Add abseil-cpp on windows - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake CMake: Add abseil-cpp - Force abseil-cpp SHA1 to 45221cc note: Just before the PR #136 which break all CMake port to absl: C++ Part - Fix warning with the use of ABSL_MUST_USE_RESULT > The macro must appear as the very first part of a function declaration or definition: ... Note: past advice was to place the macro after the argument list. src: dependencies/sources/abseil-cpp-master/absl/base/attributes.h:418 - Rename enum after windows clash - Remove non compact table constraints - Change index type from int64 to int in routing library - Fix file_nonport compilation on windows - Fix another naming conflict with windows (NO_ERROR is a macro) - Cleanup hash containers; work on sat internals - Add optional_boolean sub-proto Sync cpp examples with internal code - reenable issue173 after reducing number of loops port to absl: Python Part - Add back cp_model.INT32_MIN|MAX for examples Update Python examples - Add random_tsp.py - Run words_square example - Run magic_square in python tests port to absl: Java Part - Fix compilation of the new routing parameters in java - Protect some code from SWIG parsing Update Java Examples port to absl: .Net Part Update .Net examples work on sat internals; Add C++ CP-SAT CpModelBuilder API; update sample code and recipes to use the new API; sync with internal code Remove VS 2015 in Appveyor-CI - abseil-cpp does not support VS 2015... improve tables upgrade C++ sat examples to use the new API; work on sat internals update license dates rewrite jobshop_ft06_distance.py to use the CP-SAT solver rename last example revert last commit more work on SAT internals fix
2018-10-31 16:18:18 +01:00
import com.google.ortools.constraintsolver.RoutingIndexManager;
import com.google.ortools.constraintsolver.RoutingModel;
2019-02-18 15:27:32 +01:00
import com.google.ortools.constraintsolver.RoutingSearchParameters;
import com.google.ortools.constraintsolver.RoutingSearchStatus;
2019-03-12 14:51:01 +01:00
import com.google.ortools.constraintsolver.main;
import java.util.function.LongBinaryOperator;
2019-01-09 11:28:14 +01:00
import java.util.logging.Logger;
2019-01-09 11:28:14 +01:00
// [END import]
2012-05-02 20:00:03 +00:00
/** Minimal TSP. */
2019-01-09 11:28:14 +01:00
public class Tsp {
private static final Logger logger = Logger.getLogger(Tsp.class.getName());
// [START data_model]
static class DataModel {
2019-02-18 15:27:32 +01:00
public final int[][] locations = {
{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},
};
public final int vehicleNumber = 1;
public final int depot = 0;
2019-01-09 11:28:14 +01:00
public DataModel() {
// Convert locations in meters using a city block dimension of 114m x 80m.
2019-01-10 10:53:01 +01:00
for (int[] element : locations) {
element[0] *= 114;
element[1] *= 80;
2019-01-09 11:28:14 +01:00
}
}
2018-11-10 23:56:52 +01:00
}
2019-01-09 11:28:14 +01:00
// [END data_model]
2012-05-02 20:00:03 +00:00
2019-01-09 11:28:14 +01:00
// [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 implements LongBinaryOperator {
2019-01-09 11:28:14 +01:00
public ManhattanDistance(DataModel data, RoutingIndexManager manager) {
// precompute distance between location to have distance callback in O(1)
2019-01-11 16:49:07 +01:00
distanceMatrix = new long[data.locations.length][data.locations.length];
indexManager = manager;
2019-01-09 11:28:14 +01:00
for (int fromNode = 0; fromNode < data.locations.length; ++fromNode) {
for (int toNode = 0; toNode < data.locations.length; ++toNode) {
if (fromNode == toNode) {
2019-01-11 16:49:07 +01:00
distanceMatrix[fromNode][toNode] = 0;
2019-01-09 11:28:14 +01:00
} else {
2019-01-11 16:49:07 +01:00
distanceMatrix[fromNode][toNode] =
2019-01-09 11:28:14 +01:00
(long) abs(data.locations[toNode][0] - data.locations[fromNode][0])
+ (long) abs(data.locations[toNode][1] - data.locations[fromNode][1]);
}
}
2012-05-02 20:00:03 +00:00
}
}
2019-02-18 15:27:32 +01:00
@Override
public long applyAsLong(long fromIndex, long toIndex) {
2019-01-11 16:49:07 +01:00
// Convert from routing variable Index to distance matrix NodeIndex.
int fromNode = indexManager.indexToNode(fromIndex);
int toNode = indexManager.indexToNode(toIndex);
return distanceMatrix[fromNode][toNode];
2012-05-02 20:00:03 +00:00
}
2019-01-11 16:49:07 +01:00
private final long[][] distanceMatrix;
private final RoutingIndexManager indexManager;
2012-05-02 20:00:03 +00:00
}
2019-01-09 11:28:14 +01:00
// [END manhattan_distance]
2012-05-02 20:00:03 +00:00
2019-01-09 11:28:14 +01:00
// [START solution_printer]
/// @brief Print the solution.
static void printSolution(
RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
RoutingSearchStatus.Value status = routing.status();
logger.info("Status: " + status);
if (status != RoutingSearchStatus.Value.ROUTING_OPTIMAL
&& status != RoutingSearchStatus.Value.ROUTING_SUCCESS) {
logger.warning("No solution found!");
return;
}
2019-01-09 11:28:14 +01:00
// 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);
2012-05-02 20:00:03 +00:00
}
2019-01-09 11:28:14 +01:00
route += manager.indexToNode(routing.end(0));
logger.info(route);
logger.info("Distance of the route: " + routeDistance + "m");
2012-05-02 20:00:03 +00:00
}
2019-01-09 11:28:14 +01:00
// [END solution_printer]
2012-05-02 20:00:03 +00:00
2019-01-09 11:28:14 +01:00
public static void main(String[] args) throws Exception {
Loader.loadNativeLibraries();
2019-01-09 11:28:14 +01:00
// Instantiate the data problem.
// [START data]
final DataModel data = new DataModel();
// [END data]
2012-05-02 20:00:03 +00:00
2019-01-09 11:28:14 +01:00
// Create Routing Index Manager
// [START index_manager]
RoutingIndexManager manager =
new RoutingIndexManager(data.locations.length, data.vehicleNumber, data.depot);
// [END index_manager]
2012-05-02 20:00:03 +00:00
2019-01-09 11:28:14 +01:00
// Create Routing Model.
// [START routing_model]
RoutingModel routing = new RoutingModel(manager);
// [END routing_model]
2012-05-02 20:00:03 +00:00
// Create and register a transit callback.
// [START transit_callback]
2019-02-18 15:27:32 +01:00
final int transitCallbackIndex =
routing.registerTransitCallback(new ManhattanDistance(data, manager));
// [END transit_callback]
2019-01-09 11:28:14 +01:00
// Define cost of each arc.
// [START arc_cost]
2019-01-11 12:03:44 +01:00
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
2019-01-09 11:28:14 +01:00
// [END arc_cost]
2012-05-02 20:00:03 +00:00
2019-01-09 11:28:14 +01:00
// Setting first solution heuristic.
// [START parameters]
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
2018-11-10 23:56:52 +01:00
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
2018-11-10 23:43:32 +01:00
.build();
2019-01-09 11:28:14 +01:00
// [END parameters]
2019-01-09 11:28:14 +01:00
// Solve the problem.
// [START solve]
Assignment solution = routing.solveWithParameters(searchParameters);
// [END solve]
2012-05-02 20:00:03 +00:00
2019-01-09 11:28:14 +01:00
// Print solution on console.
// [START print_solution]
printSolution(routing, manager, solution);
2019-01-09 11:28:14 +01:00
// [END print_solution]
2012-05-02 20:00:03 +00:00
}
}
2019-01-09 11:28:14 +01:00
// [END program]