java: sync tests with Google

This commit is contained in:
Corentin Le Molgat
2021-08-31 11:58:46 +02:00
parent 7f01735c78
commit 96ead8f216
14 changed files with 2356 additions and 602 deletions

View File

@@ -10,96 +10,281 @@
// 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.
package com.google.ortools;
package com.google.ortools.constraintsolver;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.google.ortools.Loader;
import com.google.ortools.constraintsolver.Assignment;
import com.google.ortools.constraintsolver.AssignmentIntContainer;
import com.google.ortools.constraintsolver.BaseLns;
import com.google.ortools.constraintsolver.Decision;
import com.google.ortools.constraintsolver.DecisionBuilder;
import com.google.ortools.constraintsolver.IntVar;
import com.google.ortools.constraintsolver.IntVarLocalSearchFilter;
import com.google.ortools.constraintsolver.IntVarLocalSearchOperator;
import com.google.ortools.constraintsolver.LocalSearchFilterManager;
import com.google.ortools.constraintsolver.LocalSearchPhaseParameters;
import com.google.ortools.constraintsolver.OptimizeVar;
import com.google.ortools.constraintsolver.SearchLog;
import com.google.ortools.constraintsolver.SearchMonitor;
import com.google.ortools.constraintsolver.SolutionCollector;
import com.google.ortools.constraintsolver.Solver;
import com.google.ortools.constraintsolver.main;
import java.lang.ref.WeakReference;
import com.google.common.collect.Iterables;
import com.google.ortools.constraintsolver.ConstraintSolverParameters;
import com.google.ortools.constraintsolver.RegularLimitParameters;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
/** Tests the Constraint solver java interface. */
public class ConstraintSolverTest {
private static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while (ref.get() != null) {
System.gc();
}
}
private static final Logger logger = Logger.getLogger(ConstraintSolverTest.class.getName());
@Test
public void testSolverCtor() throws Exception {
public final class ConstraintSolverTest {
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
logger.info("testSolverCtor...");
Solver solver = new Solver("TestSolver");
if (!solver.model_name().equals("TestSolver")) {
throw new AssertionError("Solver ill formed");
}
if (solver.toString().length() < 0) {
throw new AssertionError("Solver ill formed");
}
logger.info("testSolverCtor...DONE");
}
@Test
public void testIntVar() throws Exception {
Loader.loadNativeLibraries();
logger.info("testIntVar...");
Solver solver = new Solver("Solver");
IntVar var = solver.makeIntVar(3, 11, "IntVar");
if (var.min() != 3) {
throw new AssertionError("IntVar Min wrong");
}
if (var.max() != 11) {
throw new AssertionError("IntVar Max wrong");
}
logger.info("testIntVar...DONE");
public void testSolverCtor() {
final Solver solver = new Solver("TestSolver");
assertNotNull(solver);
assertEquals("TestSolver", solver.model_name());
assertNotNull(solver.toString());
}
@Test
private static void testIntVarArray() throws Exception {
Loader.loadNativeLibraries();
logger.info("testIntVarArray...");
Solver solver = new Solver("Solver");
IntVar[] vars = solver.makeIntVarArray(7, 3, 5, "vars");
if (vars.length != 7) {
throw new AssertionError("Vars length wrong");
}
public void testIntVar() {
final Solver solver = new Solver("Solver");
final IntVar var = solver.makeIntVar(3, 11, "IntVar");
assertEquals(3, var.min());
assertEquals(11, var.max());
}
@Test
public void testIntVarArray() {
final Solver solver = new Solver("Solver");
final IntVar[] vars = solver.makeIntVarArray(7, 3, 5, "vars");
assertThat(vars).hasLength(7);
for (IntVar var : vars) {
if (var.min() != 3) {
throw new AssertionError("IntVar Min wrong");
}
if (var.max() != 5) {
throw new AssertionError("IntVar Max wrong");
}
assertEquals(3, var.min());
assertEquals(5, var.max());
}
logger.info("testIntVarArray...DONE");
}
@Test
public void testRabbitsPheasants() {
final Solver solver = new Solver("testRabbitsPheasants");
final IntVar rabbits = solver.makeIntVar(0, 100, "rabbits");
final IntVar pheasants = solver.makeIntVar(0, 100, "pheasants");
solver.addConstraint(solver.makeEquality(solver.makeSum(rabbits, pheasants), 20));
solver.addConstraint(solver.makeEquality(
solver.makeSum(solver.makeProd(rabbits, 4), solver.makeProd(pheasants, 2)), 56));
final DecisionBuilder db =
solver.makePhase(rabbits, pheasants, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);
solver.newSearch(db);
solver.nextSolution();
assertEquals(8, rabbits.value());
assertEquals(12, pheasants.value());
solver.endSearch();
}
// A Decision builder that does nothing.
static class DummyDecisionBuilder extends JavaDecisionBuilder {
@Override
public Decision next(Solver solver) throws Solver.FailException {
System.out.println("In Dummy Decision Builder");
return null;
}
@Override
public String toString() {
return "DummyDecisionBuilder";
}
}
@Test
public void testDummyDecisionBuilder() {
final Solver solver = new Solver("testDummyDecisionBuilder");
final DecisionBuilder db = new DummyDecisionBuilder();
assertTrue(solver.solve(db));
}
/**
* A decision builder that fails.
*/
static class FailDecisionBuilder extends JavaDecisionBuilder {
@Override
public Decision next(Solver solver) throws Solver.FailException {
System.out.println("In Fail Decision Builder");
solver.fail();
return null;
}
}
@Test
public void testFailDecisionBuilder() {
final Solver solver = new Solver("testFailDecisionBuilder");
final DecisionBuilder db = new FailDecisionBuilder();
assertFalse(solver.solve(db));
}
/** Golomb Ruler test */
@Test
public void testGolombRuler() {
final int m = 8;
final Solver solver = new Solver("GR " + m);
final IntVar[] ticks = solver.makeIntVarArray(m, 0, (1 << (m + 1)) - 1, "ticks");
solver.addConstraint(solver.makeEquality(ticks[0], 0));
for (int i = 0; i < ticks.length - 1; i++) {
solver.addConstraint(solver.makeLess(ticks[i], ticks[i + 1]));
}
final ArrayList<IntVar> diff = new ArrayList<>();
for (int i = 0; i < m - 1; i++) {
for (int j = i + 1; j < m; j++) {
diff.add(solver.makeDifference(ticks[j], ticks[i]).var());
}
}
solver.addConstraint(solver.makeAllDifferent(diff.toArray(new IntVar[0]), true));
// break symetries
if (m > 2) {
solver.addConstraint(solver.makeLess(diff.get(0), Iterables.getLast(diff)));
}
final OptimizeVar opt = solver.makeMinimize(ticks[m - 1], 1);
final DecisionBuilder db =
solver.makePhase(ticks, Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_MIN_VALUE);
final SearchMonitor log = solver.makeSearchLog(10000, opt);
assertTrue(solver.solve(db, opt, log));
assertEquals(34, opt.best());
}
@Test
public void testElementFunction() {
final Solver solver = new Solver("testElementFunction");
final IntVar index = solver.makeIntVar(0, 10, "index");
final IntExpr element = solver.makeElement((long x) -> x * 2, index);
assertEquals(0, element.min());
assertEquals(20, element.max());
}
@Test
public void testSolverParameters() {
final ConstraintSolverParameters parameters = ConstraintSolverParameters.newBuilder()
.mergeFrom(Solver.defaultSolverParameters())
.setTraceSearch(true)
.build();
final Solver solver = new Solver("testSolverParameters", parameters);
final ConstraintSolverParameters stored = solver.parameters();
assertTrue(stored.getTraceSearch());
}
@Test
public void testRegularLimitParameters() {
final Solver solver = new Solver("testRegularLimitParameters");
final RegularLimitParameters protoLimit =
RegularLimitParameters.newBuilder()
.mergeFrom(solver.makeDefaultRegularLimitParameters())
.setFailures(20000)
.build();
assertEquals(20000, protoLimit.getFailures());
final SearchLimit limit = solver.makeLimit(protoLimit);
assertNotNull(limit);
}
// verify Closure in Decision.
@Test
public void testClosureDecision() {
final StringProperty call = new StringProperty("");
final Solver solver = new Solver("ClosureDecisionTest");
final Decision decision = solver.makeDecision(
(Solver s) -> call.setValue("Apply"), (Solver s) -> call.setValue("Refute"));
System.gc();
decision.apply(solver);
assertEquals("Apply", call.toString());
decision.refute(solver);
assertEquals("Refute", call.toString());
}
@Test
public void testSolverInClosureDecision() {
final Solver solver = new Solver("SolverTestName");
final String modelName = solver.model_name();
// Lambda can only capture final or implicit final.
final AtomicInteger countApply = new AtomicInteger(0);
final AtomicInteger countRefute = new AtomicInteger(0);
assertEquals(0, countApply.intValue());
assertEquals(0, countRefute.intValue());
final Decision decision = solver.makeDecision(
(Solver s) -> {
assertEquals(s.model_name(), modelName);
countApply.addAndGet(1);
},
(Solver s) -> {
assertEquals(s.model_name(), modelName);
countRefute.addAndGet(1);
});
System.gc(); // verify lambda are kept alive
decision.apply(solver);
assertEquals(1, countApply.intValue());
assertEquals(0, countRefute.intValue());
decision.refute(solver);
assertEquals(1, countApply.intValue());
assertEquals(1, countRefute.intValue());
}
// A Decision builder that does nothing
public static class ActionDecisionBuilder extends JavaDecisionBuilder {
Consumer<Solver> apply;
Consumer<Solver> refute;
boolean passed;
public ActionDecisionBuilder(Consumer<Solver> a, Consumer<Solver> r) {
apply = a;
refute = r;
passed = false;
}
@Override
public Decision next(Solver solver) throws Solver.FailException {
if (passed) {
return null;
}
passed = true;
return solver.makeDecision(apply, refute);
}
@Override
public String toString() {
return "ActionDecisionBuilder";
}
}
// Tests the ActionDecisionBuilder.
@Test
public void testActionDecisionBuilder() {
final Solver solver = new Solver("testActionDecisionBuilder");
// Lambda can only capture final or implicit final
final AtomicInteger countApply = new AtomicInteger(0);
final AtomicInteger countRefute = new AtomicInteger(0);
assertEquals(0, countApply.intValue());
assertEquals(0, countRefute.intValue());
final DecisionBuilder db = new ActionDecisionBuilder(
(Solver s) -> countApply.addAndGet(1),
(Solver s) -> countRefute.addAndGet(1));
solver.newSearch(db);
assertTrue(solver.nextSolution());
assertEquals(1, countApply.intValue());
assertEquals(0, countRefute.intValue());
assertTrue(solver.nextSolution());
assertEquals(1, countApply.intValue());
assertEquals(1, countRefute.intValue());
solver.endSearch();
}
// ----- LocalSearch Test -----
private static class MoveOneVar extends IntVarLocalSearchOperator {
public MoveOneVar(IntVar[] variables) {
super(variables);
@@ -130,23 +315,22 @@ public class ConstraintSolverTest {
}
@Test
public void testSolver() throws Exception {
Loader.loadNativeLibraries();
Solver solver = new Solver("Solver");
IntVar[] vars = solver.makeIntVarArray(4, 0, 4, "vars");
IntVar sumVar = solver.makeSum(vars).var();
OptimizeVar obj = solver.makeMinimize(sumVar, 1);
DecisionBuilder db =
public void testSolver() {
final Solver solver = new Solver("Solver");
final IntVar[] vars = solver.makeIntVarArray(4, 0, 4, "vars");
final IntVar sumVar = solver.makeSum(vars).var();
final OptimizeVar obj = solver.makeMinimize(sumVar, 1);
final DecisionBuilder db =
solver.makePhase(vars, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MAX_VALUE);
MoveOneVar moveOneVar = new MoveOneVar(vars);
LocalSearchPhaseParameters lsParams =
final MoveOneVar moveOneVar = new MoveOneVar(vars);
final LocalSearchPhaseParameters lsParams =
solver.makeLocalSearchPhaseParameters(sumVar, moveOneVar, db);
DecisionBuilder ls = solver.makeLocalSearchPhase(vars, db, lsParams);
SolutionCollector collector = solver.makeLastSolutionCollector();
final DecisionBuilder ls = solver.makeLocalSearchPhase(vars, db, lsParams);
final SolutionCollector collector = solver.makeLastSolutionCollector();
collector.addObjective(sumVar);
SearchMonitor log = solver.makeSearchLog(1000, obj);
solver.solve(ls, collector, obj, log);
logger.info("Objective value = " + collector.objectiveValue(0));
final SearchMonitor log = solver.makeSearchLog(1000, obj);
assertTrue(solver.solve(ls, collector, obj, log));
}
private static class SumFilter extends IntVarLocalSearchFilter {
@@ -183,32 +367,44 @@ public class ConstraintSolverTest {
}
return newSum < sum;
}
private long sum;
}
private static class StringProperty {
public StringProperty(String initialValue) {
value = initialValue;
}
public void setValue(String newValue) {
value = newValue;
}
@Override
public String toString() {
return value;
}
private String value;
}
@Test
public void testSolverWithFilter() throws Exception {
Loader.loadNativeLibraries();
Solver solver = new Solver("Solver");
IntVar[] vars = solver.makeIntVarArray(4, 0, 4, "vars");
IntVar sumVar = solver.makeSum(vars).var();
OptimizeVar obj = solver.makeMinimize(sumVar, 1);
DecisionBuilder db =
public void testSolverWithLocalSearchFilter() {
final Solver solver = new Solver("Solver");
final IntVar[] vars = solver.makeIntVarArray(4, 0, 4, "vars");
final IntVar sumVar = solver.makeSum(vars).var();
final OptimizeVar obj = solver.makeMinimize(sumVar, 1);
final DecisionBuilder db =
solver.makePhase(vars, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MAX_VALUE);
MoveOneVar moveOneVar = new MoveOneVar(vars);
SumFilter filter = new SumFilter(vars);
IntVarLocalSearchFilter[] filters = new IntVarLocalSearchFilter[1];
filters[0] = filter;
LocalSearchFilterManager filter_manager = new LocalSearchFilterManager(filters);
LocalSearchFilterManager filterManager = new LocalSearchFilterManager(filters);
LocalSearchPhaseParameters lsParams =
solver.makeLocalSearchPhaseParameters(sumVar, moveOneVar, db, null, filter_manager);
solver.makeLocalSearchPhaseParameters(sumVar, moveOneVar, db, null, filterManager);
DecisionBuilder ls = solver.makeLocalSearchPhase(vars, db, lsParams);
SolutionCollector collector = solver.makeLastSolutionCollector();
collector.addObjective(sumVar);
SearchMonitor log = solver.makeSearchLog(1000, obj);
solver.solve(ls, collector, obj, log);
logger.info("Objective value = " + collector.objectiveValue(0));
}
private static class OneVarLns extends BaseLns {
@@ -218,44 +414,44 @@ public class ConstraintSolverTest {
@Override
public void initFragments() {
index_ = 0;
index = 0;
}
@Override
public boolean nextFragment() {
int size = size();
if (index_ < size) {
appendToFragment(index_);
++index_;
if (index < size) {
appendToFragment(index);
++index;
return true;
} else {
return false;
}
}
private int index_;
private int index;
}
@Test
public void testSolverLns() throws Exception {
Loader.loadNativeLibraries();
Solver solver = new Solver("Solver");
IntVar[] vars = solver.makeIntVarArray(4, 0, 4, "vars");
IntVar sumVar = solver.makeSum(vars).var();
OptimizeVar obj = solver.makeMinimize(sumVar, 1);
DecisionBuilder db =
public void testSolverLns() {
final Solver solver = new Solver("Solver");
final IntVar[] vars = solver.makeIntVarArray(4, 0, 4, "vars");
final IntVar sumVar = solver.makeSum(vars).var();
final OptimizeVar obj = solver.makeMinimize(sumVar, 1);
final DecisionBuilder db =
solver.makePhase(vars, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MAX_VALUE);
OneVarLns oneVarLns = new OneVarLns(vars);
LocalSearchPhaseParameters lsParams =
final OneVarLns oneVarLns = new OneVarLns(vars);
final LocalSearchPhaseParameters lsParams =
solver.makeLocalSearchPhaseParameters(sumVar, oneVarLns, db);
DecisionBuilder ls = solver.makeLocalSearchPhase(vars, db, lsParams);
SolutionCollector collector = solver.makeLastSolutionCollector();
final DecisionBuilder ls = solver.makeLocalSearchPhase(vars, db, lsParams);
final SolutionCollector collector = solver.makeLastSolutionCollector();
collector.addObjective(sumVar);
SearchMonitor log = solver.makeSearchLog(1000, obj);
final SearchMonitor log = solver.makeSearchLog(1000, obj);
solver.solve(ls, collector, obj, log);
logger.info("Objective value = " + collector.objectiveValue(0));
}
// ----- SearchLog Test -----
// TODO(user): Improve search log tests; currently only tests coverage and callback.
// note: this is more or less what is done in search_test.cc
private static void runSearchLog(SearchMonitor searchlog) {
searchlog.enterSearch();
searchlog.exitSearch();
@@ -269,160 +465,79 @@ public class ConstraintSolverTest {
// Simple Coverage test...
@Test
public void testSearchLog() throws Exception {
Loader.loadNativeLibraries();
logger.info("testSearchLog...");
Solver solver = new Solver("TestSearchLog");
IntVar var = solver.makeIntVar(1, 1, "Variable");
OptimizeVar objective = solver.makeMinimize(var, 1);
SearchMonitor searchlog = solver.makeSearchLog(0);
public void testSearchLog() {
final Solver solver = new Solver("TestSearchLog");
final IntVar var = solver.makeIntVar(1, 1, "Variable");
solver.makeMinimize(var, 1);
final SearchMonitor searchlog = solver.makeSearchLog(0);
runSearchLog(searchlog);
logger.info("testSearchLog...DONE");
}
private static class SearchCount implements Supplier<String> {
public SearchCount(AtomicInteger count_) {
count = count_;
public SearchCount(AtomicInteger initialCount) {
count = initialCount;
}
@Override
public String get() {
count.addAndGet(1);
return "display callback called...";
}
private AtomicInteger count;
private final AtomicInteger count;
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
public void testSearchLogWithCallback(boolean enableGC) throws Exception {
Loader.loadNativeLibraries();
logger.info("testSearchLogWithCallback (enable gc:" + enableGC + ")...");
Solver solver = new Solver("TestSearchLog");
IntVar var = solver.makeIntVar(1, 1, "Variable");
OptimizeVar objective = solver.makeMinimize(var, 1);
AtomicInteger count = new AtomicInteger(0);
SearchMonitor searchlog = solver.makeSearchLog(0, // branch period
@Test
public void testSearchLogWithCallback() {
final Solver solver = new Solver("TestSearchLog");
final AtomicInteger count = new AtomicInteger(0);
final SearchMonitor searchlog = solver.makeSearchLog(
0, // branch period
new SearchCount(count));
if (enableGC) {
gc();
}
System.gc(); // verify SearchCount is kept alive by the searchlog
runSearchLog(searchlog);
logger.info("count:" + count.intValue());
if (count.intValue() != 1)
throw new AssertionError("count != 1");
;
logger.info("testSearchLogWithCallback (enable gc:" + enableGC + ")...DONE");
assertEquals(1, count.intValue());
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
public void testSearchLogWithIntVarCallback(boolean enableGC) throws Exception {
Loader.loadNativeLibraries();
logger.info("testSearchLogWithIntVarCallback (enable gc:" + enableGC + ")...");
Solver solver = new Solver("TestSearchLog");
IntVar var = solver.makeIntVar(1, 1, "Variable");
OptimizeVar objective = solver.makeMinimize(var, 1);
AtomicInteger count = new AtomicInteger(0);
SearchMonitor searchlog = solver.makeSearchLog(0, // branch period
@Test
public void testSearchLogWithLambdaCallback() {
final Solver solver = new Solver("TestSearchLog");
final AtomicInteger count = new AtomicInteger(0);
final SearchMonitor searchlog = solver.makeSearchLog(
0, // branch period
() -> {
count.addAndGet(1);
return "display callback called...";
});
System.gc(); // verify lambda is kept alive by the searchlog
runSearchLog(searchlog);
assertEquals(1, count.intValue());
}
@Test
public void testSearchLogWithIntVarCallback() {
final Solver solver = new Solver("TestSearchLog");
final IntVar var = solver.makeIntVar(1, 1, "Variable");
final AtomicInteger count = new AtomicInteger(0);
final SearchMonitor searchlog = solver.makeSearchLog(
0, // branch period
var, // IntVar to monitor
new SearchCount(count));
if (enableGC) {
gc();
}
System.gc();
runSearchLog(searchlog);
if (count.intValue() != 1)
throw new AssertionError("count != 1");
;
logger.info("testSearchLogWithIntVarCallback (enable gc:" + enableGC + ")...DONE");
assertEquals(1, count.intValue());
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
public void testSearchLogWithObjectiveCallback(boolean enableGC) throws Exception {
Loader.loadNativeLibraries();
logger.info("testSearchLogWithObjectiveCallback (enable gc:" + enableGC + ")...");
Solver solver = new Solver("TestSearchLog");
IntVar var = solver.makeIntVar(1, 1, "Variable");
OptimizeVar objective = solver.makeMinimize(var, 1);
AtomicInteger count = new AtomicInteger(0);
SearchMonitor searchlog = solver.makeSearchLog(0, // branch period
@Test
public void testSearchLogWithObjectiveCallback() {
final Solver solver = new Solver("TestSearchLog");
final IntVar var = solver.makeIntVar(1, 1, "Variable");
final OptimizeVar objective = solver.makeMinimize(var, 1);
final AtomicInteger count = new AtomicInteger(0);
final SearchMonitor searchlog = solver.makeSearchLog(
0, // branch period
objective, // objective var to monitor
new SearchCount(count));
if (enableGC) {
gc();
}
System.gc();
runSearchLog(searchlog);
if (count.intValue() != 1)
throw new AssertionError("count != 1");
;
logger.info("testSearchLogWithObjectiveCallback (enable gc:" + enableGC + ")...DONE");
}
private static class StringProperty {
public StringProperty(String value) {
value_ = value;
}
public void setValue(String value) {
value_ = value;
;
}
public String toString() {
return value_;
}
private String value_;
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
public void testClosureDecision(boolean enableGC) throws Exception {
Loader.loadNativeLibraries();
logger.info("testClosureDecision (enable gc:" + enableGC + ")...");
final StringProperty call = new StringProperty("");
Solver solver = new Solver("ClosureDecisionTest");
Decision decision = solver.makeDecision(
(Solver s) -> { call.setValue("Apply"); }, (Solver s) -> { call.setValue("Refute"); });
if (enableGC) {
gc();
}
decision.apply(solver);
if (!call.toString().equals("Apply")) {
throw new AssertionError("Apply action not called");
}
decision.refute(solver);
if (!call.toString().equals("Refute")) {
throw new AssertionError("Refute action not called");
}
logger.info("testClosureDecision (enable gc:" + enableGC + ")...DONE");
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
public void testSolverInClosureDecision(boolean enableGC) throws Exception {
Loader.loadNativeLibraries();
logger.info("testSolverInClosureDecision (enable gc:" + enableGC + ")...");
Solver solver = new Solver("SolverTestName");
String model_name = solver.model_name();
Decision decision = solver.makeDecision(
(Solver s)
-> {
if (!s.model_name().equals(model_name)) {
throw new AssertionError("Solver ill formed");
}
},
(Solver s) -> {
if (!s.model_name().equals(model_name)) {
throw new AssertionError("Solver ill formed");
}
});
if (enableGC) {
gc(); // verify SearchCount is kept alive
}
decision.apply(solver);
decision.refute(solver);
logger.info("testSolverInClosureDecision (enable gc:" + enableGC + ")...DONE");
assertEquals(1, count.intValue());
}
}

View File

@@ -830,7 +830,7 @@ namespace Google.OrTools.Tests
Assert.Equal(3, ct.count());
}
// TODO(mizux): Improve search log tests; currently only tests coverage.
// TODO(user): Improve search log tests; currently only tests coverage.
void RunSearchLog(in SearchMonitor searchlog)
{
searchlog.EnterSearch();

View File

@@ -0,0 +1,231 @@
// Copyright 2010-2021 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.
package com.google.ortools.sat;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import com.google.ortools.Loader;
import com.google.ortools.util.Domain;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Tests the CpSolver java interface. */
public final class CpModelTest {
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
}
@Test
public void testCpModel_newIntVar() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newIntVar(0, 10, "x");
final IntVar y = model.newIntVarFromDomain(Domain.fromValues(new long[] {0, 1, 2, 5}), "y");
final IntVar z =
model.newIntVarFromDomain(Domain.fromIntervals(new long[][] {{0, 2}, {5}}), "");
final IntVar t = model.newBoolVar("t");
final IntVar u = model.newConstant(5);
assertThat(x.getName()).isEqualTo("x");
assertThat(y.getName()).isEqualTo("y");
assertThat(z.getName()).isEmpty();
assertThat(t.getName()).isEqualTo("t");
assertThat(u.getName()).isEmpty();
assertThat(x.getDomain().flattenedIntervals()).isEqualTo(new long[] {0, 10});
assertThat(x.getShortString()).isEqualTo("x(0..10)");
assertThat(y.getShortString()).isEqualTo("y(0..2, 5)");
assertThat(z.getShortString()).isEqualTo("var_2(0..2, 5)");
assertThat(t.getShortString()).isEqualTo("t(0..1)");
assertThat(u.getShortString()).isEqualTo("5");
}
@Test
public void testCpModel_addBoolOr() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
final IntVar z = model.newBoolVar("z");
model.addBoolOr(new Literal[] {x, y.not(), z});
assertThat(model.model().getConstraintsCount()).isEqualTo(1);
assertThat(model.model().getConstraints(0).hasBoolOr()).isTrue();
assertThat(model.model().getConstraints(0).getBoolOr().getLiteralsCount()).isEqualTo(3);
}
@Test
public void testCpModel_addBoolAnd() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
final IntVar z = model.newBoolVar("z");
model.addBoolAnd(new Literal[] {x, y.not(), z});
assertThat(model.model().getConstraintsCount()).isEqualTo(1);
assertThat(model.model().getConstraints(0).hasBoolAnd()).isTrue();
assertThat(model.model().getConstraints(0).getBoolAnd().getLiteralsCount()).isEqualTo(3);
}
@Test
public void testCpModel_addBoolXor() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
final IntVar z = model.newBoolVar("z");
model.addBoolXor(new Literal[] {x, y.not(), z});
assertThat(model.model().getConstraintsCount()).isEqualTo(1);
assertThat(model.model().getConstraints(0).hasBoolXor()).isTrue();
assertThat(model.model().getConstraints(0).getBoolXor().getLiteralsCount()).isEqualTo(3);
}
@Test
public void testCpModel_addImplication() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
model.addImplication(x, y);
assertThat(model.model().getConstraintsCount()).isEqualTo(1);
assertThat(model.model().getConstraints(0).hasBoolOr()).isTrue();
assertThat(model.model().getConstraints(0).getBoolOr().getLiteralsCount()).isEqualTo(2);
}
@Test
public void testCpModel_addLinear() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
model.addEquality(LinearExpr.sum(new IntVar[] {x, y}), 1);
assertThat(model.model().getConstraintsCount()).isEqualTo(1);
assertThat(model.model().getConstraints(0).hasLinear()).isTrue();
assertThat(model.model().getConstraints(0).getLinear().getVarsCount()).isEqualTo(2);
final IntVar b = model.newBoolVar("b");
model.addEquality(LinearExpr.sum(new IntVar[] {x, y}), 2).onlyEnforceIf(b.not());
assertThat(model.model().getConstraintsCount()).isEqualTo(2);
assertThat(model.model().getConstraints(1).hasLinear()).isTrue();
assertThat(model.model().getConstraints(1).getEnforcementLiteralCount()).isEqualTo(1);
assertThat(model.model().getConstraints(1).getEnforcementLiteral(0)).isEqualTo(-3);
final IntVar c = model.newBoolVar("c");
model.addEquality(LinearExpr.sum(new IntVar[] {x, y}), 3).onlyEnforceIf(new Literal[] {b, c});
assertThat(model.model().getConstraintsCount()).isEqualTo(3);
assertThat(model.model().getConstraints(2).hasLinear()).isTrue();
assertThat(model.model().getConstraints(2).getEnforcementLiteralCount()).isEqualTo(2);
assertThat(model.model().getConstraints(2).getEnforcementLiteral(0)).isEqualTo(2);
assertThat(model.model().getConstraints(2).getEnforcementLiteral(1)).isEqualTo(3);
}
@Test
public void testCpModel_addNoOverlap() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final int horizon = 100;
final IntVar startVar1 = model.newIntVar(0, horizon, "start1");
final IntVar endVar1 = model.newIntVar(0, horizon, "end1");
// Java code supports IntVar or integer constants in intervals.
final int duration1 = 10;
final IntervalVar interval1 = model.newIntervalVar(startVar1, duration1, endVar1, "interval1");
final IntVar startVar2 = model.newIntVar(0, horizon, "start2");
final IntVar endVar2 = model.newIntVar(0, horizon, "end2");
// Java code supports IntVar or integer constants in intervals.
final int duration2 = 15;
final IntervalVar interval2 = model.newIntervalVar(startVar2, duration2, endVar2, "interval2");
model.addNoOverlap(new IntervalVar[] {interval1, interval2});
assertThat(model.model().getConstraintsCount()).isEqualTo(3);
assertThat(model.model().getConstraints(0).hasInterval()).isTrue();
assertThat(model.model().getConstraints(1).hasInterval()).isTrue();
assertThat(model.model().getConstraints(2).hasNoOverlap()).isTrue();
assertThat(model.model().getConstraints(2).getNoOverlap().getIntervalsCount()).isEqualTo(2);
}
@Test
public void testCpModel_addNoOverlap2D() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final int horizon = 100;
final IntVar startVar1 = model.newIntVar(0, horizon, "start1");
final IntVar endVar1 = model.newIntVar(0, horizon, "end1");
// Java code supports IntVar or integer constants in intervals.
final int duration1 = 10;
final IntervalVar interval1 = model.newIntervalVar(startVar1, duration1, endVar1, "interval1");
final IntVar startVar2 = model.newIntVar(0, horizon, "start2");
final IntVar endVar2 = model.newIntVar(0, horizon, "end2");
// Java code supports IntVar or integer constants in intervals.
final int duration2 = 15;
final IntervalVar interval2 = model.newIntervalVar(startVar2, duration2, endVar2, "interval2");
model.addNoOverlap2D(
new IntervalVar[] {interval1, interval2}, new IntervalVar[] {interval1, interval2});
assertThat(model.model().getConstraintsCount()).isEqualTo(3);
assertThat(model.model().getConstraints(0).hasInterval()).isTrue();
assertThat(model.model().getConstraints(1).hasInterval()).isTrue();
assertThat(model.model().getConstraints(2).hasNoOverlap2D()).isTrue();
assertThat(model.model().getConstraints(2).getNoOverlap2D().getXIntervalsCount()).isEqualTo(2);
assertThat(model.model().getConstraints(2).getNoOverlap2D().getYIntervalsCount()).isEqualTo(2);
}
@Test
public void testCpModel_modelStats() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
model.addImplication(x, y);
String stats = model.modelStats();
assertThat(stats).isNotEmpty();
}
@Test
public void testCpModel_validateOk() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
model.addImplication(x, y);
String stats = model.validate();
assertThat(stats).isEmpty();
}
@Test
public void testCpModel_validateNotOk() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newIntVar(0, 9223372036854775807L, "x");
final IntVar y = model.newIntVar(0, 10, "y");
model.addLinearExpressionInDomain(LinearExpr.sum(new IntVar[] {x, y}),
Domain.fromFlatIntervals(new long[] {6, 9223372036854775807L}));
String stats = model.validate();
assertThat(stats).isNotEmpty();
}
@Test
public void testCpModel_exceptionVisibility() throws Exception {
CpModel.MismatchedArrayLengths ex1 = new CpModel.MismatchedArrayLengths("test1", "ar1", "ar2");
CpModel.WrongLength ex2 = new CpModel.WrongLength("test2", "ar");
assertThat(ex1).hasMessageThat().isEqualTo("test1: ar1 and ar2 have mismatched lengths");
assertThat(ex2).hasMessageThat().isEqualTo("test2: ar");
}
}

View File

@@ -0,0 +1,260 @@
// Copyright 2010-2021 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.
package com.google.ortools.sat;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import com.google.ortools.Loader;
import com.google.ortools.sat.CpSolverStatus;
import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Tests the CpSolver java interface. */
public final class CpSolverTest {
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
}
static class SolutionCounter extends CpSolverSolutionCallback {
public SolutionCounter() {}
@Override
public void onSolutionCallback() {
solutionCount++;
}
private int solutionCount;
public int getSolutionCount() {
return solutionCount;
}
}
static class LogToString {
public LogToString() {
logBuilder = new StringBuilder();
}
public void newMessage(String message) {
logBuilder.append(message).append("\n");
}
private final StringBuilder logBuilder;
public String getLog() {
return logBuilder.toString();
}
}
@Test
public void testCpSolver_solve() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
// Creates the variables.
int numVals = 3;
final IntVar x = model.newIntVar(0, numVals - 1, "x");
final IntVar y = model.newIntVar(0, numVals - 1, "y");
// Creates the constraints.
model.addDifferent(x, y);
// Creates a solver and solves the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
final CpSolverStatus status = solver.solve(model);
assertThat(status).isEqualTo(CpSolverStatus.OPTIMAL);
assertThat(solver.value(x)).isNotEqualTo(solver.value(y));
final String stats = solver.responseStats();
assertThat(stats).isNotEmpty();
}
@Test
public void testCpSolver_hinting() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newIntVar(0, 5, "x");
final IntVar y = model.newIntVar(0, 6, "y");
// Creates the constraints.
model.addEquality(LinearExpr.sum(new IntVar[] {x, y}), 6);
// Add hints.
model.addHint(x, 2);
model.addHint(y, 4);
// Creates a solver and solves the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
solver.getParameters().setCpModelPresolve(false);
final CpSolverStatus status = solver.solve(model);
assertThat(status).isEqualTo(CpSolverStatus.OPTIMAL);
assertThat(solver.value(x)).isEqualTo(2);
assertThat(solver.value(y)).isEqualTo(4);
}
@Test
public void testCpSolver_booleanValue() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
final IntVar x = model.newBoolVar("x");
final IntVar y = model.newBoolVar("y");
model.addBoolOr(new Literal[] {x, y.not()});
// Creates a solver and solves the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
final CpSolverStatus status = solver.solve(model);
assertEquals(CpSolverStatus.OPTIMAL, status);
assertThat(solver.booleanValue(x) || solver.booleanValue(y.not())).isTrue();
}
@Test
public void testCpSolver_searchAllSolutions() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
// Creates the variables.
int numVals = 3;
final IntVar x = model.newIntVar(0, numVals - 1, "x");
final IntVar y = model.newIntVar(0, numVals - 1, "y");
model.newIntVar(0, numVals - 1, "z");
// Creates the constraints.
model.addDifferent(x, y);
// Creates a solver and solves the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
final SolutionCounter cb = new SolutionCounter();
solver.searchAllSolutions(model, cb);
assertThat(cb.getSolutionCount()).isEqualTo(18);
assertThat(solver.numBranches()).isGreaterThan(0L);
}
@Test
public void testCpSolver_objectiveValue() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
// Creates the variables.
final int numVals = 3;
final IntVar x = model.newIntVar(0, numVals - 1, "x");
final IntVar y = model.newIntVar(0, numVals - 1, "y");
final IntVar z = model.newIntVar(0, numVals - 1, "z");
// Creates the constraints.
model.addDifferent(x, y);
// Maximizes a linear combination of variables.
model.maximize(LinearExpr.scalProd(new IntVar[] {x, y, z}, new int[] {1, 2, 3}));
// Creates a solver and solves the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
CpSolverStatus status = solver.solve(model);
assertThat(status).isEqualTo(CpSolverStatus.OPTIMAL);
assertThat(solver.objectiveValue()).isEqualTo(11.0);
}
@Test
public void testCpModel_crashPresolve() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
// Create decision variables
final IntVar x = model.newIntVar(0, 5, "x");
final IntVar y = model.newIntVar(0, 5, "y");
// Create a linear constraint which enforces that only x or y can be greater than 0.
model.addLinearConstraint(LinearExpr.sum(new IntVar[] {x, y}), 0, 1);
// Create the objective variable
final IntVar obj = model.newIntVar(0, 3, "obj");
// Cut the domain of the objective variable
model.addGreaterOrEqual(obj, 2);
// Set a constraint that makes the problem infeasible
model.addMaxEquality(obj, new IntVar[] {x, y});
// Optimize objective
model.minimize(obj);
// Create a solver and solve the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
com.google.ortools.sat.CpSolverStatus status = solver.solve(model);
assertThat(status).isEqualTo(CpSolverStatus.INFEASIBLE);
}
@Test
public void testCpSolver_customLog() throws Exception {
final CpModel model = new CpModel();
assertNotNull(model);
// Creates the variables.
final int numVals = 3;
final IntVar x = model.newIntVar(0, numVals - 1, "x");
final IntVar y = model.newIntVar(0, numVals - 1, "y");
// Creates the constraints.
model.addDifferent(x, y);
// Creates a solver and solves the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
StringBuilder logBuilder = new StringBuilder();
Consumer<String> appendToLog = (String message) -> logBuilder.append(message).append('\n');
solver.setLogCallback(appendToLog);
solver.getParameters().setLogToStdout(false).setLogSearchProgress(true);
CpSolverStatus status = solver.solve(model);
assertThat(status).isEqualTo(CpSolverStatus.OPTIMAL);
String log = logBuilder.toString();
assertThat(log).isNotEmpty();
assertThat(log).contains("Parameters");
assertThat(log).contains("log_to_stdout: false");
assertThat(log).contains("OPTIMAL");
}
@Test
public void testCpSolver_customLogMultiThread() {
final CpModel model = new CpModel();
assertNotNull(model);
// Creates the variables.
int numVals = 3;
IntVar x = model.newIntVar(0, numVals - 1, "x");
IntVar y = model.newIntVar(0, numVals - 1, "y");
// Creates the constraints.
model.addDifferent(x, y);
// Creates a solver and solves the model.
final CpSolver solver = new CpSolver();
assertNotNull(solver);
StringBuilder logBuilder = new StringBuilder();
Consumer<String> appendToLog = (String message) -> logBuilder.append(message).append('\n');
solver.setLogCallback(appendToLog);
solver.getParameters()
.setLogToStdout(false)
.setLogSearchProgress(true)
.setNumSearchWorkers(12);
CpSolverStatus status = solver.solve(model);
assertThat(status).isEqualTo(CpSolverStatus.OPTIMAL);
String log = logBuilder.toString();
assertThat(log).isNotEmpty();
assertThat(log).contains("Parameters");
assertThat(log).contains("log_to_stdout: false");
assertThat(log).contains("OPTIMAL");
}
}

View File

@@ -0,0 +1,83 @@
// Copyright 2010-2021 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.
package com.google.ortools.graph;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import com.google.ortools.Loader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Test the Min/Max Flow solver java interface. */
public final class FlowTest {
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
}
@Test
public void testMinCostFlow() {
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}};
final int expectedCost = 275;
final MinCostFlow minCostFlow = new MinCostFlow();
assertNotNull(minCostFlow);
for (int source = 0; source < numSources; ++source) {
for (int target = 0; target < numTargets; ++target) {
minCostFlow.addArcWithCapacityAndUnitCost(
source, numSources + target, 1, costs[source][target]);
}
}
for (int source = 0; source < numSources; ++source) {
minCostFlow.setNodeSupply(source, 1);
}
for (int target = 0; target < numTargets; ++target) {
minCostFlow.setNodeSupply(numSources + target, -1);
}
final MinCostFlowBase.Status solveStatus = minCostFlow.solve();
assertEquals(solveStatus, MinCostFlow.Status.OPTIMAL);
final long totalFlowCost = minCostFlow.getOptimalCost();
assertEquals(expectedCost, totalFlowCost);
}
@Test
public void testMaxFlow() {
final int numNodes = 6;
final int numArcs = 9;
final int[] tails = {0, 0, 0, 0, 1, 2, 3, 3, 4};
final int[] heads = {1, 2, 3, 4, 3, 4, 4, 5, 5};
final int[] capacities = {5, 8, 2, 0, 4, 5, 6, 0, 4};
final int[] expectedFlows = {4, 4, 2, 0, 4, 4, 0, 6, 4};
final int expectedTotalFlow = 10;
final MaxFlow maxFlow = new MaxFlow();
assertNotNull(maxFlow);
for (int i = 0; i < numArcs; ++i) {
maxFlow.addArcWithCapacity(tails[i], heads[i], capacities[i]);
}
maxFlow.setArcCapacity(7, 6);
final MaxFlow.Status solveStatus = maxFlow.solve(/*source=*/0, /*sink=*/numNodes - 1);
assertEquals(solveStatus, MaxFlow.Status.OPTIMAL);
final long totalFlow = maxFlow.getOptimalFlow();
assertEquals(expectedTotalFlow, totalFlow);
for (int i = 0; i < numArcs; ++i) {
assertEquals(maxFlow.getFlow(i), expectedFlows[i]);
}
}
}

View File

@@ -0,0 +1,54 @@
// Copyright 2010-2021 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.
package com.google.ortools.algorithms;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import com.google.ortools.Loader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Test the Knapsack solver java interface. */
public final class KnapsackSolverTest {
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
}
@Test
public void testKnapsackSolver() {
final KnapsackSolver solver = new KnapsackSolver(
KnapsackSolver.SolverType.KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, "test");
assertNotNull(solver);
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[] capacities = {850};
solver.init(profits, weights, capacities);
final long computedProfit = solver.solve();
assertEquals(7534, computedProfit);
}
}

