package aima.test.core.unit.logic.fol.kb.data;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import aima.core.logic.fol.CNFConverter;
import aima.core.logic.fol.StandardizeApartIndexicalFactory;
import aima.core.logic.fol.domain.DomainFactory;
import aima.core.logic.fol.domain.FOLDomain;
import aima.core.logic.fol.kb.FOLKnowledgeBase;
import aima.core.logic.fol.kb.data.CNF;
import aima.core.logic.fol.kb.data.Clause;
import aima.core.logic.fol.kb.data.Literal;
import aima.core.logic.fol.parsing.FOLParser;
import aima.core.logic.fol.parsing.ast.AtomicSentence;
import aima.core.logic.fol.parsing.ast.Constant;
import aima.core.logic.fol.parsing.ast.Function;
import aima.core.logic.fol.parsing.ast.Predicate;
import aima.core.logic.fol.parsing.ast.Sentence;
import aima.core.logic.fol.parsing.ast.Term;
import aima.core.logic.fol.parsing.ast.Variable;
/**
* @author Ciaran O'Reilly
*
*/
public class ClauseTest {
@Before
public void setUp() {
StandardizeApartIndexicalFactory.flush();
}
@Test
public void testImmutable() {
Clause c = new Clause();
Assert.assertFalse(c.isImmutable());
c.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
c.setImmutable();
Assert.assertTrue(c.isImmutable());
try {
c.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>()));
Assert.fail("Should have thrown an IllegalStateException");
} catch (IllegalStateException ise) {
// Ok, Expected
}
try {
c.addPositiveLiteral(new Predicate("Pred3", new ArrayList<Term>()));
Assert.fail("Should have thrown an IllegalStateException");
} catch (IllegalStateException ise) {
// Ok, Expected
}
}
@Test
public void testIsEmpty() {
Clause c1 = new Clause();
Assert.assertTrue(c1.isEmpty());
c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertFalse(c1.isEmpty());
Clause c2 = new Clause();
Assert.assertTrue(c2.isEmpty());
c2.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertFalse(c2.isEmpty());
Clause c3 = new Clause();
Assert.assertTrue(c3.isEmpty());
c3.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c3.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
// Should be empty as they resolved with each other
Assert.assertFalse(c3.isEmpty());
c3.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c3.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertFalse(c3.isEmpty());
}
@Test
public void testIsHornClause() {
Clause c1 = new Clause();
Assert.assertFalse(c1.isHornClause());
c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertTrue(c1.isHornClause());
c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertTrue(c1.isHornClause());
c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>()));
Assert.assertTrue(c1.isHornClause());
c1.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>()));
Assert.assertTrue(c1.isHornClause());
c1.addPositiveLiteral(new Predicate("Pred5", new ArrayList<Term>()));
Assert.assertFalse(c1.isHornClause());
}
@Test
public void testIsDefiniteClause() {
Clause c1 = new Clause();
Assert.assertFalse(c1.isDefiniteClause());
c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertFalse(c1.isDefiniteClause());
c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertTrue(c1.isDefiniteClause());
c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>()));
Assert.assertTrue(c1.isDefiniteClause());
c1.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>()));
Assert.assertTrue(c1.isDefiniteClause());
c1.addPositiveLiteral(new Predicate("Pred5", new ArrayList<Term>()));
Assert.assertFalse(c1.isDefiniteClause());
}
@Test
public void testIsUnitClause() {
Clause c1 = new Clause();
Assert.assertFalse(c1.isUnitClause());
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertTrue(c1.isUnitClause());
c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertFalse(c1.isUnitClause());
c1 = new Clause();
Assert.assertFalse(c1.isUnitClause());
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertTrue(c1.isUnitClause());
c1.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertFalse(c1.isUnitClause());
c1 = new Clause();
Assert.assertFalse(c1.isUnitClause());
c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertTrue(c1.isUnitClause());
c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertFalse(c1.isUnitClause());
}
@Test
public void testIsImplicationDefiniteClause() {
Clause c1 = new Clause();
Assert.assertFalse(c1.isImplicationDefiniteClause());
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertFalse(c1.isImplicationDefiniteClause());
c1.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertTrue(c1.isImplicationDefiniteClause());
c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>()));
Assert.assertTrue(c1.isImplicationDefiniteClause());
c1.addPositiveLiteral(new Predicate("Pred4", new ArrayList<Term>()));
Assert.assertFalse(c1.isImplicationDefiniteClause());
}
@Test
public void testBinaryResolvents() {
FOLDomain domain = new FOLDomain();
domain.addPredicate("Pred1");
domain.addPredicate("Pred2");
domain.addPredicate("Pred3");
domain.addPredicate("Pred4");
Clause c1 = new Clause();
// Ensure that resolving to self when empty returns an empty clause
Assert.assertNotNull(c1.binaryResolvents(c1));
Assert.assertEquals(1, c1.binaryResolvents(c1).size());
Assert.assertTrue(c1.binaryResolvents(c1).iterator().next().isEmpty());
// Check if resolve with self to an empty clause
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertNotNull(c1.binaryResolvents(c1));
Assert.assertEquals(1, c1.binaryResolvents(c1).size());
// i.e. resolving a tautology with a tautology gives you
// back a tautology.
Assert.assertEquals("[~Pred1(), Pred1()]", c1.binaryResolvents(c1)
.iterator().next().toString());
// Check if try to resolve with self and no resolvents
c1 = new Clause();
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertEquals(0, c1.binaryResolvents(c1).size());
c1 = new Clause();
Clause c2 = new Clause();
// Ensure that two empty clauses resolve to an empty clause
Assert.assertNotNull(c1.binaryResolvents(c2));
Assert.assertEquals(1, c1.binaryResolvents(c2).size());
Assert.assertTrue(c1.binaryResolvents(c2).iterator().next().isEmpty());
Assert.assertNotNull(c2.binaryResolvents(c1));
Assert.assertEquals(1, c2.binaryResolvents(c1).size());
Assert.assertTrue(c2.binaryResolvents(c1).iterator().next().isEmpty());
// Enusre the two complementary clauses resolve
// to the empty clause
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c2.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
Assert.assertNotNull(c1.binaryResolvents(c2));
Assert.assertEquals(1, c1.binaryResolvents(c2).size());
Assert.assertTrue(c1.binaryResolvents(c2).iterator().next().isEmpty());
Assert.assertNotNull(c2.binaryResolvents(c1));
Assert.assertEquals(1, c2.binaryResolvents(c1).size());
Assert.assertTrue(c2.binaryResolvents(c1).iterator().next().isEmpty());
// Ensure that two clauses that have two complementaries
// resolve with two resolvents
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c2.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
c2.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertNotNull(c1.binaryResolvents(c2));
Assert.assertEquals(2, c1.binaryResolvents(c2).size());
Assert.assertNotNull(c2.binaryResolvents(c1));
Assert.assertEquals(2, c2.binaryResolvents(c1).size());
// Ensure two clauses that factor are not
// considered resolved
c1 = new Clause();
c2 = new Clause();
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>()));
c1.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>()));
c2.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
c2.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>()));
Assert.assertNotNull(c1.binaryResolvents(c2));
Assert.assertEquals(0, c1.binaryResolvents(c2).size());
Assert.assertNotNull(c2.binaryResolvents(c1));
Assert.assertEquals(0, c2.binaryResolvents(c1).size());
// Ensure the resolvent is a subset of the originals
c1 = new Clause();
c2 = new Clause();
c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>()));
c1.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>()));
c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>()));
c2.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>()));
Assert.assertNotNull(c1.binaryResolvents(c2));
Assert.assertNotNull(c2.binaryResolvents(c1));
Assert.assertEquals(1, c1.binaryResolvents(c2).iterator().next()
.getNumberPositiveLiterals());
Assert.assertEquals(1, c1.binaryResolvents(c2).iterator().next()
.getNumberNegativeLiterals());
Assert.assertEquals(1, c2.binaryResolvents(c1).iterator().next()
.getNumberPositiveLiterals());
Assert.assertEquals(1, c2.binaryResolvents(c1).iterator().next()
.getNumberNegativeLiterals());
}
@Test
public void testBinaryResolventsOrderDoesNotMatter() {
// This is a regression test, to ensure
// the ordering of resolvents does not matter.
// If the order ends up mattering, then likely
// a problem was introduced in the Clause class
// unifier, or related class.
// Set up the initial set of clauses based on the
// loves animal domain as it contains functions
// new clauses will always be created (i.e. is an
// infinite universe of discourse).
FOLKnowledgeBase kb = new FOLKnowledgeBase(
DomainFactory.lovesAnimalDomain());
kb.tell("FORALL x (FORALL y (Animal(y) => Loves(x, y)) => EXISTS y Loves(y, x))");
kb.tell("FORALL x (EXISTS y (Animal(y) AND Kills(x, y)) => FORALL z NOT(Loves(z, x)))");
kb.tell("FORALL x (Animal(x) => Loves(Jack, x))");
kb.tell("(Kills(Jack, Tuna) OR Kills(Curiosity, Tuna))");
kb.tell("Cat(Tuna)");
kb.tell("FORALL x (Cat(x) => Animal(x))");
Set<Clause> clauses = new LinkedHashSet<Clause>();
clauses.addAll(kb.getAllClauses());
Set<Clause> newClauses = new LinkedHashSet<Clause>();
long maxRunTime = 30 * 1000; // 30 seconds
long finishTime = System.currentTimeMillis() + maxRunTime;
do {
clauses.addAll(newClauses);
newClauses.clear();
Clause[] clausesA = new Clause[clauses.size()];
clauses.toArray(clausesA);
for (int i = 0; i < clausesA.length; i++) {
Clause cI = clausesA[i];
for (int j = 0; j < clausesA.length; j++) {
Clause cJ = clausesA[j];
newClauses.addAll(cI.getFactors());
newClauses.addAll(cJ.getFactors());
Set<Clause> cIresolvents = cI.binaryResolvents(cJ);
Set<Clause> cJresolvents = cJ.binaryResolvents(cI);
if (!cIresolvents.equals(cJresolvents)) {
System.err.println("cI=" + cI);
System.err.println("cJ=" + cJ);
System.err.println("cIR=" + cIresolvents);
System.err.println("cJR=" + cJresolvents);
Assert.fail("Ordering of binary resolvents has become important, which should not be the case");
}
for (Clause r : cIresolvents) {
newClauses.addAll(r.getFactors());
}
if (System.currentTimeMillis() > finishTime) {
break;
}
}
if (System.currentTimeMillis() > finishTime) {
break;
}
}
} while (System.currentTimeMillis() < finishTime);
}
@Test
public void testEqualityBinaryResolvents() {
FOLDomain domain = new FOLDomain();
domain.addConstant("A");
domain.addConstant("B");
FOLParser parser = new FOLParser(domain);
// B = A
Clause c1 = new Clause();
c1.addPositiveLiteral((AtomicSentence) parser.parse("B = A"));
Clause c2 = new Clause();
c2.addNegativeLiteral((AtomicSentence) parser.parse("B = A"));
c2.addPositiveLiteral((AtomicSentence) parser.parse("B = A"));
Set<Clause> resolvents = c1.binaryResolvents(c2);
Assert.assertEquals(1, resolvents.size());
Assert.assertEquals("[[B = A]]", resolvents.toString());
}
@Test
public void testHashCode() {
Term cons1 = new Constant("C1");
Term cons2 = new Constant("C2");
Term var1 = new Variable("v1");
List<Term> pts1 = new ArrayList<Term>();
List<Term> pts2 = new ArrayList<Term>();
pts1.add(cons1);
pts1.add(cons2);
pts1.add(var1);
pts2.add(cons2);
pts2.add(cons1);
pts2.add(var1);
Clause c1 = new Clause();
Clause c2 = new Clause();
Assert.assertEquals(c1.hashCode(), c2.hashCode());
c1.addNegativeLiteral(new Predicate("Pred1", pts1));
Assert.assertNotSame(c1.hashCode(), c2.hashCode());
c2.addNegativeLiteral(new Predicate("Pred1", pts1));
Assert.assertEquals(c1.hashCode(), c2.hashCode());
c1.addPositiveLiteral(new Predicate("Pred1", pts1));
Assert.assertNotSame(c1.hashCode(), c2.hashCode());
c2.addPositiveLiteral(new Predicate("Pred1", pts1));
Assert.assertEquals(c1.hashCode(), c2.hashCode());
}
@Test
public void testSimpleEquals() {
Term cons1 = new Constant("C1");
Term cons2 = new Constant("C2");
Term var1 = new Variable("v1");
List<Term> pts1 = new ArrayList<Term>();
List<Term> pts2 = new ArrayList<Term>();
pts1.add(cons1);
pts1.add(cons2);
pts1.add(var1);
pts2.add(cons2);
pts2.add(cons1);
pts2.add(var1);
Clause c1 = new Clause();
Clause c2 = new Clause();
Assert.assertTrue(c1.equals(c1));
Assert.assertTrue(c2.equals(c2));
Assert.assertTrue(c1.equals(c2));
Assert.assertTrue(c2.equals(c1));
// Check negatives
c1.addNegativeLiteral(new Predicate("Pred1", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addNegativeLiteral(new Predicate("Pred1", pts1));
Assert.assertTrue(c1.equals(c2));
Assert.assertTrue(c2.equals(c1));
c1.addNegativeLiteral(new Predicate("Pred2", pts2));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addNegativeLiteral(new Predicate("Pred2", pts2));
Assert.assertTrue(c1.equals(c2));
Assert.assertTrue(c2.equals(c1));
// Check same but added in different order
c1.addNegativeLiteral(new Predicate("Pred3", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c1.addNegativeLiteral(new Predicate("Pred4", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addNegativeLiteral(new Predicate("Pred4", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addNegativeLiteral(new Predicate("Pred3", pts1));
Assert.assertTrue(c1.equals(c2));
Assert.assertTrue(c2.equals(c1));
// Check positives
c1.addPositiveLiteral(new Predicate("Pred1", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addPositiveLiteral(new Predicate("Pred1", pts1));
Assert.assertTrue(c1.equals(c2));
Assert.assertTrue(c2.equals(c1));
c1.addPositiveLiteral(new Predicate("Pred2", pts2));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addPositiveLiteral(new Predicate("Pred2", pts2));
Assert.assertTrue(c1.equals(c2));
Assert.assertTrue(c2.equals(c1));
// Check same but added in different order
c1.addPositiveLiteral(new Predicate("Pred3", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c1.addPositiveLiteral(new Predicate("Pred4", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addPositiveLiteral(new Predicate("Pred4", pts1));
Assert.assertFalse(c1.equals(c2));
Assert.assertFalse(c2.equals(c1));
c2.addPositiveLiteral(new Predicate("Pred3", pts1));
Assert.assertTrue(c1.equals(c2));
Assert.assertTrue(c2.equals(c1));
}
@Test
public void testComplexEquals() {
FOLDomain domain = new FOLDomain();
domain.addConstant("A");
domain.addConstant("B");
domain.addConstant("C");
domain.addConstant("D");
domain.addPredicate("P");
domain.addPredicate("Animal");
domain.addPredicate("Kills");
domain.addFunction("F");
domain.addFunction("SF0");
FOLParser parser = new FOLParser(domain);
CNFConverter cnfConverter = new CNFConverter(parser);
Sentence s1 = parser.parse("((x1 = y1 AND y1 = z1) => x1 = z1)");
Sentence s2 = parser.parse("((x2 = y2 AND F(y2) = z2) => F(x2) = z2)");
CNF cnf1 = cnfConverter.convertToCNF(s1);
CNF cnf2 = cnfConverter.convertToCNF(s2);
Clause c1 = cnf1.getConjunctionOfClauses().get(0);
Clause c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertFalse(c1.equals(c2));
s1 = parser.parse("((x1 = y1 AND y1 = z1) => x1 = z1)");
s2 = parser.parse("((x2 = y2 AND y2 = z2) => x2 = z2)");
cnf1 = cnfConverter.convertToCNF(s1);
cnf2 = cnfConverter.convertToCNF(s2);
c1 = cnf1.getConjunctionOfClauses().get(0);
c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertTrue(c1.equals(c2));
s1 = parser.parse("((x1 = y1 AND y1 = z1) => x1 = z1)");
s2 = parser.parse("((y2 = z2 AND x2 = y2) => x2 = z2)");
cnf1 = cnfConverter.convertToCNF(s1);
cnf2 = cnfConverter.convertToCNF(s2);
c1 = cnf1.getConjunctionOfClauses().get(0);
c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertTrue(c1.equals(c2));
s1 = parser.parse("(((x1 = y1 AND y1 = z1) AND z1 = r1) => x1 = r1)");
s2 = parser.parse("(((x2 = y2 AND y2 = z2) AND z2 = r2) => x2 = r2)");
cnf1 = cnfConverter.convertToCNF(s1);
cnf2 = cnfConverter.convertToCNF(s2);
c1 = cnf1.getConjunctionOfClauses().get(0);
c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertTrue(c1.equals(c2));
s1 = parser.parse("(((x1 = y1 AND y1 = z1) AND z1 = r1) => x1 = r1)");
s2 = parser.parse("(((z2 = r2 AND y2 = z2) AND x2 = y2) => x2 = r2)");
cnf1 = cnfConverter.convertToCNF(s1);
cnf2 = cnfConverter.convertToCNF(s2);
c1 = cnf1.getConjunctionOfClauses().get(0);
c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertTrue(c1.equals(c2));
s1 = parser.parse("(((x1 = y1 AND y1 = z1) AND z1 = r1) => x1 = r1)");
s2 = parser.parse("(((x2 = y2 AND y2 = z2) AND z2 = y2) => x2 = r2)");
cnf1 = cnfConverter.convertToCNF(s1);
cnf2 = cnfConverter.convertToCNF(s2);
c1 = cnf1.getConjunctionOfClauses().get(0);
c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertFalse(c1.equals(c2));
s1 = parser
.parse("(((((x1 = y1 AND y1 = z1) AND z1 = r1) AND r1 = q1) AND q1 = s1) => x1 = r1)");
s2 = parser
.parse("(((((x2 = y2 AND y2 = z2) AND z2 = r2) AND r2 = q2) AND q2 = s2) => x2 = r2)");
cnf1 = cnfConverter.convertToCNF(s1);
cnf2 = cnfConverter.convertToCNF(s2);
c1 = cnf1.getConjunctionOfClauses().get(0);
c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertTrue(c1.equals(c2));
s1 = parser
.parse("((((NOT(Animal(c1920)) OR NOT(Animal(c1921))) OR NOT(Kills(c1922,c1920))) OR NOT(Kills(c1919,c1921))) OR NOT(Kills(SF0(c1922),SF0(c1919))))");
s2 = parser
.parse("((((NOT(Animal(c1929)) OR NOT(Animal(c1928))) OR NOT(Kills(c1927,c1929))) OR NOT(Kills(c1930,c1928))) OR NOT(Kills(SF0(c1930),SF0(c1927))))");
cnf1 = cnfConverter.convertToCNF(s1);
cnf2 = cnfConverter.convertToCNF(s2);
c1 = cnf1.getConjunctionOfClauses().get(0);
c2 = cnf2.getConjunctionOfClauses().get(0);
Assert.assertTrue(c1.equals(c2));
}
@Test
public void testNonTrivialFactors() {
FOLDomain domain = new FOLDomain();
domain.addConstant("A");
domain.addConstant("B");
domain.addFunction("F");
domain.addFunction("G");
domain.addFunction("H");
domain.addPredicate("P");
domain.addPredicate("Q");
FOLParser parser = new FOLParser(domain);
// p(x,y), q(a,b), p(b,a), q(y,x)
Clause c = new Clause();
c.addPositiveLiteral((Predicate) parser.parse("P(x,y)"));
c.addPositiveLiteral((Predicate) parser.parse("Q(A,B)"));
c.addNegativeLiteral((Predicate) parser.parse("P(B,A)"));
c.addPositiveLiteral((Predicate) parser.parse("Q(y,x)"));
Assert.assertEquals("[[~P(B,A), P(B,A), Q(A,B)]]", c
.getNonTrivialFactors().toString());
// p(x,y), q(a,b), p(b,a), q(y,x)
c = new Clause();
c.addPositiveLiteral((Predicate) parser.parse("P(x,y)"));
c.addPositiveLiteral((Predicate) parser.parse("Q(A,B)"));
c.addNegativeLiteral((Predicate) parser.parse("P(B,A)"));
c.addNegativeLiteral((Predicate) parser.parse("Q(y,x)"));
Assert.assertEquals("[]", c.getNonTrivialFactors().toString());
// p(x,f(y)), p(g(u),x), p(f(y),u)
c = new Clause();
c.addPositiveLiteral((Predicate) parser.parse("P(x,F(y))"));
c.addPositiveLiteral((Predicate) parser.parse("P(G(u),x)"));
c.addPositiveLiteral((Predicate) parser.parse("P(F(y),u)"));
// Should be: [{P(F(c#),F(c#)),P(G(F(c#)),F(c#))}]
c = c.getNonTrivialFactors().iterator().next();
Literal p = c.getPositiveLiterals().get(0);
Assert.assertEquals("P", p.getAtomicSentence().getSymbolicName());
Function f = (Function) p.getAtomicSentence().getArgs().get(0);
Assert.assertEquals("F", f.getFunctionName());
Variable v = (Variable) f.getTerms().get(0);
f = (Function) p.getAtomicSentence().getArgs().get(1);
Assert.assertEquals("F", f.getFunctionName());
Assert.assertEquals(v, f.getTerms().get(0));
//
p = c.getPositiveLiterals().get(1);
f = (Function) p.getAtomicSentence().getArgs().get(0);
Assert.assertEquals("G", f.getFunctionName());
f = (Function) f.getTerms().get(0);
Assert.assertEquals("F", f.getFunctionName());
Assert.assertEquals(v, f.getTerms().get(0));
f = (Function) p.getAtomicSentence().getArgs().get(1);
Assert.assertEquals("F", f.getFunctionName());
Assert.assertEquals(v, f.getTerms().get(0));
// p(g(x)), q(x), p(f(a)), p(x), p(g(f(x))), q(f(a))
c = new Clause();
c.addPositiveLiteral((Predicate) parser.parse("P(G(x))"));
c.addPositiveLiteral((Predicate) parser.parse("Q(x)"));
c.addPositiveLiteral((Predicate) parser.parse("P(F(A))"));
c.addPositiveLiteral((Predicate) parser.parse("P(x)"));
c.addPositiveLiteral((Predicate) parser.parse("P(G(F(x)))"));
c.addPositiveLiteral((Predicate) parser.parse("Q(F(A))"));
Assert.assertEquals("[[P(F(A)), P(G(F(F(A)))), P(G(F(A))), Q(F(A))]]",
c.getNonTrivialFactors().toString());
}
// Note: Tests derived from:
// http://logic.stanford.edu/classes/cs157/2008/notes/chap09.pdf
// page 16.
@Test
public void testIsTautology() {
FOLDomain domain = new FOLDomain();
domain.addConstant("A");
domain.addPredicate("P");
domain.addPredicate("Q");
domain.addPredicate("R");
domain.addFunction("F");
FOLParser parser = new FOLParser(domain);
// {p(f(a)),~p(f(a))}
Clause c = new Clause();
c.addPositiveLiteral((Predicate) parser.parse("P(F(A))"));
Assert.assertFalse(c.isTautology());
c.addNegativeLiteral((Predicate) parser.parse("P(F(A))"));
Assert.assertTrue(c.isTautology());
// {p(x),q(y),~q(y),r(z)}
c = new Clause();
c.addPositiveLiteral((Predicate) parser.parse("P(x)"));
Assert.assertFalse(c.isTautology());
c.addPositiveLiteral((Predicate) parser.parse("Q(y)"));
Assert.assertFalse(c.isTautology());
c.addNegativeLiteral((Predicate) parser.parse("Q(y)"));
Assert.assertTrue(c.isTautology());
c.addPositiveLiteral((Predicate) parser.parse("R(z)"));
Assert.assertTrue(c.isTautology());
// {~p(a),p(x)}
c = new Clause();
c.addNegativeLiteral((Predicate) parser.parse("P(A)"));
Assert.assertFalse(c.isTautology());
c.addPositiveLiteral((Predicate) parser.parse("P(x)"));
Assert.assertFalse(c.isTautology());
}
// Note: Tests derived from:
// http://logic.stanford.edu/classes/cs157/2008/lectures/lecture12.pdf
// slides 17 and 18.
@Test
public void testSubsumes() {
FOLDomain domain = new FOLDomain();
domain.addConstant("A");
domain.addConstant("B");
domain.addConstant("C");
domain.addConstant("D");
domain.addConstant("E");
domain.addConstant("F");
domain.addConstant("G");
domain.addConstant("H");
domain.addConstant("I");
domain.addConstant("J");
domain.addPredicate("P");
domain.addPredicate("Q");
FOLParser parser = new FOLParser(domain);
// Example
// {~p(a,b),q(c)}
Clause psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(x,y)}
Clause phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(x,y)"));
Assert.assertTrue(phi.subsumes(psi));
// Non-Example
// {~p(x,b),q(x)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(x,B)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(x)"));
// {~p(a,y)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(A,y)"));
// Reason for Non-Example:
// {p(b,b)}
// {~q(b)}
Assert.assertFalse(phi.subsumes(psi));
//
// Additional Examples
// Non-Example
// {~p(x,b),q(z)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(x,B)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(z)"));
// {~p(a,y)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(A,y)"));
Assert.assertFalse(phi.subsumes(psi));
// Example
// {~p(a,b),~p(w,z),q(c)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(w,z)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(x,y),~p(a,b)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(x,y)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
Assert.assertTrue(phi.subsumes(psi));
// Non-Example
// {~p(v,b),~p(w,z),q(c)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(v,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(w,z)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(x,y),~p(a,b)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(x,y)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
Assert.assertFalse(phi.subsumes(psi));
// Example
// {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(c)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(i,j)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
Assert.assertTrue(phi.subsumes(psi));
// Example
// {~p(a,b),~p(c,d),~p(e,f),q(c)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(e,f),~p(a,b),~p(c,d)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
Assert.assertTrue(phi.subsumes(psi));
// Example
// {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(c)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(i,j),~p(c,d)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
Assert.assertTrue(phi.subsumes(psi));
// Non-Example
// {~p(a,b),~p(x,d),~p(e,f),~p(g,h),~p(i,j),q(c)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(x,D)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(i,j),~p(c,d)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
Assert.assertFalse(phi.subsumes(psi));
// Example
// {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(c)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C)"));
// {~p(i,j),~p(a,x)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(A,x)"));
Assert.assertTrue(phi.subsumes(psi));
// Example
// {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(a,b),q(c,d),q(e,f)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C,D)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(E,F)"));
// {~p(i,j),~p(a,b),q(e,f),q(a,b)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
phi.addPositiveLiteral((Predicate) parser.parse("Q(E,F)"));
phi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)"));
Assert.assertTrue(phi.subsumes(psi));
// Non-Example
// {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(a,b),q(c,d),q(e,f)}
psi = new Clause();
psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)"));
psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(C,D)"));
psi.addPositiveLiteral((Predicate) parser.parse("Q(E,F)"));
// {~p(i,j),~p(a,b),q(e,f),q(a,b)}
phi = new Clause();
phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)"));
phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)"));
phi.addPositiveLiteral((Predicate) parser.parse("Q(E,A)"));
phi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)"));
Assert.assertFalse(phi.subsumes(psi));
}
}