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
This commit is contained in:
@@ -13,12 +13,15 @@
|
||||
// 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.IntVar;
|
||||
import com.google.ortools.constraintsolver.NodeEvaluator2;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.FirstSolutionStrategy;
|
||||
import com.google.ortools.constraintsolver.IntIntToLong;
|
||||
import com.google.ortools.constraintsolver.IntToLong;
|
||||
import com.google.ortools.constraintsolver.IntVar;
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
@@ -41,12 +44,11 @@ class Pair<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample showing how to model and solve a capacitated vehicle routing problem
|
||||
* with time windows using the swig-wrapped version of the vehicle routing
|
||||
* library in src/constraint_solver.
|
||||
* Sample showing how to model and solve a capacitated vehicle routing problem with time windows
|
||||
* using the swig-wrapped version of the vehicle routing library in src/constraint_solver.
|
||||
*/
|
||||
|
||||
public class CapacitatedVehicleRoutingProblemWithTimeWindows {
|
||||
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
@@ -60,8 +62,6 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows {
|
||||
|
||||
// Quantity to be picked up for each order.
|
||||
private List<Integer> orderDemands = new ArrayList();
|
||||
// Time duration spent to deliver each order.
|
||||
private List<Integer> orderDurations = new ArrayList();
|
||||
// Time window in which each order must be performed.
|
||||
private List<Pair<Integer, Integer>> orderTimeWindows = new ArrayList();
|
||||
// Penalty cost "paid" for dropping an order.
|
||||
@@ -69,8 +69,6 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows {
|
||||
|
||||
// Capacity of the vehicles.
|
||||
private int vehicleCapacity = 0;
|
||||
// Earliest time at which each vehicle must start its tour.
|
||||
private List<Integer> vehicleStartTime = new ArrayList();
|
||||
// Latest time at which each vehicle must end its tour.
|
||||
private List<Integer> vehicleEndTime = new ArrayList();
|
||||
// Cost per unit of distance of each vehicle.
|
||||
@@ -84,53 +82,76 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows {
|
||||
private final Random randomGenerator = new Random(0xBEEF);
|
||||
|
||||
/**
|
||||
* Constructs a capacitated vehicle routing problem with time windows.
|
||||
* Creates a Manhattan Distance evaluator with 'costCoefficient'.
|
||||
*
|
||||
* @param manager Node Index Manager.
|
||||
* @param costCoefficient The coefficient to apply to the evaluator.
|
||||
*/
|
||||
private CapacitatedVehicleRoutingProblemWithTimeWindows() {}
|
||||
private IntIntToLong buildManhattanCallback(RoutingIndexManager manager, int costCoefficient) {
|
||||
return new IntIntToLong() {
|
||||
@Override
|
||||
public long run(int firstIndex, int secondIndex) {
|
||||
try {
|
||||
int firstNode = manager.indexToNode(firstIndex);
|
||||
int secondNode = manager.indexToNode(secondIndex);
|
||||
Pair<Integer, Integer> firstLocation = locations.get(firstNode);
|
||||
Pair<Integer, Integer> secondLocation = locations.get(secondNode);
|
||||
return (long) costCoefficient
|
||||
* (Math.abs(firstLocation.first - secondLocation.first)
|
||||
+ Math.abs(firstLocation.second - secondLocation.second));
|
||||
} catch (Throwable throwed) {
|
||||
logger.warning(throwed.getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates order data. Location of the order is random, as well as its
|
||||
* demand (quantity), time window and penalty.
|
||||
* Creates order data. Location of the order is random, as well as its demand (quantity), time
|
||||
* window and penalty.
|
||||
*
|
||||
* @param numberOfOrders number of orders to build.
|
||||
* @param xMax maximum x coordinate in which orders are located.
|
||||
* @param yMax maximum y coordinate in which orders are located.
|
||||
* @param demandMax maximum quantity of a demand.
|
||||
* @param timeWindowMin minimum starting time of the order time window.
|
||||
* @param timeWindowMax maximum starting time of the order time window.
|
||||
* @param timeWindowWidth duration of the order time window.
|
||||
* @param penaltyMin minimum pernalty cost if order is dropped.
|
||||
* @param penaltyMax maximum pernalty cost if order is dropped.
|
||||
*/
|
||||
private void buildOrders(int numberOfOrders, int xMax, int yMax, int demandMax, int timeWindowMin,
|
||||
int timeWindowMax, int timeWindowWidth, int penaltyMin, int penaltyMax) {
|
||||
private void buildOrders(
|
||||
int numberOfOrders,
|
||||
int xMax,
|
||||
int yMax,
|
||||
int demandMax,
|
||||
int timeWindowMax,
|
||||
int timeWindowWidth,
|
||||
int penaltyMin,
|
||||
int penaltyMax) {
|
||||
logger.info("Building orders.");
|
||||
for (int order = 0; order < numberOfOrders; ++order) {
|
||||
locations.add(Pair.of(randomGenerator.nextInt(xMax + 1), randomGenerator.nextInt(yMax + 1)));
|
||||
orderDemands.add(randomGenerator.nextInt(demandMax + 1));
|
||||
/** @todo 1) Specify deliver duration for each shipment*/
|
||||
orderDurations.add(2); // in minutes
|
||||
int timeWindowStart = randomGenerator.nextInt(timeWindowMax - timeWindowMin) + timeWindowMin;
|
||||
int timeWindowStart = randomGenerator.nextInt(timeWindowMax + 1);
|
||||
orderTimeWindows.add(Pair.of(timeWindowStart, timeWindowStart + timeWindowWidth));
|
||||
orderPenalties.add(randomGenerator.nextInt(penaltyMax - penaltyMin + 1) + penaltyMin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates fleet data. Vehicle starting and ending locations are random, as
|
||||
* well as vehicle costs per distance unit.
|
||||
* Creates fleet data. Vehicle starting and ending locations are random, as well as vehicle costs
|
||||
* per distance unit.
|
||||
*
|
||||
* @param numberOfVehicles
|
||||
* @param xMax maximum x coordinate in which orders are located.
|
||||
* @param yMax maximum y coordinate in which orders are located.
|
||||
* @param startTime earliest start time of a tour of a vehicle.
|
||||
* @param endTime latest end time of a tour of a vehicle.
|
||||
* @param capacity capacity of a vehicle.
|
||||
* @param costCoefficientMax maximum cost per distance unit of a vehicle
|
||||
* (mimimum is 1),
|
||||
* @param costCoefficientMax maximum cost per distance unit of a vehicle (mimimum is 1),
|
||||
*/
|
||||
private void buildFleet(int numberOfVehicles, int xMax, int yMax, int startTime, int endTime,
|
||||
int capacity, int costCoefficientMax) {
|
||||
private void buildFleet(
|
||||
int numberOfVehicles, int xMax, int yMax, int endTime, int capacity, int costCoefficientMax) {
|
||||
logger.info("Building fleet.");
|
||||
vehicleCapacity = capacity;
|
||||
vehicleStarts = new int[numberOfVehicles];
|
||||
@@ -140,101 +161,75 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows {
|
||||
locations.add(Pair.of(randomGenerator.nextInt(xMax + 1), randomGenerator.nextInt(yMax + 1)));
|
||||
vehicleEnds[vehicle] = locations.size();
|
||||
locations.add(Pair.of(randomGenerator.nextInt(xMax + 1), randomGenerator.nextInt(yMax + 1)));
|
||||
vehicleStartTime.add(startTime);
|
||||
vehicleEndTime.add(endTime);
|
||||
vehicleCostCoefficients.add(randomGenerator.nextInt(costCoefficientMax) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves the current routing problem.
|
||||
*/
|
||||
/** Solves the current routing problem. */
|
||||
private void solve(final int numberOfOrders, final int numberOfVehicles) {
|
||||
logger.info(
|
||||
"Creating model with " + numberOfOrders + " orders and " + numberOfVehicles + " vehicles.");
|
||||
// Finalizing model
|
||||
final int numberOfLocations = locations.size();
|
||||
|
||||
RoutingModel model =
|
||||
new RoutingModel(numberOfLocations, numberOfVehicles, vehicleStarts, vehicleEnds);
|
||||
RoutingIndexManager manager =
|
||||
new RoutingIndexManager(numberOfLocations, numberOfVehicles, vehicleStarts, vehicleEnds);
|
||||
RoutingModel model = new RoutingModel(manager);
|
||||
|
||||
// Setting up dimensions
|
||||
final int bigNumber = 100000;
|
||||
NodeEvaluator2 timeCallback = new NodeEvaluator2() {
|
||||
@Override
|
||||
public long run(int firstIndex, int secondIndex) {
|
||||
try {
|
||||
Pair<Integer, Integer> firstLocation = locations.get(firstIndex);
|
||||
Pair<Integer, Integer> secondLocation = locations.get(secondIndex);
|
||||
Integer distance = 0;
|
||||
Integer duration = 0;
|
||||
distance = Math.abs(firstLocation.first - secondLocation.first)
|
||||
+ Math.abs(firstLocation.second - secondLocation.second);
|
||||
// Deal with Order duration shipment
|
||||
if (firstIndex < numberOfOrders) {
|
||||
// shipment duration
|
||||
duration += orderDurations.get(firstIndex);
|
||||
final IntIntToLong callback = buildManhattanCallback(manager, 1);
|
||||
final String timeStr = "time";
|
||||
model.addDimension(
|
||||
model.registerTransitCallback(callback), bigNumber, bigNumber, false, timeStr);
|
||||
RoutingDimension timeDimension = model.getMutableDimension(timeStr);
|
||||
|
||||
IntToLong demandCallback =
|
||||
new IntToLong() {
|
||||
@Override
|
||||
public long run(int index) {
|
||||
try {
|
||||
int node = manager.indexToNode(index);
|
||||
if (node < numberOfOrders) {
|
||||
return orderDemands.get(node);
|
||||
}
|
||||
return 0;
|
||||
} catch (Throwable throwed) {
|
||||
logger.warning(throwed.getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return distance + duration;
|
||||
} catch (Throwable throwed) {
|
||||
logger.warning(throwed.getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
model.addDimension(timeCallback, bigNumber, bigNumber, false, "time");
|
||||
NodeEvaluator2 demandCallback = new NodeEvaluator2() {
|
||||
@Override
|
||||
public long run(int firstIndex, int secondIndex) {
|
||||
try {
|
||||
if (firstIndex < numberOfOrders) {
|
||||
return orderDemands.get(firstIndex);
|
||||
}
|
||||
return 0;
|
||||
} catch (Throwable throwed) {
|
||||
logger.warning(throwed.getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
model.addDimension(demandCallback, 0, vehicleCapacity, true, "capacity");
|
||||
};
|
||||
final String capacityStr = "capacity";
|
||||
model.addDimension(
|
||||
model.registerUnaryTransitCallback(demandCallback), 0, vehicleCapacity, true, capacityStr);
|
||||
RoutingDimension capacityDimension = model.getMutableDimension(capacityStr);
|
||||
|
||||
// Setting up vehicles
|
||||
IntIntToLong[] callbacks = new IntIntToLong[numberOfVehicles];
|
||||
for (int vehicle = 0; vehicle < numberOfVehicles; ++vehicle) {
|
||||
final int costCoefficient = vehicleCostCoefficients.get(vehicle);
|
||||
NodeEvaluator2 manhattanCostCallback = new NodeEvaluator2() {
|
||||
@Override
|
||||
public long run(int firstIndex, int secondIndex) {
|
||||
try {
|
||||
Pair<Integer, Integer> firstLocation = locations.get(firstIndex);
|
||||
Pair<Integer, Integer> secondLocation = locations.get(secondIndex);
|
||||
return costCoefficient
|
||||
* (Math.abs(firstLocation.first - secondLocation.first)
|
||||
+ Math.abs(firstLocation.second - secondLocation.second));
|
||||
} catch (Throwable throwed) {
|
||||
logger.warning(throwed.getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
model.setArcCostEvaluatorOfVehicle(manhattanCostCallback, vehicle);
|
||||
model.cumulVar(model.start(vehicle), "time").setMin(vehicleStartTime.get(vehicle));
|
||||
model.cumulVar(model.end(vehicle), "time").setMax(vehicleEndTime.get(vehicle));
|
||||
callbacks[vehicle] = buildManhattanCallback(manager, costCoefficient);
|
||||
final int vehicleCost = model.registerTransitCallback(callbacks[vehicle]);
|
||||
model.setArcCostEvaluatorOfVehicle(vehicleCost, vehicle);
|
||||
timeDimension.cumulVar(model.end(vehicle)).setMax(vehicleEndTime.get(vehicle));
|
||||
}
|
||||
|
||||
// Setting up orders
|
||||
for (int order = 0; order < numberOfOrders; ++order) {
|
||||
model.cumulVar(model.nodeToIndex(order), "time")
|
||||
timeDimension
|
||||
.cumulVar(order)
|
||||
.setRange(orderTimeWindows.get(order).first, orderTimeWindows.get(order).second);
|
||||
int[] orders = {order};
|
||||
model.addDisjunction(orders, orderPenalties.get(order));
|
||||
long[] orderIndices = {manager.nodeToIndex(order)};
|
||||
model.addDisjunction(orderIndices, orderPenalties.get(order));
|
||||
}
|
||||
|
||||
// Solving
|
||||
RoutingSearchParameters parameters =
|
||||
RoutingSearchParameters.newBuilder()
|
||||
.mergeFrom(RoutingModel.defaultSearchParameters())
|
||||
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
|
||||
main.defaultRoutingSearchParameters()
|
||||
.toBuilder()
|
||||
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.ALL_UNPERFORMED)
|
||||
.build();
|
||||
|
||||
logger.info("Search");
|
||||
@@ -258,25 +253,38 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows {
|
||||
long order = model.start(vehicle);
|
||||
// Empty route has a minimum of two nodes: Start => End
|
||||
if (model.isEnd(solution.value(model.nextVar(order)))) {
|
||||
route += "/!\\Empty Route/!\\ ";
|
||||
}
|
||||
{
|
||||
route += "Empty";
|
||||
} else {
|
||||
for (; !model.isEnd(order); order = solution.value(model.nextVar(order))) {
|
||||
IntVar load = model.cumulVar(order, "capacity");
|
||||
IntVar time = model.cumulVar(order, "time");
|
||||
route += order + " Load(" + solution.value(load) + ") "
|
||||
+ "Time(" + solution.min(time) + ", " + solution.max(time) + ") -> ";
|
||||
IntVar load = capacityDimension.cumulVar(order);
|
||||
IntVar time = timeDimension.cumulVar(order);
|
||||
route +=
|
||||
order
|
||||
+ " Load("
|
||||
+ solution.value(load)
|
||||
+ ") "
|
||||
+ "Time("
|
||||
+ solution.min(time)
|
||||
+ ", "
|
||||
+ solution.max(time)
|
||||
+ ") -> ";
|
||||
}
|
||||
IntVar load = model.cumulVar(order, "capacity");
|
||||
IntVar time = model.cumulVar(order, "time");
|
||||
route += order + " Load(" + solution.value(load) + ") "
|
||||
+ "Time(" + solution.min(time) + ", " + solution.max(time) + ")";
|
||||
IntVar load = capacityDimension.cumulVar(order);
|
||||
IntVar time = timeDimension.cumulVar(order);
|
||||
route +=
|
||||
order
|
||||
+ " Load("
|
||||
+ solution.value(load)
|
||||
+ ") "
|
||||
+ "Time("
|
||||
+ solution.min(time)
|
||||
+ ", "
|
||||
+ solution.max(time)
|
||||
+ ")";
|
||||
}
|
||||
output += route + "\n";
|
||||
}
|
||||
logger.info(output);
|
||||
} else {
|
||||
logger.info("No solution Found !");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,24 +294,20 @@ public class CapacitatedVehicleRoutingProblemWithTimeWindows {
|
||||
final int xMax = 20;
|
||||
final int yMax = 20;
|
||||
final int demandMax = 3;
|
||||
final int timeWindowMin = 8 * 60;
|
||||
final int timeWindowMax = 17 * 60;
|
||||
final int timeWindowMax = 24 * 60;
|
||||
final int timeWindowWidth = 4 * 60;
|
||||
final int penaltyMin = 50;
|
||||
final int penaltyMax = 100;
|
||||
/** @todo Specify vehicle start time*/
|
||||
final int startTime = 8 * 60;
|
||||
/** @todo Specify vehicle end time*/
|
||||
final int endTime = 17 * 60;
|
||||
final int endTime = 24 * 60;
|
||||
final int costCoefficientMax = 3;
|
||||
|
||||
final int orders = 100;
|
||||
final int vehicles = 20;
|
||||
final int capacity = 50;
|
||||
|
||||
problem.buildOrders(orders, xMax, yMax, demandMax, timeWindowMin, timeWindowMax,
|
||||
timeWindowWidth, penaltyMin, penaltyMax);
|
||||
problem.buildFleet(vehicles, xMax, yMax, startTime, endTime, capacity, costCoefficientMax);
|
||||
problem.buildOrders(
|
||||
orders, xMax, yMax, demandMax, timeWindowMax, timeWindowWidth, penaltyMin, penaltyMax);
|
||||
problem.buildFleet(vehicles, xMax, yMax, endTime, capacity, costCoefficientMax);
|
||||
problem.solve(orders, vehicles);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,9 @@
|
||||
import com.google.ortools.graph.MaxFlow;
|
||||
import com.google.ortools.graph.MinCostFlow;
|
||||
|
||||
/**
|
||||
* Sample showing how to model using the flow solver.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Sample showing how to model using the flow solver. */
|
||||
public class FlowExample {
|
||||
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
@@ -29,7 +26,11 @@ public class FlowExample {
|
||||
final int numSources = 4;
|
||||
final int numTargets = 4;
|
||||
final int[][] costs = {
|
||||
{90, 75, 75, 80}, {35, 85, 55, 65}, {125, 95, 90, 105}, {45, 110, 95, 115}};
|
||||
{90, 75, 75, 80},
|
||||
{35, 85, 55, 65},
|
||||
{125, 95, 90, 105},
|
||||
{45, 110, 95, 115}
|
||||
};
|
||||
final int expectedCost = 275;
|
||||
MinCostFlow minCostFlow = new MinCostFlow();
|
||||
for (int source = 0; source < numSources; ++source) {
|
||||
@@ -47,8 +48,13 @@ public class FlowExample {
|
||||
System.out.println("total flow = " + totalFlowCost + "/" + expectedCost);
|
||||
for (int i = 0; i < minCostFlow.getNumArcs(); ++i) {
|
||||
if (minCostFlow.getFlow(i) > 0) {
|
||||
System.out.println("From source " + minCostFlow.getTail(i) + " to target "
|
||||
+ minCostFlow.getHead(i) + ": cost " + minCostFlow.getUnitCost(i));
|
||||
System.out.println(
|
||||
"From source "
|
||||
+ minCostFlow.getTail(i)
|
||||
+ " to target "
|
||||
+ minCostFlow.getHead(i)
|
||||
+ ": cost "
|
||||
+ minCostFlow.getUnitCost(i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -69,8 +75,15 @@ public class FlowExample {
|
||||
if (maxFlow.solve(0, 5) == MaxFlow.Status.OPTIMAL) {
|
||||
System.out.println("Total flow " + maxFlow.getOptimalFlow() + "/" + expectedTotalFlow);
|
||||
for (int i = 0; i < maxFlow.getNumArcs(); ++i) {
|
||||
System.out.println("From source " + maxFlow.getTail(i) + " to target " + maxFlow.getHead(i)
|
||||
+ ": " + maxFlow.getFlow(i) + " / " + maxFlow.getCapacity(i));
|
||||
System.out.println(
|
||||
"From source "
|
||||
+ maxFlow.getTail(i)
|
||||
+ " to target "
|
||||
+ maxFlow.getHead(i)
|
||||
+ ": "
|
||||
+ maxFlow.getFlow(i)
|
||||
+ " / "
|
||||
+ maxFlow.getCapacity(i));
|
||||
}
|
||||
// TODO(user): Our SWIG configuration does not currently handle these
|
||||
// functions correctly in Java:
|
||||
|
||||
@@ -16,11 +16,7 @@ import com.google.ortools.linearsolver.MPObjective;
|
||||
import com.google.ortools.linearsolver.MPSolver;
|
||||
import com.google.ortools.linearsolver.MPVariable;
|
||||
|
||||
/**
|
||||
* Integer programming example that shows how to use the API.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Integer programming example that shows how to use the API. */
|
||||
public class IntegerProgramming {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
@@ -67,9 +63,10 @@ public class IntegerProgramming {
|
||||
|
||||
// Verify that the solution satisfies all constraints (when using solvers
|
||||
// others than GLOP_LINEAR_PROGRAMMING, this is highly recommended!).
|
||||
if (!solver.verifySolution(/*tolerance=*/1e-7, /*logErrors=*/true)) {
|
||||
System.err.println("The solution returned by the solver violated the"
|
||||
+ " problem constraints by at least 1e-7");
|
||||
if (!solver.verifySolution(/*tolerance=*/ 1e-7, /*logErrors=*/ true)) {
|
||||
System.err.println(
|
||||
"The solution returned by the solver violated the"
|
||||
+ " problem constraints by at least 1e-7");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,26 +13,35 @@
|
||||
|
||||
import com.google.ortools.algorithms.KnapsackSolver;
|
||||
|
||||
/**
|
||||
* Sample showing how to model using the knapsack solver.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Sample showing how to model using the knapsack solver. */
|
||||
public class Knapsack {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
|
||||
private static void solve() {
|
||||
KnapsackSolver solver = new KnapsackSolver(
|
||||
KnapsackSolver.SolverType.KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, "test");
|
||||
final long[] profits = {360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147,
|
||||
78, 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28, 87, 73, 78, 15, 26,
|
||||
78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276, 312};
|
||||
KnapsackSolver solver =
|
||||
new KnapsackSolver(
|
||||
KnapsackSolver.SolverType.KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, "test");
|
||||
final long[] profits = {
|
||||
360, 83, 59, 130, 431, 67, 230, 52, 93,
|
||||
125, 670, 892, 600, 38, 48, 147, 78, 256,
|
||||
63, 17, 120, 164, 432, 35, 92, 110, 22,
|
||||
42, 50, 323, 514, 28, 87, 73, 78, 15,
|
||||
26, 78, 210, 36, 85, 189, 274, 43, 33,
|
||||
10, 19, 389, 276, 312
|
||||
};
|
||||
|
||||
final long[][] weights = {{7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, 42, 9,
|
||||
0, 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, 7, 29, 93, 44, 71, 3, 86, 66, 31,
|
||||
65, 0, 79, 20, 65, 52, 13}};
|
||||
final long[][] weights = {
|
||||
{
|
||||
7, 0, 30, 22, 80, 94, 11, 81, 70,
|
||||
64, 59, 18, 0, 36, 3, 8, 15, 42,
|
||||
9, 0, 42, 47, 52, 32, 26, 48, 55,
|
||||
6, 29, 84, 2, 4, 18, 56, 7, 29,
|
||||
93, 44, 71, 3, 86, 66, 31, 65, 0,
|
||||
79, 20, 65, 52, 13
|
||||
}
|
||||
};
|
||||
|
||||
final long[] capacities = {850};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2010-2018 Google LLC
|
||||
// Copyright 2010-2017 Google
|
||||
// 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
|
||||
@@ -15,21 +15,25 @@ import com.google.ortools.graph.LinearSumAssignment;
|
||||
|
||||
/**
|
||||
* Test assignment on a 4x4 matrix. Example taken from
|
||||
* http://www.ee.oulu.fi/~mpa/matreng/eem1_2-1.htm with kCost[0][1]
|
||||
* modified so the optimum solution is unique.
|
||||
*
|
||||
* http://www.ee.oulu.fi/~mpa/matreng/eem1_2-1.htm with kCost[0][1] modified so the optimum solution
|
||||
* is unique.
|
||||
*/
|
||||
|
||||
public class LinearAssignmentAPI {
|
||||
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
|
||||
|
||||
private static void runAssignmentOn4x4Matrix() {
|
||||
final int numSources = 4;
|
||||
final int numTargets = 4;
|
||||
final int[][] cost = {
|
||||
{90, 76, 75, 80}, {35, 85, 55, 65}, {125, 95, 90, 105}, {45, 110, 95, 115}};
|
||||
{90, 76, 75, 80},
|
||||
{35, 85, 55, 65},
|
||||
{125, 95, 90, 105},
|
||||
{45, 110, 95, 115}
|
||||
};
|
||||
final int expectedCost = cost[0][3] + cost[1][2] + cost[2][1] + cost[3][0];
|
||||
|
||||
LinearSumAssignment assignment = new LinearSumAssignment();
|
||||
@@ -42,8 +46,13 @@ public class LinearAssignmentAPI {
|
||||
if (assignment.solve() == LinearSumAssignment.Status.OPTIMAL) {
|
||||
System.out.println("Total cost = " + assignment.getOptimalCost() + "/" + expectedCost);
|
||||
for (int node = 0; node < assignment.getNumNodes(); ++node) {
|
||||
System.out.println("Left node " + node + " assigned to right node "
|
||||
+ assignment.getRightMate(node) + " with cost " + assignment.getAssignmentCost(node));
|
||||
System.out.println(
|
||||
"Left node "
|
||||
+ node
|
||||
+ " assigned to right node "
|
||||
+ assignment.getRightMate(node)
|
||||
+ " with cost "
|
||||
+ assignment.getAssignmentCost(node));
|
||||
}
|
||||
} else {
|
||||
System.out.println("No solution found.");
|
||||
|
||||
@@ -16,11 +16,7 @@ import com.google.ortools.linearsolver.MPObjective;
|
||||
import com.google.ortools.linearsolver.MPSolver;
|
||||
import com.google.ortools.linearsolver.MPVariable;
|
||||
|
||||
/**
|
||||
* Linear programming example that shows how to use the API.
|
||||
*
|
||||
*/
|
||||
|
||||
/** Linear programming example that shows how to use the API. */
|
||||
public class LinearProgramming {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
@@ -90,9 +86,10 @@ public class LinearProgramming {
|
||||
|
||||
// Verify that the solution satisfies all constraints (when using solvers
|
||||
// others than GLOP_LINEAR_PROGRAMMING, this is highly recommended!).
|
||||
if (!solver.verifySolution(/*tolerance=*/1e-7, /*logErrors=*/true)) {
|
||||
System.err.println("The solution returned by the solver violated the"
|
||||
+ " problem constraints by at least 1e-7");
|
||||
if (!solver.verifySolution(/*tolerance=*/ 1e-7, /*logErrors=*/ true)) {
|
||||
System.err.println(
|
||||
"The solution returned by the solver violated the"
|
||||
+ " problem constraints by at least 1e-7");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,7 @@ import com.google.ortools.constraintsolver.SearchMonitor;
|
||||
import com.google.ortools.constraintsolver.SolutionCollector;
|
||||
import com.google.ortools.constraintsolver.Solver;
|
||||
|
||||
/**
|
||||
* Sample showing how to model using the constraint programming solver.
|
||||
*
|
||||
*/
|
||||
/** Sample showing how to model using the constraint programming solver. */
|
||||
public class LsApi {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
|
||||
@@ -14,13 +14,9 @@ import com.google.ortools.constraintsolver.ConstraintSolverParameters;
|
||||
import com.google.ortools.constraintsolver.DecisionBuilder;
|
||||
import com.google.ortools.constraintsolver.IntVar;
|
||||
import com.google.ortools.constraintsolver.Solver;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Sample showing how to model using the constraint programming solver.
|
||||
*
|
||||
*/
|
||||
/** Sample showing how to model using the constraint programming solver. */
|
||||
public class RabbitsPheasants {
|
||||
private static Logger logger = Logger.getLogger(RabbitsPheasants.class.getName());
|
||||
|
||||
@@ -29,9 +25,8 @@ public class RabbitsPheasants {
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves the rabbits + pheasants problem. We are seing 20 heads
|
||||
* and 56 legs. How many rabbits and how many pheasants are we thus
|
||||
* seeing?
|
||||
* Solves the rabbits + pheasants problem. We are seing 20 heads and 56 legs. How many rabbits and
|
||||
* how many pheasants are we thus seeing?
|
||||
*/
|
||||
private static void solve(boolean traceSearch) {
|
||||
ConstraintSolverParameters parameters = ConstraintSolverParameters.newBuilder()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 2012 Google
|
||||
// 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.
|
||||
@@ -12,25 +12,28 @@
|
||||
// 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 java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
import com.google.ortools.constraintsolver.Assignment;
|
||||
import com.google.ortools.constraintsolver.NodeEvaluator2;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.FirstSolutionStrategy;
|
||||
import com.google.ortools.constraintsolver.IntIntToLong;
|
||||
import com.google.ortools.constraintsolver.IntToLong;
|
||||
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 Tsp {
|
||||
static {
|
||||
System.loadLibrary("jniortools");
|
||||
}
|
||||
|
||||
static class RandomManhattan extends NodeEvaluator2 {
|
||||
public RandomManhattan(int size, int seed) {
|
||||
static class RandomManhattan extends IntIntToLong {
|
||||
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);
|
||||
@@ -40,30 +43,33 @@ class Tsp {
|
||||
|
||||
@Override
|
||||
public long run(int firstIndex, int secondIndex) {
|
||||
return Math.abs(xs[firstIndex] - xs[secondIndex])
|
||||
+ Math.abs(ys[firstIndex] - ys[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 NodeEvaluator2 {
|
||||
static class ConstantCallback extends IntToLong {
|
||||
@Override
|
||||
public long run(int firstIndex, int secondIndex) {
|
||||
public long run(int index) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void solve(int size, int forbidden, int seed) {
|
||||
RoutingModel routing = new RoutingModel(size, 1, 0);
|
||||
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.
|
||||
NodeEvaluator2 distances = new RandomManhattan(size, seed);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(distances);
|
||||
IntIntToLong distances = new RandomManhattan(manager, size, seed);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(routing.registerTransitCallback(distances));
|
||||
|
||||
// Forbid node connections (randomly).
|
||||
Random randomizer = new Random();
|
||||
@@ -79,12 +85,17 @@ class Tsp {
|
||||
}
|
||||
|
||||
// Add dummy dimension to test API.
|
||||
routing.addDimension(new ConstantCallback(), size + 1, size + 1, true, "dummy");
|
||||
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(RoutingModel.defaultSearchParameters())
|
||||
.mergeFrom(main.defaultRoutingSearchParameters())
|
||||
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
|
||||
.build();
|
||||
|
||||
@@ -95,8 +106,9 @@ class Tsp {
|
||||
// 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))) {
|
||||
for (long node = routing.start(route_number);
|
||||
!routing.isEnd(node);
|
||||
node = solution.value(routing.nextVar(node))) {
|
||||
System.out.print("" + node + " -> ");
|
||||
}
|
||||
System.out.println("0");
|
||||
|
||||
@@ -10,22 +10,29 @@
|
||||
// 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 java.io.*;
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
import com.google.ortools.constraintsolver.Assignment;
|
||||
import com.google.ortools.constraintsolver.FirstSolutionStrategy;
|
||||
import com.google.ortools.constraintsolver.IntIntToLong;
|
||||
import com.google.ortools.constraintsolver.RoutingDimension;
|
||||
import com.google.ortools.constraintsolver.RoutingIndexManager;
|
||||
import com.google.ortools.constraintsolver.RoutingModel;
|
||||
import com.google.ortools.constraintsolver.NodeEvaluator2;
|
||||
import com.google.ortools.constraintsolver.RoutingDimension;
|
||||
import com.google.ortools.constraintsolver.RoutingSearchParameters;
|
||||
import com.google.ortools.constraintsolver.FirstSolutionStrategy;
|
||||
import com.google.ortools.constraintsolver.Assignment;
|
||||
import com.google.ortools.constraintsolver.main;
|
||||
import java.io.*;
|
||||
|
||||
class DataProblem {
|
||||
private int[][] locations_;
|
||||
|
||||
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}};
|
||||
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}
|
||||
};
|
||||
|
||||
// Compute locations in meters using the block dimension defined as follow
|
||||
// Manhattan average block: 750ft x 264ft -> 228m x 80m
|
||||
@@ -60,28 +67,31 @@ class DataProblem {
|
||||
/// @details It uses an array of positions and computes
|
||||
/// the Manhattan distance between the two positions of
|
||||
/// two different indices.
|
||||
class ManhattanDistance extends NodeEvaluator2 {
|
||||
private int[][] distances_;
|
||||
class ManhattanDistance extends IntIntToLong {
|
||||
private int[][] distances;
|
||||
private RoutingIndexManager indexManager;
|
||||
|
||||
public ManhattanDistance(DataProblem data) {
|
||||
public ManhattanDistance(DataProblem data, RoutingIndexManager manager) {
|
||||
// precompute distance between location to have distance callback in O(1)
|
||||
distances_ = new int[data.getLocationNumber()][data.getLocationNumber()];
|
||||
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;
|
||||
if (fromNode == toNode) distances[fromNode][toNode] = 0;
|
||||
else
|
||||
distances_[fromNode][toNode] =
|
||||
distances[fromNode][toNode] =
|
||||
abs(data.getLocations()[toNode][0] - data.getLocations()[fromNode][0])
|
||||
+ abs(data.getLocations()[toNode][1] - data.getLocations()[fromNode][1]);
|
||||
+ abs(data.getLocations()[toNode][1] - data.getLocations()[fromNode][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
/// @brief Returns the manhattan distance between the two nodes.
|
||||
public long run(int fromNode, int toNode) {
|
||||
return distances_[fromNode][toNode];
|
||||
public long run(int fromIndex, int toIndex) {
|
||||
int fromNode = indexManager.indexToNode(fromIndex);
|
||||
int toNode = indexManager.indexToNode(toIndex);
|
||||
return distances[fromNode][toNode];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +101,10 @@ class Vrp {
|
||||
}
|
||||
|
||||
/// @brief Add Global Span constraint.
|
||||
static void addDistanceDimension(RoutingModel routing, DataProblem data) {
|
||||
static void addDistanceDimension(RoutingModel routing, DataProblem data, int distanceIndex) {
|
||||
String distance = "Distance";
|
||||
routing.addDimension(new ManhattanDistance(data),
|
||||
routing.addDimension(
|
||||
distanceIndex,
|
||||
0, // null slack
|
||||
3000, // maximum distance per vehicle
|
||||
true, // start cumul to zero
|
||||
@@ -105,21 +116,22 @@ class Vrp {
|
||||
}
|
||||
|
||||
/// @brief Print the solution
|
||||
static void printSolution(DataProblem data, RoutingModel routing, Assignment solution) {
|
||||
static void printSolution(
|
||||
DataProblem data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
|
||||
// Solution cost.
|
||||
System.out.println("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(routing.indexToNode(index) + " -> ");
|
||||
for (long index = routing.start(i); !routing.isEnd(index); ) {
|
||||
System.out.print(manager.indexToNode((int) index) + " -> ");
|
||||
|
||||
long previousIndex = index;
|
||||
index = solution.value(routing.nextVar(index));
|
||||
distance += routing.getArcCostForVehicle(previousIndex, index, i);
|
||||
}
|
||||
System.out.println(routing.indexToNode(routing.end(i)));
|
||||
System.out.println(manager.indexToNode((int) routing.end(i)));
|
||||
System.out.println("Distance of the route: " + distance + "m");
|
||||
}
|
||||
}
|
||||
@@ -130,24 +142,26 @@ class Vrp {
|
||||
DataProblem data = new DataProblem();
|
||||
|
||||
// Create Routing Model
|
||||
RoutingModel routing =
|
||||
new RoutingModel(data.getLocationNumber(), data.getVehicleNumber(), data.getDepot());
|
||||
RoutingIndexManager manager =
|
||||
new RoutingIndexManager(data.getLocationNumber(), data.getVehicleNumber(), data.getDepot());
|
||||
RoutingModel routing = new RoutingModel(manager);
|
||||
|
||||
// Setting the cost function.
|
||||
// [todo]: protect callback from the GC
|
||||
NodeEvaluator2 distanceEvaluator = new ManhattanDistance(data);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(distanceEvaluator);
|
||||
addDistanceDimension(routing, data);
|
||||
IntIntToLong distanceEvaluator = new ManhattanDistance(data, manager);
|
||||
int distanceIndex = routing.registerTransitCallback(distanceEvaluator);
|
||||
routing.setArcCostEvaluatorOfAllVehicles(distanceIndex);
|
||||
addDistanceDimension(routing, data, distanceIndex);
|
||||
|
||||
// Setting first solution heuristic (cheapest addition).
|
||||
RoutingSearchParameters search_parameters =
|
||||
RoutingSearchParameters.newBuilder()
|
||||
.mergeFrom(RoutingModel.defaultSearchParameters())
|
||||
.mergeFrom(main.defaultRoutingSearchParameters())
|
||||
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
|
||||
.build();
|
||||
|
||||
Assignment solution = routing.solveWithParameters(search_parameters);
|
||||
printSolution(data, routing, solution);
|
||||
printSolution(data, routing, manager, solution);
|
||||
}
|
||||
|
||||
/// @brief Entry point of the program.
|
||||
|
||||
Reference in New Issue
Block a user