java: sync tests with Google
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
231
examples/tests/CpModelTest.java
Normal file
231
examples/tests/CpModelTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
260
examples/tests/CpSolverTest.java
Normal file
260
examples/tests/CpSolverTest.java
Normal 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");
|
||||
}
|
||||
}
|
||||
83
examples/tests/FlowTest.java
Normal file
83
examples/tests/FlowTest.java
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
examples/tests/KnapsackSolverTest.java
Normal file
54
examples/tests/KnapsackSolverTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
167
examples/tests/LinearExprTest.java
Normal file
167
examples/tests/LinearExprTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user