View File

@@ -0,0 +1,167 @@
// Copyright 2010-2021 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.
package com.google.ortools.sat;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import com.google.ortools.Loader;
import com.google.ortools.util.Domain;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public final class LinearExprTest {
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
}
@Test
public void testLinearExpr_term() {
final CpModel model = new CpModel();
assertNotNull(model);
final Domain domain = new Domain(0, 10);
final IntVar y = model.newIntVarFromDomain(domain, "y");
final LinearExpr expr = LinearExpr.term(y, 12);
assertNotNull(expr);
assertEquals(1, expr.numElements());
assertEquals(y, expr.getVariable(0));
assertEquals(12, expr.getCoefficient(0));
assertEquals(0, expr.getOffset());
}
@Test
public void testLinearExpr_booleanTerm() {
final CpModel model = new CpModel();
assertNotNull(model);
final Literal y = model.newBoolVar("y");
final LinearExpr expr = LinearExpr.term(y.not(), 12);
assertNotNull(expr);
assertThat(expr.numElements()).isEqualTo(1);
assertThat(expr.getVariable(0)).isEqualTo(y);
assertThat(expr.getCoefficient(0)).isEqualTo(-12);
assertThat(expr.getOffset()).isEqualTo(12);
}
@Test
public void testLinearExpr_affine() {
final CpModel model = new CpModel();
assertNotNull(model);
final Domain domain = new Domain(0, 10);
final IntVar y = model.newIntVarFromDomain(domain, "y");
final LinearExpr expr = LinearExpr.affine(y, 12, 5);
assertNotNull(expr);
assertThat(expr.numElements()).isEqualTo(1);
assertThat(expr.getVariable(0)).isEqualTo(y);
assertThat(expr.getCoefficient(0)).isEqualTo(12);
assertThat(expr.getOffset()).isEqualTo(5);
}
@Test
public void testLinearExpr_booleanAffine() {
final CpModel model = new CpModel();
assertNotNull(model);
final Literal y = model.newBoolVar("y");
final LinearExpr expr = LinearExpr.affine(y.not(), 12, 5);
assertNotNull(expr);
assertThat(expr.numElements()).isEqualTo(1);
assertThat(expr.getVariable(0)).isEqualTo(y);
assertThat(expr.getCoefficient(0)).isEqualTo(-12);
assertThat(expr.getOffset()).isEqualTo(17);
}
@Test
public void testLinearExpr_sum() {
final CpModel model = new CpModel();
assertNotNull(model);
final Domain domain = new Domain(0, 10);
final IntVar x = model.newIntVarFromDomain(domain, "x");
final IntVar y = model.newIntVarFromDomain(domain, "y");
final LinearExpr expr = LinearExpr.sum(new IntVar[] {x, y});
assertNotNull(expr);
assertThat(expr.numElements()).isEqualTo(2);
assertThat(expr.getVariable(0)).isEqualTo(x);
assertThat(expr.getCoefficient(0)).isEqualTo(1);
assertThat(expr.getVariable(1)).isEqualTo(y);
assertThat(expr.getCoefficient(1)).isEqualTo(1);
assertThat(expr.getOffset()).isEqualTo(0);
}
@Test
public void testLinearExpr_scalProd() {
final CpModel model = new CpModel();
assertNotNull(model);
final Domain domain = new Domain(0, 10);
final IntVar x = model.newIntVarFromDomain(domain, "x");
final IntVar y = model.newIntVarFromDomain(domain, "y");
final LinearExpr expr = LinearExpr.scalProd(new IntVar[] {x, y}, new long[] {3, 5});
assertNotNull(expr);
assertThat(expr.numElements()).isEqualTo(2);
assertThat(expr.getVariable(0)).isEqualTo(x);
assertThat(expr.getCoefficient(0)).isEqualTo(3);
assertThat(expr.getVariable(1)).isEqualTo(y);
assertThat(expr.getCoefficient(1)).isEqualTo(5);
assertThat(expr.getOffset()).isEqualTo(0);
}
@Test
public void testLinearExpr_booleanSum() {
final CpModel model = new CpModel();
assertNotNull(model);
final Literal x = model.newBoolVar("x");
final Literal y = model.newBoolVar("y");
final LinearExpr expr = LinearExpr.booleanSum(new Literal[] {x, y.not()});
assertNotNull(expr);
assertThat(expr.numElements()).isEqualTo(2);
assertThat(expr.getVariable(0)).isEqualTo(x);
assertThat(expr.getCoefficient(0)).isEqualTo(1);
assertThat(expr.getVariable(1)).isEqualTo(y);
assertThat(expr.getCoefficient(1)).isEqualTo(-1);
assertThat(expr.getOffset()).isEqualTo(-1);
}
@Test
public void testLinearExpr_booleanScalProd() {
final CpModel model = new CpModel();
assertNotNull(model);
final Literal x = model.newBoolVar("x");
final Literal y = model.newBoolVar("y");
final LinearExpr expr =
LinearExpr.booleanScalProd(new Literal[] {x, y.not()}, new long[] {3, 5});
assertNotNull(expr);
assertThat(expr.numElements()).isEqualTo(2);
assertThat(expr.getVariable(0)).isEqualTo(x);
assertThat(expr.getCoefficient(0)).isEqualTo(3);
assertThat(expr.getVariable(1)).isEqualTo(y);
assertThat(expr.getCoefficient(1)).isEqualTo(-5);
assertThat(expr.getOffset()).isEqualTo(-5);
}
}

