/**
*
*/
package kodkod.test.unit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import kodkod.ast.Formula;
import kodkod.engine.Solution.Outcome;
import kodkod.engine.Solver;
import kodkod.engine.satlab.ResolutionTrace;
import kodkod.engine.satlab.SATFactory;
import kodkod.engine.satlab.SATProver;
import kodkod.engine.satlab.SATSolver;
import kodkod.instance.Bounds;
import kodkod.util.ints.Ints;
import org.junit.Test;
import kodkod.test.util.Solvers;
import kodkod.examples.alloy.CeilingsAndFloors;
/**
* A test that loads multiple native solvers into memory.
*
* @author Emian Torlak
*/
public class NativeSolverTest {
private static final List<SATFactory> solvers = Solvers.allAvailableSolvers();
private final Formula formula;
private final Bounds bounds;
public NativeSolverTest() {
final CeilingsAndFloors prob = new CeilingsAndFloors();
this.formula = prob.checkBelowTooDoublePrime();
this.bounds = prob.bounds(6, 6);
}
@Test
public void testEmptyCNF() {
for(SATFactory factory : solvers) {
assertTrue(factory.instance().solve());
}
}
@Test
public void testEmptyClauseCNF() {
for(SATFactory factory : solvers) {
final SATSolver solver = factory.instance();
solver.addClause(new int[0]);
assertFalse(solver.solve());
}
}
@Test
public void testProofOfEmptyClauseCNF() {
for(SATFactory factory : solvers) {
if (!factory.prover()) continue;
final SATProver solver = (SATProver) factory.instance();
solver.addClause(new int[0]);
assertFalse(solver.solve());
final ResolutionTrace proof = solver.proof();
assertEquals(1, proof.size());
assertEquals(Ints.singleton(0), proof.core());
assertEquals(Ints.EMPTY_SET, proof.resolvents());
assertEquals(0, proof.get(0).size());
}
}
@Test
public void testProofOfNthEmptyClauseCNF() {
for(SATFactory factory : solvers) {
if (!factory.prover()) continue;
final SATProver solver = (SATProver) factory.instance();
solver.addVariables(1);
solver.addClause(new int[]{1});
solver.addVariables(1);
solver.addClause(new int[]{-2});
solver.addVariables(2);
solver.addClause(new int[]{2, 3, 4});
solver.addClause(new int[0]);
solver.addClause(new int[]{4});
solver.addClause(new int[]{3});
assertFalse(solver.solve());
final ResolutionTrace proof = solver.proof();
assertEquals(4, proof.size());
assertEquals(Ints.singleton(3), proof.core());
assertEquals(Ints.EMPTY_SET, proof.resolvents());
assertEquals(0, proof.get(3).size());
}
}
@Test
public void testProofOfLastEmptyClauseCNF() {
for(SATFactory factory : solvers) {
if (!factory.prover()) continue;
final SATProver solver = (SATProver) factory.instance();
solver.addVariables(1);
solver.addClause(new int[]{1});
solver.addVariables(1);
solver.addClause(new int[]{-2});
solver.addVariables(2);
solver.addClause(new int[]{2, 3, 4});
solver.addClause(new int[0]);
assertFalse(solver.solve());
final ResolutionTrace proof = solver.proof();
assertEquals(4, proof.size());
assertEquals(Ints.singleton(3), proof.core());
assertEquals(Ints.EMPTY_SET, proof.resolvents());
assertEquals(0, proof.get(3).size());
}
}
@Test(expected=IllegalArgumentException.class)
public void testPlingelingBadThreadInput() {
final SATFactory pl = SATFactory.plingeling(0, true);
solveWith(pl);
}
@Test
public void testPlingelingOneThread() {
final SATFactory pl = SATFactory.plingeling(1,null);
assertEquals(Outcome.UNSATISFIABLE, solveWith(pl));
}
@Test
public void testPlingelingPortfolio() {
final SATFactory pl = SATFactory.plingeling(null,true);
assertEquals(Outcome.UNSATISFIABLE, solveWith(pl));
}
@Test
public void testPlingelingThreeThreadsPortfolio() {
final SATFactory pl = SATFactory.plingeling(3,true);
assertEquals(Outcome.UNSATISFIABLE, solveWith(pl));
}
// @Test
// public void testLingelingIncremental() {
// final SATSolver solver = SATFactory.Lingeling.instance();
// solver.addVariables(1);
// solver.addClause(new int[]{1});
// assertTrue(solver.solve());
// solver.addVariables(1);
// solver.addClause(new int[]{-2});
// assertTrue(solver.solve());
// solver.addVariables(8);
// solver.addClause(new int[]{2, 9, 10});
// assertTrue(solver.solve());
// solver.addClause(new int[0]);
// solver.addClause(new int[]{7, 8, 10});
// assertFalse(solver.solve());
// solver.addClause(new int[]{-3, 5});
// assertFalse(solver.solve());
// }
//
// @Test
// public void testLingelingRetrieveModel() {
// final SATSolver solver = SATFactory.Lingeling.instance();
// solver.addVariables(1);
// solver.addClause(new int[]{1});
// assertTrue(solver.solve());
// solver.addVariables(1);
// solver.addClause(new int[]{-2});
// assertTrue(solver.solve());
// solver.addVariables(18);
// solver.addClause(new int[]{2, 9, 10});
// assertTrue(solver.solve());
// try {
// for(int i = 1; i <= 20; i++)
// solver.valueOf(i);
// } catch (IllegalArgumentException ia) {
// fail(ia.getMessage());
// }
// try {
// solver.valueOf(21);
// fail("Expected an IllegalArgumentsException for non-existant variable 21.");
// } catch (IllegalArgumentException ia) {
// // do nothing
// }
// }
@Test
public void testMultipleSolvers() {
final List<Callable<Outcome>> calls = new ArrayList<Callable<Outcome>>();
for(SATFactory factory : solvers) {
calls.add(callSolver(factory));
}
final ExecutorService exec = Executors.newFixedThreadPool(calls.size());
try {
final List<Future<Outcome>> out = exec.invokeAll(calls);
assertEquals(calls.size(), out.size());
for(Future<Outcome> result : out) {
assertEquals(Outcome.UNSATISFIABLE, result.get());
}
} catch (InterruptedException e) {
fail("Unexpected interruption");
} catch (ExecutionException e) {
fail("Unexpected execution exception");
}
}
private Callable<Outcome> callSolver(final SATFactory factory) {
return new Callable<Outcome>() {
public Outcome call() throws Exception {
return solveWith(factory);
}
};
}
private Outcome solveWith(SATFactory factory) {
final Solver solver = new Solver();
solver.options().setSolver(factory);
return solver.solve(formula, bounds).outcome();
}
}