View File

@@ -10,181 +10,617 @@
// 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.
package com.google.ortools;
package com.google.ortools.linearsolver;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.google.ortools.Loader;
import com.google.ortools.linearsolver.MPConstraint;
import com.google.ortools.linearsolver.MPObjective;
import com.google.ortools.linearsolver.MPSolver;
import com.google.ortools.linearsolver.MPVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class LinearSolverTest {
static {
System.setProperty(
"java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT] [%4$-7s] %5$s %n");
/** Test the Linear Solver java interface. */
public final class LinearSolverTest {
// Numerical tolerance for checking primal, dual, objective values
// and other values.
private static final double NUM_TOLERANCE = 1e-5;
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
}
private static final Logger logger = Logger.getLogger(LinearSolverTest.class.getName());
private static void solveAndPrint(
MPSolver solver, MPVariable[] variables, MPConstraint[] constraints) {
logger.info("Number of variables = " + solver.numVariables());
logger.info("Number of constraints = " + solver.numConstraints());
final MPSolver.ResultStatus status = solver.solve();
// Check that the problem has an optimal solution.
if (status != MPSolver.ResultStatus.OPTIMAL) {
logger.severe("The problem does not have an optimal solution!");
private void runBasicCtor(MPSolver.OptimizationProblemType solverType) {
if (!MPSolver.supportsProblemType(solverType)) {
return;
}
logger.info("Solution:");
ArrayList<MPVariable> vars = new ArrayList<>(Arrays.asList(variables));
vars.forEach(var -> logger.info(var.name() + " = " + var.solutionValue()));
logger.info("Optimal objective value = " + solver.objective().value());
logger.info("");
logger.info("Advanced usage:");
logger.info("Problem solved in " + solver.wallTime() + " milliseconds");
logger.info("Problem solved in " + solver.iterations() + " iterations");
if (solver.isMip())
return;
vars.forEach(var -> logger.info(var.name() + ": reduced cost " + var.reducedCost()));
final double[] activities = solver.computeConstraintActivities();
ArrayList<MPConstraint> cts = new ArrayList<>(Arrays.asList(constraints));
cts.forEach(ct
-> logger.info(ct.name() + ": dual value = " + ct.dualValue()
+ " activity = " + activities[ct.index()]));
}
@ParameterizedTest
@ValueSource(strings = {"GLOP", "GLPK_LP", "CLP", "GUROBI_LP"})
private static void testLinearProgramming(String problem_type) {
logger.info("------ Linear programming example with " + problem_type + " ------");
MPSolver solver = MPSolver.createSolver(problem_type);
if (solver == null)
return;
// x and y are continuous non-negative variables.
MPVariable x = solver.makeNumVar(0.0, Double.POSITIVE_INFINITY, "x");
MPVariable y = solver.makeNumVar(0.0, Double.POSITIVE_INFINITY, "y");
// Objectif function: Maximize 3x + 4y).
MPObjective objective = solver.objective();
objective.setCoefficient(x, 3);
objective.setCoefficient(y, 4);
objective.setMaximization();
// x + 2y <= 14.
final MPConstraint c0 = solver.makeConstraint(-Double.POSITIVE_INFINITY, 14.0, "c0");
c0.setCoefficient(x, 1);
c0.setCoefficient(y, 2);
// 3x - y >= 0.
final MPConstraint c1 = solver.makeConstraint(0.0, Double.POSITIVE_INFINITY, "c1");
c1.setCoefficient(x, 3);
c1.setCoefficient(y, -1);
// x - y <= 2.
final MPConstraint c2 = solver.makeConstraint(-Double.POSITIVE_INFINITY, 2.0, "c2");
c2.setCoefficient(x, 1);
c2.setCoefficient(y, -1);
solveAndPrint(solver, new MPVariable[] {x, y}, new MPConstraint[] {c0, c1, c2});
}
@ParameterizedTest
@ValueSource(strings = {"GLPK", "CBC", "SCIP", "SAT"})
private static void testMixedIntegerProgramming(String problem_type) {
logger.info("------ Mixed integer programming example with " + problem_type + " ------");
MPSolver solver = MPSolver.createSolver(problem_type);
if (solver == null)
return;
// x and y are continuous non-negative variables.
MPVariable x = solver.makeIntVar(0.0, Double.POSITIVE_INFINITY, "x");
MPVariable y = solver.makeIntVar(0.0, Double.POSITIVE_INFINITY, "y");
// Objectif function: Maximize x + 10 * y.
MPObjective objective = solver.objective();
objective.setCoefficient(x, 1);
objective.setCoefficient(y, 10);
objective.setMaximization();
// x + 7 * y <= 17.5.
final MPConstraint c0 = solver.makeConstraint(-Double.POSITIVE_INFINITY, 17.5, "c0");
c0.setCoefficient(x, 1);
c0.setCoefficient(y, 7);
// x <= 3.5.
final MPConstraint c1 = solver.makeConstraint(-Double.POSITIVE_INFINITY, 3.5, "c1");
c1.setCoefficient(x, 1);
c1.setCoefficient(y, 0);
solveAndPrint(solver, new MPVariable[] {x, y}, new MPConstraint[] {c0, c1});
}
@ParameterizedTest
@ValueSource(strings = {"SAT", "BOP"})
private static void testBooleanProgramming(String problem_type) {
logger.info("------ Boolean programming example with " + problem_type + " ------");
MPSolver solver = MPSolver.createSolver(problem_type);
if (solver == null)
return;
// x and y are continuous non-negative variables.
MPVariable x = solver.makeBoolVar("x");
MPVariable y = solver.makeBoolVar("y");
// Objectif function: Maximize 2 * x + y.
MPObjective objective = solver.objective();
objective.setCoefficient(x, 2);
objective.setCoefficient(y, 1);
objective.setMinimization();
// 1 <= x + 2 * y <= 3.
final MPConstraint c0 = solver.makeConstraint(1, 3, "c0");
c0.setCoefficient(x, 1);
c0.setCoefficient(y, 2);
solveAndPrint(solver, new MPVariable[] {x, y}, new MPConstraint[] {c0});
final MPSolver solver = new MPSolver("testBasicCtor", solverType);
assertNotNull(solver);
solver.solve();
}
@Test
public void testSameConstraintName() {
Loader.loadNativeLibraries();
MPSolver solver = MPSolver.createSolver("CBC");
boolean success = true;
public void testMPSolver_basicCtor() {
runBasicCtor(MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING);
runBasicCtor(MPSolver.OptimizationProblemType.GLPK_LINEAR_PROGRAMMING);
runBasicCtor(MPSolver.OptimizationProblemType.GLPK_MIXED_INTEGER_PROGRAMMING);
runBasicCtor(MPSolver.OptimizationProblemType.CLP_LINEAR_PROGRAMMING);
runBasicCtor(MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING);
}
@Test
public void testMPSolver_destructor() {
final MPSolver solver =
new MPSolver("testDestructor", MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING);
assertNotNull(solver);
solver.delete();
}
private void runLinearSolver(MPSolver.OptimizationProblemType problemType,
boolean integerVariables) {
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("Solver", problemType);
assertNotNull(solver);
final double infinity = MPSolver.infinity();
final MPVariable x1 = solver.makeNumVar(0.0, infinity, "x1");
final MPVariable x2 = solver.makeNumVar(0.0, infinity, "x2");
final MPVariable x3 = solver.makeNumVar(0.0, infinity, "x3");
if (integerVariables) {
x1.setInteger(true);
x2.setInteger(true);
x3.setInteger(true);
}
assertEquals(3, solver.numVariables());
final MPObjective objective = solver.objective();
objective.setCoefficient(x1, 10);
objective.setCoefficient(x2, 6);
objective.setCoefficient(x3, 4);
objective.setMaximization();
assertEquals(6.0, objective.getCoefficient(x2), 1e-6);
assertTrue(objective.maximization());
assertFalse(objective.minimization());
final MPConstraint c0 = solver.makeConstraint(-1000, 100.0);
c0.setCoefficient(x1, 1);
c0.setCoefficient(x2, 1);
c0.setCoefficient(x3, 1);
final MPConstraint c1 = solver.makeConstraint(-1000, 600.0);
c1.setCoefficient(x1, 10);
c1.setCoefficient(x2, 4);
c1.setCoefficient(x3, 5);
assertEquals(4.0, c1.getCoefficient(x2), 1e-6);
final MPConstraint c2 = solver.makeConstraint(-1000, 300.0);
c2.setCoefficient(x1, 2);
c2.setCoefficient(x2, 2);
c2.setCoefficient(x3, 6);
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
if (integerVariables) {
assertEquals(732.0, objective.value(), NUM_TOLERANCE);
assertEquals(33.0, x1.solutionValue(), NUM_TOLERANCE);
assertEquals(67.0, x2.solutionValue(), NUM_TOLERANCE);
assertEquals(0.0, x3.solutionValue(), NUM_TOLERANCE);
} else {
assertEquals(733.333333, objective.value(), NUM_TOLERANCE);
assertEquals(33.333333, x1.solutionValue(), NUM_TOLERANCE);
assertEquals(66.666667, x2.solutionValue(), NUM_TOLERANCE);
assertEquals(0, x3.solutionValue(), NUM_TOLERANCE);
}
}
@Test
public void testMPSolver_linearSolver() {
runLinearSolver(MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING, false);
runLinearSolver(MPSolver.OptimizationProblemType.CLP_LINEAR_PROGRAMMING, false);
runLinearSolver(MPSolver.OptimizationProblemType.GLPK_LINEAR_PROGRAMMING, false);
runLinearSolver(MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING, true);
runLinearSolver(MPSolver.OptimizationProblemType.GLPK_MIXED_INTEGER_PROGRAMMING, true);
runLinearSolver(MPSolver.OptimizationProblemType.SCIP_MIXED_INTEGER_PROGRAMMING, true);
}
private void runFirstLinearExample(MPSolver.OptimizationProblemType problemType) {
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("Solver", problemType);
assertNotNull(solver);
final MPVariable x1 = solver.makeNumVar(0.0, Double.POSITIVE_INFINITY, "x1");
final MPVariable x2 = solver.makeNumVar(0.0, Double.POSITIVE_INFINITY, "x2");
final MPVariable x3 = solver.makeNumVar(0.0, Double.POSITIVE_INFINITY, "x3");
assertEquals(3, solver.numVariables());
final double[] obj = {10.0, 6.0, 4.0};
final MPObjective objective = solver.objective();
objective.setCoefficient(x1, obj[0]);
objective.setCoefficient(x2, obj[1]);
objective.setCoefficient(x3, obj[2]);
objective.setMaximization();
final double rhs0 = 100.0;
final MPConstraint c0 = solver.makeConstraint(-Double.POSITIVE_INFINITY, rhs0, "c0");
final double[] coef0 = {1.0, 1.0, 1.0};
c0.setCoefficient(x1, coef0[0]);
c0.setCoefficient(x2, coef0[1]);
c0.setCoefficient(x3, coef0[2]);
final double rhs1 = 600.0;
final MPConstraint c1 = solver.makeConstraint(-Double.POSITIVE_INFINITY, rhs1, "c1");
final double[] coef1 = {10.0, 4.0, 5.0};
c1.setCoefficient(x1, coef1[0]);
c1.setCoefficient(x2, coef1[1]);
c1.setCoefficient(x3, coef1[2]);
final double rhs2 = 300.0;
final MPConstraint c2 = solver.makeConstraint(-Double.POSITIVE_INFINITY, rhs2);
final double[] coef2 = {2.0, 2.0, 6.0};
c2.setCoefficient(x1, coef2[0]);
c2.setCoefficient(x2, coef2[1]);
c2.setCoefficient(x3, coef2[2]);
assertEquals(3, solver.numConstraints());
assertEquals("c0", c0.name());
assertEquals("c1", c1.name());
assertEquals("auto_c_000000002", c2.name());
// The problem has an optimal solution.;
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(733.333333, objective.value(), NUM_TOLERANCE);
assertEquals(33.333333, x1.solutionValue(), NUM_TOLERANCE);
assertEquals(66.666667, x2.solutionValue(), NUM_TOLERANCE);
assertEquals(0, x3.solutionValue(), NUM_TOLERANCE);
// c0 and c1 are binding;
final double[] activities = solver.computeConstraintActivities();
assertEquals(3, activities.length);
assertEquals(3.333333, c0.dualValue(), NUM_TOLERANCE);
assertEquals(0.666667, c1.dualValue(), NUM_TOLERANCE);
assertEquals(rhs0, activities[c0.index()], NUM_TOLERANCE);
assertEquals(rhs1, activities[c1.index()], NUM_TOLERANCE);
assertEquals(MPSolver.BasisStatus.AT_UPPER_BOUND, c0.basisStatus());
assertEquals(MPSolver.BasisStatus.AT_UPPER_BOUND, c1.basisStatus());
// c2 is not binding;
assertEquals(0.0, c2.dualValue(), NUM_TOLERANCE);
assertEquals(200.0, activities[c2.index()], NUM_TOLERANCE);
assertEquals(MPSolver.BasisStatus.BASIC, c2.basisStatus());
// The optimum of the dual problem is equal to the optimum of the;
// primal problem.;
final double dualObjectiveValue = c0.dualValue() * rhs0 + c1.dualValue() * rhs1;
assertEquals(objective.value(), dualObjectiveValue, NUM_TOLERANCE);
// x1 and x2 are basic;
assertEquals(0.0, x1.reducedCost(), NUM_TOLERANCE);
assertEquals(0.0, x2.reducedCost(), NUM_TOLERANCE);
assertEquals(MPSolver.BasisStatus.BASIC, x1.basisStatus());
assertEquals(MPSolver.BasisStatus.BASIC, x2.basisStatus());
// x3 is non-basic;
final double x3ExpectedReducedCost =
(obj[2] - coef0[2] * c0.dualValue() - coef1[2] * c1.dualValue());
assertEquals(x3ExpectedReducedCost, x3.reducedCost(), NUM_TOLERANCE);
assertEquals(MPSolver.BasisStatus.AT_LOWER_BOUND, x3.basisStatus());
if (solver.problemType() == MPSolver.OptimizationProblemType.GLPK_LINEAR_PROGRAMMING) {
assertEquals(56.333333, solver.computeExactConditionNumber(), NUM_TOLERANCE);
}
}
@Test
public void testMPSolver_firstLinearExample() {
runFirstLinearExample(MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING);
runFirstLinearExample(MPSolver.OptimizationProblemType.CLP_LINEAR_PROGRAMMING);
runFirstLinearExample(MPSolver.OptimizationProblemType.GLPK_LINEAR_PROGRAMMING);
runFirstLinearExample(MPSolver.OptimizationProblemType.GUROBI_LINEAR_PROGRAMMING);
}
private void runFirstMIPExample(MPSolver.OptimizationProblemType problemType) {
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("Solver", problemType);
assertNotNull(solver);
// Integer variables shouldn't have infinite bounds, nor really large bounds:
// it can make your solver behave erratically. If you have integer variables
// with a truly large dynamic range you should consider making it non-integer.
final double upperBound = 1000;
final MPVariable x1 = solver.makeIntVar(0.0, upperBound, "x1");
final MPVariable x2 = solver.makeIntVar(0.0, upperBound, "x2");
solver.objective().setCoefficient(x1, 1);
solver.objective().setCoefficient(x2, 2);
final MPConstraint ct = solver.makeConstraint(17, Double.POSITIVE_INFINITY);
ct.setCoefficient(x1, 3);
ct.setCoefficient(x2, 2);
// Check the solution.
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
final double optObjValue = 6.0;
assertEquals(optObjValue, solver.objective().value(), 1e-6);
assertEquals(optObjValue, solver.objective().bestBound(), 1e-6);
final double optRowActivity = 18.0;
assertEquals(optRowActivity, solver.computeConstraintActivities()[ct.index()], NUM_TOLERANCE);
// BOP does not support nodes().
if (solver.problemType() != MPSolver.OptimizationProblemType.BOP_INTEGER_PROGRAMMING) {
assertThat(solver.nodes()).isAtLeast(0);
}
}
@Test
public void testMPSolver_firstMIPExample() {
runFirstMIPExample(MPSolver.OptimizationProblemType.BOP_INTEGER_PROGRAMMING);
runFirstMIPExample(MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING);
runFirstMIPExample(MPSolver.OptimizationProblemType.GLPK_MIXED_INTEGER_PROGRAMMING);
runFirstMIPExample(MPSolver.OptimizationProblemType.SCIP_MIXED_INTEGER_PROGRAMMING);
runFirstMIPExample(MPSolver.OptimizationProblemType.SAT_INTEGER_PROGRAMMING);
runFirstMIPExample(MPSolver.OptimizationProblemType.GUROBI_MIXED_INTEGER_PROGRAMMING);
}
private void runSuccessiveObjectives(MPSolver.OptimizationProblemType problemType) {
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("Solver", problemType);
assertNotNull(solver);
final MPVariable x1 = solver.makeNumVar(0, 10, "var1");
final MPVariable x2 = solver.makeNumVar(0, 10, "var2");
final MPConstraint ct = solver.makeConstraint(0, 10);
ct.setCoefficient(x1, 1);
ct.setCoefficient(x2, 2);
final MPObjective objective = solver.objective();
objective.setCoefficient(x1, 1);
objective.setCoefficient(x2, 0);
objective.setOptimizationDirection(true);
// Check the solution.
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(10.0, x1.solutionValue(), NUM_TOLERANCE);
assertEquals(0.0, x2.solutionValue(), NUM_TOLERANCE);
objective.setCoefficient(x1, 0);
objective.setCoefficient(x2, 1);
objective.setOptimizationDirection(true);
// Check the solution
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(0.0, x1.solutionValue(), NUM_TOLERANCE);
assertEquals(5.0, x2.solutionValue(), NUM_TOLERANCE);
objective.setCoefficient(x1, -1);
objective.setCoefficient(x2, 0);
objective.setOptimizationDirection(false);
// Check the solution.
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(10.0, x1.solutionValue(), NUM_TOLERANCE);
assertEquals(0.0, x2.solutionValue(), NUM_TOLERANCE);
}
@Test
public void testMPSolver_successiveObjectives() {
runSuccessiveObjectives(MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.CLP_LINEAR_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.GLPK_LINEAR_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.GUROBI_LINEAR_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.GLPK_MIXED_INTEGER_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.SCIP_MIXED_INTEGER_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.SAT_INTEGER_PROGRAMMING);
runSuccessiveObjectives(MPSolver.OptimizationProblemType.GUROBI_MIXED_INTEGER_PROGRAMMING);
}
private void runObjectiveOffset(MPSolver.OptimizationProblemType problemType) {
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("Solver", problemType);
assertNotNull(solver);
final MPVariable x1 = solver.makeNumVar(1.0, 10.0, "x1");
final MPVariable x2 = solver.makeNumVar(1.0, 10.0, "x2");
final MPConstraint ct = solver.makeConstraint(0, 4.0);
ct.setCoefficient(x1, 1);
ct.setCoefficient(x2, 2);
final double objectiveOffset = 10.0;
// Simple minimization.
final MPObjective objective = solver.objective();
objective.setCoefficient(x1, 1.0);
objective.setCoefficient(x2, 1.0);
objective.setOffset(objectiveOffset);
objective.setOptimizationDirection(false);
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(2.0 + objectiveOffset, objective.value(), 1e-6);
// Offset is provided in several separate constants.
objective.setCoefficient(x1, 1.0);
objective.setCoefficient(x2, 1.0);
objective.setOffset(-1.0);
objective.setOffset(objectiveOffset + objective.offset());
objective.setOffset(1.0 + objective.offset());
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(2.0 + objectiveOffset, objective.value(), 1e-6);
// Simple maximization.
objective.setCoefficient(x1, 1.0);
objective.setCoefficient(x2, 1.0);
objective.setOffset(objectiveOffset);
objective.setOptimizationDirection(true);
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(3.0 + objectiveOffset, objective.value(), 1e-6);
}
@Test
public void testMPSolver_objectiveOffset() {
runObjectiveOffset(MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.CLP_LINEAR_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.GLPK_LINEAR_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.GUROBI_LINEAR_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.CBC_MIXED_INTEGER_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.GLPK_MIXED_INTEGER_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.SCIP_MIXED_INTEGER_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.SAT_INTEGER_PROGRAMMING);
runObjectiveOffset(MPSolver.OptimizationProblemType.GUROBI_MIXED_INTEGER_PROGRAMMING);
}
@Test
public void testMPSolver_lazyConstraints() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.SCIP_MIXED_INTEGER_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("testLazyConstraints", problemType);
assertNotNull(solver);
final double infinity = MPSolver.infinity();
final MPVariable x = solver.makeIntVar(0, infinity, "x");
final MPVariable y = solver.makeIntVar(0, infinity, "y");
final MPConstraint ct1 = solver.makeConstraint(0, 10.0);
ct1.setCoefficient(x, 2.0);
ct1.setCoefficient(y, 1.0);
final MPConstraint ct2 = solver.makeConstraint(0, 10.0);
ct2.setCoefficient(x, 1.0);
ct2.setCoefficient(y, 2.0);
ct2.setIsLazy(true);
assertFalse(ct1.isLazy());
assertTrue(ct2.isLazy());
final MPObjective objective = solver.objective();
objective.setCoefficient(x, 1.0);
objective.setCoefficient(y, 1.0);
objective.setOptimizationDirection(true);
assertEquals(MPSolver.ResultStatus.OPTIMAL, solver.solve());
assertEquals(solver.objective().value(), 6.0, NUM_TOLERANCE);
}
@Test
public void testMPSolver_sameConstraintName() {
MPSolver solver = MPSolver.createSolver("GLOP");
assertNotNull(solver);
boolean success = false;
solver.makeConstraint("my_const_name");
try {
solver.makeConstraint("my_const_name");
} catch (Throwable e) {
System.out.println(e);
success = false;
success = true;
}
logger.info("Success = " + success);
assertTrue(success);
}
@Test
public void testSetHintAndSolverGetters() {
Loader.loadNativeLibraries();
MPSolver solver = MPSolver.createSolver("GLOP");
public void testMPSolver_exportModelToProto() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("testExportModelToProto", problemType);
assertNotNull(solver);
solver.makeNumVar(0.0, 10.0, "x1");
solver.makeConstraint(0.0, 0.0);
solver.objective().setOptimizationDirection(true);
final MPModelProto model = solver.exportModelToProto();
assertEquals(1, model.getVariableCount());
assertEquals(1, model.getConstraintCount());
assertTrue(model.getMaximize());
}
@Test
public void testMPsolver_createSolutionResponseProto() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("testCreateSolutionResponseProto", problemType);
assertNotNull(solver);
final MPVariable x1 = solver.makeNumVar(0.0, 10.0, "x1");
solver.objective().setCoefficient(x1, 1.0);
solver.objective().setOptimizationDirection(true);
solver.solve();
final MPSolutionResponse response = solver.createSolutionResponseProto();
assertEquals(MPSolverResponseStatus.MPSOLVER_OPTIMAL, response.getStatus());
assertEquals(10.0, response.getObjectiveValue(), 1e-6);
}
@Test
public void testMPSolver_solveWithProto() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPModelProto.Builder modelBuilder = MPModelProto.newBuilder().setMaximize(true);
final MPVariableProto variable = MPVariableProto.newBuilder()
.setLowerBound(0.0)
.setUpperBound(10.0)
.setName("x1")
.setIsInteger(false)
.setObjectiveCoefficient(1.0)
.build();
modelBuilder.addVariable(variable);
final MPModelRequest request = MPModelRequest.newBuilder()
.setModel(modelBuilder.build())
.setSolverType(MPModelRequest.SolverType.GLOP_LINEAR_PROGRAMMING)
.build();
final MPSolutionResponse response = MPSolver.solveWithProto(request);
assertEquals(MPSolverResponseStatus.MPSOLVER_OPTIMAL, response.getStatus());
assertEquals(10.0, response.getObjectiveValue(), 1e-6);
}
@Test
public void testModelExport() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("tesModelExport", problemType);
assertNotNull(solver);
final double infinity = MPSolver.infinity();
// x1, x2 and x3 are continuous non-negative variables.
final MPVariable x1 = solver.makeNumVar(0.0, infinity, "x1");
// Maximize 10 * x1.
solver.objective().setCoefficient(x1, 10);
solver.objective().setMinimization();
// 5 * x1 <= 30.
final MPConstraint c0 = solver.makeConstraint(-infinity, 100.0);
c0.setCoefficient(x1, 5);
final MPModelExportOptions obfuscate = new MPModelExportOptions();
obfuscate.setObfuscate(true);
String out = solver.exportModelAsLpFormat();
assertThat(out).isNotEmpty();
out = solver.exportModelAsLpFormat(obfuscate);
assertThat(out).isNotEmpty();
out = solver.exportModelAsMpsFormat();
assertThat(out).isNotEmpty();
out = solver.exportModelAsMpsFormat(obfuscate);
assertThat(out).isNotEmpty();
}
@Test
public void testMPSolver_wrongModelExport() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("testWrongModelExport", problemType);
assertNotNull(solver);
// Test that forbidden names are renamed.
solver.makeBoolVar("<-%$#!&~-+ ⌂"); // Some illegal name.
String out = solver.exportModelAsLpFormat();
assertThat(out).isNotEmpty();
out = solver.exportModelAsMpsFormat();
assertThat(out).isNotEmpty();
}
@Test
public void testMPSolver_setHint() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("testSetHint", problemType);
assertNotNull(solver);
final MPVariable[] variables = {
solver.makeNumVar(0.0, 10.0, "x1"), solver.makeNumVar(0.0, 10.0, "x2")
};
final double[] values = {5.0, 6.0};
solver.setHint(variables, values);
final MPModelProto model = solver.exportModelToProto();
final PartialVariableAssignment hint = model.getSolutionHint();
assertEquals(2, hint.getVarIndexCount());
assertEquals(2, hint.getVarValueCount());
assertEquals(0, hint.getVarIndex(0));
assertEquals(5.0, hint.getVarValue(0), 1e-6);
assertEquals(1, hint.getVarIndex(1));
assertEquals(6.0, hint.getVarValue(1), 1e-6);
}
@Test
public void testMPSolver_issue132() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.CLP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("CoinError", problemType);
assertNotNull(solver);
final double infinity = MPSolver.infinity();
final MPVariable x0 = solver.makeNumVar(0.0, 1.0, "x0");
final MPVariable x1 = solver.makeNumVar(0.0, 0.3, "x1");
final MPVariable x2 = solver.makeNumVar(0.0, 0.3, "x2");
final MPVariable x3 = solver.makeNumVar(-infinity, infinity, "x3");
final MPObjective obj = solver.objective();
obj.setCoefficient(x1, 2.655523);
obj.setCoefficient(x2, -2.70917);
obj.setCoefficient(x3, 1);
obj.setMaximization();
final MPConstraint c0 = solver.makeConstraint(-infinity, 0.302499);
c0.setCoefficient(x3, 1);
c0.setCoefficient(x0, -3.484345);
final MPConstraint c1 = solver.makeConstraint(-infinity, 0.507194);
c1.setCoefficient(x3, 1);
c1.setCoefficient(x0, -3.074807);
final MPConstraint c2 = solver.makeConstraint(0.594, 0.594);
c2.setCoefficient(x0, 1);
c2.setCoefficient(x1, 1.01);
c2.setCoefficient(x2, -0.99);
System.out.println("Number of variables = " + solver.numVariables());
System.out.println("Number of constraints = " + solver.numConstraints());
solver.enableOutput();
System.out.println(solver.exportModelAsLpFormat());
System.out.println(solver.solve());
}
@Test
public void testMPSolver_setHintAndSolverGetters() {
final MPSolver.OptimizationProblemType problemType =
MPSolver.OptimizationProblemType.GLOP_LINEAR_PROGRAMMING;
if (!MPSolver.supportsProblemType(problemType)) {
return;
}
final MPSolver solver = new MPSolver("glop", problemType);
assertNotNull(solver);
// x and y are continuous non-negative variables.
MPVariable x = solver.makeIntVar(0.0, Double.POSITIVE_INFINITY, "x");
MPVariable y = solver.makeIntVar(0.0, Double.POSITIVE_INFINITY, "y");
final MPVariable x = solver.makeIntVar(0.0, Double.POSITIVE_INFINITY, "x");
final MPVariable y = solver.makeIntVar(0.0, Double.POSITIVE_INFINITY, "y");
// Objectif function: Maximize x + 10 * y.
MPObjective objective = solver.objective();
final MPObjective objective = solver.objective();
objective.setCoefficient(x, 1);
objective.setCoefficient(y, 10);
objective.setMaximization();
@@ -199,13 +635,18 @@ public class LinearSolverTest {
c1.setCoefficient(x, 1);
c1.setCoefficient(y, 0);
if (solver.constraints().length != 2) {
throw new RuntimeException("WrongConstraintLength");
}
if (solver.variables().length != 2) {
throw new RuntimeException("WrongConstraintLength");
}
// Test solver getters.
final MPVariable[] variables = solver.variables();
assertThat(variables).hasLength(2);
final MPConstraint[] constraints = solver.constraints();
assertThat(constraints).hasLength(2);
solver.setHint(new MPVariable[] {x, y}, new double[] {2.0, 3.0});
// Test API compiles.
solver.setHint(variables, new double[] {2.0, 3.0});
assertEquals("y", variables[1].name());
assertEquals("c0", constraints[0].name());
// TODO(user): Add API to query the hint.
assertFalse(solver.setNumThreads(4));
}
}

View File

@@ -10,9 +10,13 @@
// 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.
package com.google.ortools;
import static java.lang.Math.abs;
package com.google.ortools.constraintsolver;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.google.ortools.Loader;
import com.google.ortools.constraintsolver.Assignment;
@@ -22,225 +26,615 @@ import com.google.ortools.constraintsolver.RoutingModel;
import com.google.ortools.constraintsolver.RoutingSearchParameters;
import com.google.ortools.constraintsolver.main;
import com.google.ortools.constraintsolver.IntBoolPair;
import java.util.logging.Logger;
import com.google.protobuf.Duration;
import java.util.ArrayList;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
/** Tests the Routing java interface. */
public class RoutingSolverTest {
private static final Logger logger = Logger.getLogger(RoutingSolverTest.class.getName());
public final class RoutingSolverTest {
private ArrayList<Integer[]> coordinates;
@Test
public void testRoutingTransitMatrix() {
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
logger.info("testRoutingTransitMatrix...");
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(5 /*location*/, 1 /*vehicle*/, 0 /*depot*/);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Define cost of each arc.
int transitCallbackIndex;
long[][] matrix = {
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
};
transitCallbackIndex = routing.registerTransitMatrix(matrix);
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
if (null == solution)
throw new AssertionError("null == solution");
if (5 != solution.objectiveValue())
throw new AssertionError("5 != objective");
logger.info("testRoutingTransitMatrix...DONE");
coordinates = new ArrayList<>();
coordinates.add(new Integer[] {0, 0});
coordinates.add(new Integer[] {-1, 0});
coordinates.add(new Integer[] {-1, 2});
coordinates.add(new Integer[] {2, 1});
coordinates.add(new Integer[] {1, 0});
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
public void testRoutingTransitCallback(boolean enableGC) {
Loader.loadNativeLibraries();
logger.info("testRoutingTransitCallback (enable gc:" + enableGC + ")...");
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(5 /*location*/, 1 /*vehicle*/, 0 /*depot*/);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Define cost of each arc.
int transitCallbackIndex;
if (true) {
transitCallbackIndex = routing.registerTransitCallback((long fromIndex, long toIndex) -> {
// Convert from routing variable Index to user NodeIndex.
int fromNode = manager.indexToNode(fromIndex);
int toNode = manager.indexToNode(toIndex);
return abs(toNode - fromNode);
});
}
if (enableGC) {
System.gc();
}
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
if (null == solution)
throw new AssertionError("null == solution");
if (8 != solution.objectiveValue())
throw new AssertionError("8 != objective");
logger.info("testRoutingTransitCallback (enable gc:" + enableGC + ")...DONE");
public LongBinaryOperator createManhattanCostCallback(RoutingIndexManager manager) {
return (long i, long j) -> {
final int firstIndex = manager.indexToNode(i);
final int secondIndex = manager.indexToNode(j);
final Integer[] firstCoordinate = coordinates.get(firstIndex);
final Integer[] secondCoordinate = coordinates.get(secondIndex);
return (long) Math.abs(firstCoordinate[0] - secondCoordinate[0])
+ Math.abs(firstCoordinate[1] - secondCoordinate[1]);
};
}
public LongUnaryOperator createUnaryCostCallback(RoutingIndexManager manager) {
return (long fromIndex) -> {
final int fromNode = manager.indexToNode(fromIndex);
final Integer[] firstCoordinate = coordinates.get(fromNode);
return (long) Math.abs(firstCoordinate[0]) + Math.abs(firstCoordinate[1]);
};
}
public LongBinaryOperator createReturnOneCallback() {
return (long i, long j) -> 1;
}
@Test
public void testRoutingMatrixDimension() {
Loader.loadNativeLibraries();
logger.info("testRoutingMatrixDimension...");
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(5 /*location*/, 1 /*vehicle*/, 0 /*depot*/);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Define cost of each arc.
int transitCallbackIndex;
long[][] matrix = {
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
{1, 1, 1, 1, 1},
public void testRoutingIndexManager() {
final RoutingIndexManager manager = new RoutingIndexManager(42, 3, 7);
assertNotNull(manager);
assertEquals(42, manager.getNumberOfNodes());
assertEquals(3, manager.getNumberOfVehicles());
assertEquals(42 + 3 * 2 - 1, manager.getNumberOfIndices());
for (int i = 0; i < manager.getNumberOfVehicles(); ++i) {
assertEquals(7, manager.indexToNode(manager.getStartIndex(i)));
assertEquals(7, manager.indexToNode(manager.getEndIndex(i)));
}
}
@Test
public void testRoutingIndexManager_multiDepotSame() {
final RoutingIndexManager manager =
new RoutingIndexManager(42, 3, new int[] {7, 7, 7}, new int[] {7, 7, 7});
assertNotNull(manager);
assertEquals(42, manager.getNumberOfNodes());
assertEquals(3, manager.getNumberOfVehicles());
assertEquals(42 + 3 * 2 - 1, manager.getNumberOfIndices());
for (int i = 0; i < manager.getNumberOfVehicles(); ++i) {
assertEquals(7, manager.indexToNode(manager.getStartIndex(i)));
assertEquals(7, manager.indexToNode(manager.getEndIndex(i)));
}
}
@Test
public void testRoutingIndexManager_multiDepotAllDifferent() {
final RoutingIndexManager manager =
new RoutingIndexManager(42, 3, new int[] {1, 2, 3}, new int[] {4, 5, 6});
assertNotNull(manager);
assertEquals(42, manager.getNumberOfNodes());
assertEquals(3, manager.getNumberOfVehicles());
assertEquals(42, manager.getNumberOfIndices());
for (int i = 0; i < manager.getNumberOfVehicles(); ++i) {
assertEquals(i + 1, manager.indexToNode(manager.getStartIndex(i)));
assertEquals(i + 4, manager.indexToNode(manager.getEndIndex(i)));
}
}
@Test
public void testRoutingModel() {
final RoutingIndexManager manager =
new RoutingIndexManager(42, 3, new int[] {1, 2, 3}, new int[] {4, 5, 6});
assertNotNull(manager);
final RoutingModel model = new RoutingModel(manager);
assertNotNull(model);
for (int i = 0; i < manager.getNumberOfVehicles(); ++i) {
assertEquals(i + 1, manager.indexToNode(model.start(i)));
assertEquals(i + 4, manager.indexToNode(model.end(i)));
}
}
@Test
public void testRoutingModelParameters() {
final RoutingModelParameters parameters = main.defaultRoutingModelParameters();
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager, parameters);
assertEquals(1, model.vehicles());
}
@Test
public void testRoutingModel_solveWithParameters() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
final RoutingSearchParameters parameters = main.defaultRoutingSearchParameters();
final LongBinaryOperator callback = createManhattanCostCallback(manager);
final int cost = model.registerTransitCallback(callback);
System.gc();
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
Assignment solution = model.solveWithParameters(parameters);
assertEquals(10, solution.objectiveValue());
solution = model.solveFromAssignmentWithParameters(solution, parameters);
assertEquals(10, solution.objectiveValue());
}
@Test
public void testRoutingModel_costsAndSolve() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(5, model.nodes());
final LongBinaryOperator callback = createManhattanCostCallback(manager);
final int cost = model.registerTransitCallback(callback);
System.gc();
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(10, solution.objectiveValue());
}
@Test
public void testRoutingModel_matrixTransitOwnership() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(5, model.nodes());
final long[][] matrix = {
{0, 1, 3, 3, 1},
{1, 0, 2, 4, 2},
{3, 2, 0, 4, 4},
{3, 4, 4, 0, 2},
{1, 2, 4, 2, 0},
};
IntBoolPair result = routing.addMatrixDimension(
matrix,
/*capacity=*/10,
final int cost = model.registerTransitMatrix(matrix);
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(10, solution.objectiveValue());
}
@Test
public void testRoutingModel_transitCallbackOwnership() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(5, model.nodes());
final int cost = model.registerTransitCallback(createManhattanCostCallback(manager));
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(10, solution.objectiveValue());
}
@Test
public void testRoutingModel_lambdaTransitCallbackOwnership() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(5, model.nodes());
final int cost = model.registerTransitCallback(
(long fromIndex, long toIndex) -> {
final int fromNode = manager.indexToNode(fromIndex);
final int toNode = manager.indexToNode(toIndex);
return (long) Math.abs(toNode - fromNode);
});
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(8, solution.objectiveValue());
}
@Test
public void testRoutingModel_unaryTransitVectorOwnership() {
final RoutingIndexManager manager = new RoutingIndexManager(10, 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(10, model.nodes());
final long[] vector = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
final int cost = model.registerUnaryTransitVector(vector);
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(45, solution.objectiveValue());
}
@Test
public void testRoutingModel_unaryTransitCallbackOwnership() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(5, model.nodes());
final int cost = model.registerUnaryTransitCallback(createUnaryCostCallback(manager));
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(8, solution.objectiveValue());
}
@Test
public void testRoutingModel_lambdaUnaryTransitCallbackOwnership() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(5, model.nodes());
final int cost = model.registerUnaryTransitCallback(
(long fromIndex) -> {
final int fromNode = manager.indexToNode(fromIndex);
return (long) Math.abs(fromNode);
});
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(cost);
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(10, solution.objectiveValue());
}
@Test
public void testRoutingModel_routesToAssignment() {
final int vehicles = coordinates.size() - 1;
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), vehicles, 0);
final RoutingModel model = new RoutingModel(manager);
model.closeModel();
long[][] routes = new long[vehicles][];
for (int i = 0; i < vehicles; ++i) {
// Each route has a single node
routes[i] = new long[1];
routes[i][0] = manager.nodeToIndex(i + 1);
}
Assignment assignment = new Assignment(model.solver());
model.routesToAssignment(routes, false, true, assignment);
for (int i = 0; i < vehicles; ++i) {
assertEquals(assignment.value(model.nextVar(model.start(i))), i + 1);
assertEquals(assignment.value(model.nextVar(i + 1)), model.end(i));
}
}
@Test
public void testRoutingModel_addDisjunction() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator callback = createManhattanCostCallback(manager);
final int cost = model.registerTransitCallback(callback);
model.setArcCostEvaluatorOfAllVehicles(cost);
int[] a = new int[2];
a[0] = 2;
a[1] = 3;
int[] b = new int[1];
b[0] = 1;
int[] c = new int[1];
c[0] = 4;
model.addDisjunction(manager.nodesToIndices(a));
model.addDisjunction(manager.nodesToIndices(b));
model.addDisjunction(manager.nodesToIndices(c));
Assignment solution = model.solve(null);
assertEquals(8, solution.objectiveValue());
}
@Test
public void testRoutingModel_addConstantDimension() {
final RoutingIndexManager manager = new RoutingIndexManager(10, 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(10, model.nodes());
final IntBoolPair pair = model.addConstantDimension(
1,
/*capacity=*/100,
/*fix_start_cumul_to_zero=*/true,
"Dimension");
routing.setArcCostEvaluatorOfAllVehicles(result.getFirst());
// Setting first solution heuristic.
assertEquals(1, pair.getFirst());
assertTrue(pair.getSecond());
RoutingDimension dimension = model.getMutableDimension("Dimension");
dimension.setSpanCostCoefficientForAllVehicles(2);
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.setTimeLimit(Duration.newBuilder().setSeconds(10))
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
if (null == solution)
throw new AssertionError("null == solution");
if (5 != solution.objectiveValue())
throw new AssertionError("5 != objective");
logger.info("testRoutingMatrixDimension...DONE");
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solveWithParameters(searchParameters);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(20, solution.objectiveValue());
}
@Test
public void testRoutingUnaryTransitVector() {
Loader.loadNativeLibraries();
logger.info("testRoutingUnaryTransitVector...");
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(5 /*location*/, 1 /*vehicle*/, 0 /*depot*/);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Define cost of each arc.
int transitCallbackIndex;
long[] vector = {1, 1, 1, 1, 1};
transitCallbackIndex = routing.registerUnaryTransitVector(vector);
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
if (null == solution)
throw new AssertionError("null == solution");
if (5 != solution.objectiveValue())
throw new AssertionError("5 != objective");
logger.info("testRoutingUnaryTransitVector...DONE");
}
@ParameterizedTest
@ValueSource(booleans = {false, true})
public void testRoutingUnaryTransitCallback(boolean enableGC) {
Loader.loadNativeLibraries();
logger.info("testRoutingUnaryTransitCallback (enable gc:" + enableGC + ")...");
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(5 /*location*/, 1 /*vehicle*/, 0 /*depot*/);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Define cost of each arc.
int transitCallbackIndex;
if (true) {
transitCallbackIndex = routing.registerUnaryTransitCallback((long fromIndex) -> {
// Convert from routing variable Index to user NodeIndex.
int fromNode = manager.indexToNode(fromIndex);
return abs(fromNode);
});
}
if (enableGC) {
System.gc();
}
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
if (null == solution)
throw new AssertionError("null == solution");
if (10 != solution.objectiveValue())
throw new AssertionError("10 != objective");
logger.info("testRoutingUnaryTransitCallback (enable gc:" + enableGC + ")...DONE");
}
@Test
public void testRoutingVectorDimension() {
Loader.loadNativeLibraries();
logger.info("testRoutingVectorDimension...");
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(5 /*location*/, 1 /*vehicle*/, 0 /*depot*/);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Define cost of each arc.
int transitCallbackIndex;
long[] vector = {1, 1, 1, 1, 1};
IntBoolPair result = routing.addVectorDimension(
public void testRoutingModel_addVectorDimension() {
final RoutingIndexManager manager = new RoutingIndexManager(10, 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(10, model.nodes());
final long[] vector = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
final IntBoolPair pair = model.addVectorDimension(
vector,
/*capacity=*/10,
/*capacity=*/100,
/*fix_start_cumul_to_zero=*/true,
"Dimension");
routing.setArcCostEvaluatorOfAllVehicles(result.getFirst());
// Setting first solution heuristic.
assertEquals(1, pair.getFirst());
assertTrue(pair.getSecond());
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(pair.getFirst());
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.setTimeLimit(Duration.newBuilder().setSeconds(10))
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
if (null == solution)
throw new AssertionError("null == solution");
if (5 != solution.objectiveValue())
throw new AssertionError("5 != objective");
logger.info("testRoutingMatrixDimension...DONE");
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solveWithParameters(searchParameters);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(45, solution.objectiveValue());
}
@Test
public void testRoutingModel_addMatrixDimension() {
final RoutingIndexManager manager = new RoutingIndexManager(5, 1, 0);
final RoutingModel model = new RoutingModel(manager);
assertEquals(5, model.nodes());
final long[][] matrix = {
{0, 1, 3, 3, 1},
{1, 0, 2, 4, 2},
{3, 2, 0, 4, 4},
{3, 4, 4, 0, 2},
{1, 2, 4, 2, 0},
};
final IntBoolPair pair = model.addMatrixDimension(
matrix,
/*capacity=*/100,
/*fix_start_cumul_to_zero=*/true,
"Dimension");
assertEquals(1, pair.getFirst());
assertTrue(pair.getSecond());
System.gc(); // model should keep alive the callback
model.setArcCostEvaluatorOfAllVehicles(pair.getFirst());
final RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.setTimeLimit(Duration.newBuilder().setSeconds(10))
.build();
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solveWithParameters(searchParameters);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(10, solution.objectiveValue());
}
@Test
public void testRoutingModel_addDimension() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator manhattanCostCallback = createManhattanCostCallback(manager);
final int cost = model.registerTransitCallback(manhattanCostCallback);
model.setArcCostEvaluatorOfAllVehicles(cost);
final LongBinaryOperator transit = (long firstIndex, long secondIndex) -> {
int firstNode = manager.indexToNode(firstIndex);
int secondNode = manager.indexToNode(secondIndex);
if (firstNode >= coordinates.size()) {
firstNode = 0;
}
if (secondNode >= coordinates.size()) {
secondNode = 0;
}
long distanceTime = manhattanCostCallback.applyAsLong(firstIndex, secondIndex) * 10;
long visitingTime = 1;
return distanceTime + visitingTime;
};
assertTrue(
model.addDimension(model.registerTransitCallback(transit), 1000, 1000, true, "time"));
RoutingDimension dimension = model.getMutableDimension("time");
for (int i = 1; i < coordinates.size(); i++) {
int[] a = new int[1];
a[0] = i;
model.addDisjunction(manager.nodesToIndices(a), 10);
dimension.cumulVar(i).setMin(0);
dimension.cumulVar(i).setMax(40);
}
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.setTimeLimit(Duration.newBuilder().setSeconds(10))
.build();
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
Assignment solution = model.solveWithParameters(searchParameters);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
solution = model.solve(solution);
assertNotNull(solution);
assertTrue(solution.objectiveValue() >= 24 && solution.objectiveValue() <= 30);
for (long i = 1; i < coordinates.size(); i++) {
assertTrue(
solution.min(dimension.cumulVar(i)) >= 0 && solution.max(dimension.cumulVar(i)) <= 40);
}
}
@Test
public void testRoutingModel_dimensionVehicleSpanCost() {
final RoutingIndexManager manager = new RoutingIndexManager(2, 1, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator callback = createReturnOneCallback();
assertTrue(
model.addDimension(model.registerTransitCallback(callback), 1000, 1000, true, "time"));
RoutingDimension dimension = model.getMutableDimension("time");
dimension.cumulVar(1).setMin(10);
dimension.setSpanCostCoefficientForAllVehicles(2);
assertEquals(2, dimension.getSpanCostCoefficientForVehicle(0));
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(2 * (10 + 1), solution.objectiveValue());
}
@Test
public void testRoutingModel_dimensionGlobalSpanCost() {
final RoutingIndexManager manager = new RoutingIndexManager(3, 2, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator callback = createReturnOneCallback();
assertTrue(
model.addDimension(model.registerTransitCallback(callback), 1000, 1000, false, "time"));
RoutingDimension timeDimension = model.getMutableDimension("time");
timeDimension.cumulVar(1).setMin(10);
model.vehicleVar(1).setValue(0);
timeDimension.cumulVar(2).setMax(2);
model.vehicleVar(2).setValue(1);
timeDimension.setGlobalSpanCostCoefficient(2);
assertEquals(2, timeDimension.getGlobalSpanCostCoefficient());
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
assertEquals(2 * (11 - 1), solution.objectiveValue());
}
@Test
public void testRoutingModel_cumulVarSoftUpperBound() {
final RoutingIndexManager manager = new RoutingIndexManager(2, 1, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator callback = createReturnOneCallback();
assertTrue(
model.addDimension(model.registerTransitCallback(callback), 1000, 1000, false, "time"));
RoutingDimension dimension = model.getMutableDimension("time");
assertEquals(1000, dimension.getCumulVarSoftUpperBound(1));
assertEquals(0, dimension.getCumulVarSoftUpperBoundCoefficient(1));
dimension.setCumulVarSoftUpperBound(1, 5, 1);
assertEquals(5, dimension.getCumulVarSoftUpperBound(1));
assertEquals(1, dimension.getCumulVarSoftUpperBoundCoefficient(1));
}
@Test
public void testRoutingModel_addDimensionWithVehicleCapacity() {
final RoutingIndexManager manager = new RoutingIndexManager(1, 3, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator callback = createReturnOneCallback();
final long[] capacity = {5, 6, 7};
model.addDimensionWithVehicleCapacity(
model.registerTransitCallback(callback), 1000, capacity, false, "dim");
RoutingDimension dimension = model.getMutableDimension("dim");
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
for (int vehicle = 0; vehicle < 3; ++vehicle) {
assertEquals(vehicle + 4, solution.max(dimension.cumulVar(model.start(vehicle))));
assertEquals(vehicle + 5, solution.max(dimension.cumulVar(model.end(vehicle))));
}
}
@Test
public void testRoutingModel_addDimensionWithVehicleTransits() {
final RoutingIndexManager manager = new RoutingIndexManager(1, 3, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator[] callbacks = new LongBinaryOperator[3];
int[] transits = new int[3];
for (int i = 0; i < 3; ++i) {
final int value = i + 1;
callbacks[i] = (long firstIndex, long secondIndex) -> value;
transits[i] = model.registerTransitCallback(callbacks[i]);
}
long capacity = 5;
model.addDimensionWithVehicleTransits(transits, 1000, capacity, false, "dim");
RoutingDimension dimension = model.getMutableDimension("dim");
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
for (int vehicle = 0; vehicle < 3; ++vehicle) {
assertEquals(
capacity - (vehicle + 1), solution.max(dimension.cumulVar(model.start(vehicle))));
assertEquals(capacity, solution.max(dimension.cumulVar(model.end(vehicle))));
}
}
@Test
public void testRoutingModel_addDimensionWithVehicleTransitAndCapacity() {
final RoutingIndexManager manager = new RoutingIndexManager(1, 3, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator[] callbacks = new LongBinaryOperator[3];
final int[] transits = new int[3];
for (int i = 0; i < 3; ++i) {
final int value = i + 1;
callbacks[i] = (long firstIndex, long secondIndex) -> value;
transits[i] = model.registerTransitCallback(callbacks[i]);
}
long[] capacity = new long[3];
for (int i = 0; i < 3; ++i) {
capacity[i] = i + 5L;
}
model.addDimensionWithVehicleTransitAndCapacity(transits, 1000, capacity, false, "dim");
final RoutingDimension dimension = model.getMutableDimension("dim");
assertEquals(RoutingModel.ROUTING_NOT_SOLVED, model.status());
final Assignment solution = model.solve(null);
assertEquals(RoutingModel.ROUTING_SUCCESS, model.status());
assertNotNull(solution);
for (int vehicle = 0; vehicle < 3; ++vehicle) {
assertEquals(4, solution.max(dimension.cumulVar(model.start(vehicle))));
assertEquals(vehicle + 5, solution.max(dimension.cumulVar(model.end(vehicle))));
}
}
@Test
public void testRoutingModel_intVarVectorGetter() {
final RoutingIndexManager manager = new RoutingIndexManager(coordinates.size(), 1, 0);
final RoutingModel model = new RoutingModel(manager);
final LongBinaryOperator manhattanCostCallback = createManhattanCostCallback(manager);
final int cost = model.registerTransitCallback(manhattanCostCallback);
model.setArcCostEvaluatorOfAllVehicles(cost);
final LongBinaryOperator transit = (long firstIndex, long secondIndex) -> {
int firstNode = manager.indexToNode(firstIndex);
int secondNode = manager.indexToNode(secondIndex);
if (firstNode >= coordinates.size()) {
firstNode = 0;
}
if (secondNode >= coordinates.size()) {
secondNode = 0;
}
long distanceTime = manhattanCostCallback.applyAsLong(firstIndex, secondIndex) * 10;
long visitingTime = 1;
return distanceTime + visitingTime;
};
assertTrue(
model.addDimension(model.registerTransitCallback(transit), 1000, 1000, true, "time"));
RoutingDimension timeDimension = model.getMutableDimension("time");
IntVar[] cumuls = timeDimension.cumuls();
assertThat(cumuls).isNotEmpty();
IntVar[] transits = timeDimension.transits();
assertThat(transits).isNotEmpty();
IntVar[] slacks = timeDimension.slacks();
assertThat(slacks).isNotEmpty();
IntVar[] nexts = model.nexts();
assertThat(nexts).isNotEmpty();
IntVar[] vehicleVars = model.vehicleVars();
assertThat(vehicleVars).isNotEmpty();
}
}

View File

@@ -23,15 +23,19 @@ import java.lang.Thread;
import java.util.Random;
import java.util.function.Consumer;
import java.util.logging.Logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Tests the CP-SAT java interface. */
public class SatSolverTest {
private static final Logger logger = Logger.getLogger(SatSolverTest.class.getName());
@BeforeEach
public void setUp() {
Loader.loadNativeLibraries();
}
@Test
public void testDomainGetter() {
Loader.loadNativeLibraries();
System.out.println("testDomainGetter");
CpModel model = new CpModel();
@@ -47,7 +51,6 @@ public class SatSolverTest {
@Test
public void testCrashInPresolve() {
Loader.loadNativeLibraries();
System.out.println("testCrashInPresolve");
CpModel model = new CpModel();
@@ -83,7 +86,6 @@ public class SatSolverTest {
private IntVar[] entitiesOne;
@Test
public void testCrashInSolveWithAllowedAssignment() {
Loader.loadNativeLibraries();
System.out.println("testCrashInSolveWithAllowedAssignment");
final CpModel model = new CpModel();
final int numEntityOne = 50000;
@@ -113,7 +115,6 @@ public class SatSolverTest {
@Test
public void testCrashEquality() {
Loader.loadNativeLibraries();
System.out.println("testCrashInSolveWithAllowedAssignment");
final CpModel model = new CpModel();
@@ -164,7 +165,6 @@ public class SatSolverTest {
@Test
public void testLogCapture() {
Loader.loadNativeLibraries();
System.out.println("testLogCapture");
// Creates the model.

View File

@@ -751,9 +751,14 @@ check_java_pimpl: \
.PHONY: test_java_tests # Build and Run all Java Tests (located in examples/tests)
test_java_tests: \
rjava_KnapsackSolverTest \
rjava_FlowTest \
rjava_LinearSolverTest \
rjava_ConstraintSolverTest \
rjava_RoutingSolverTest \
rjava_LinearExprTest \
rjava_CpModelTest \
rjava_CpSolverTest \
rjava_SatSolverTest \
.PHONY: test_java_contrib # Build and Run all Java Contrib (located in examples/contrib)

View File

@@ -85,6 +85,11 @@
<version>1.1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
</dependencies>
<build>

View File

@@ -356,6 +356,7 @@ PROTO2_RETURN(
// - loadSolutionFromProto; // Use hand-written version.
// Expose some of the more advanced MPSolver API.
%rename (problemType) operations_research::MPSolver::ProblemType; // no test
%rename (supportsProblemType) operations_research::MPSolver::SupportsProblemType; // no test
%rename (setSolverSpecificParametersAsString)
operations_research::MPSolver::SetSolverSpecificParametersAsString; // no test

View File

@@ -68,12 +68,10 @@ PROTO2_RETURN(operations_research::sat::CpSolverResponse,
// processing to be passed to the std::function.
//
// TODO(user): cleanup java/functions.i and move the code there.
%{
#include <memory> // std::make_shared<GlobalRefGuard>
%}
%typemap(in) std::function<void(const std::string&)> %{
JavaVM* jvm;
jenv->GetJavaVM(&jvm);