/aima-core/src/test/java/aima/test/core/unit/logic/fol/UnifierTest.java
Java | 606 lines | 407 code | 162 blank | 37 comment | 0 complexity | 8b6cae8a572138184b4f475b57d2bb14 MD5 | raw file
Possible License(s): GPL-3.0, Apache-2.0
- package aima.test.core.unit.logic.fol;
-
- import java.util.ArrayList;
- import java.util.Hashtable;
- import java.util.List;
- import java.util.Map;
-
- import org.junit.Assert;
- import org.junit.Before;
- import org.junit.Test;
-
- import aima.core.logic.fol.Unifier;
- import aima.core.logic.fol.domain.DomainFactory;
- import aima.core.logic.fol.domain.FOLDomain;
- import aima.core.logic.fol.parsing.FOLParser;
- 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.TermEquality;
- import aima.core.logic.fol.parsing.ast.Variable;
-
- /**
- * @author Ravi Mohan
- * @author Ciaran O'Reilly
- */
- public class UnifierTest {
-
- private FOLParser parser;
- private Unifier unifier;
- private Map<Variable, Term> theta;
-
- @Before
- public void setUp() {
- parser = new FOLParser(DomainFactory.knowsDomain());
- unifier = new Unifier();
- theta = new Hashtable<Variable, Term>();
- }
-
- @Test
- public void testFailureIfThetaisNull() {
- Variable var = new Variable("x");
- Sentence sentence = parser.parse("Knows(x)");
- theta = null;
- Map<Variable, Term> result = unifier.unify(var, sentence, theta);
- Assert.assertNull(result);
- }
-
- @Test
- public void testUnificationFailure() {
- Variable var = new Variable("x");
- Sentence sentence = parser.parse("Knows(y)");
- theta = null;
- Map<Variable, Term> result = unifier.unify(var, sentence, theta);
- Assert.assertNull(result);
- }
-
- @Test
- public void testThetaPassedBackIfXEqualsYBothVariables() {
- Variable var1 = new Variable("x");
- Variable var2 = new Variable("x");
-
- theta.put(new Variable("dummy"), new Variable("dummy"));
- Map<Variable, Term> result = unifier.unify(var1, var2, theta);
- Assert.assertEquals(theta, result);
- Assert.assertEquals(1, theta.keySet().size());
- Assert.assertTrue(theta.containsKey(new Variable("dummy")));
- }
-
- @Test
- public void testVariableEqualsConstant() {
- Variable var1 = new Variable("x");
- Constant constant = new Constant("John");
-
- Map<Variable, Term> result = unifier.unify(var1, constant, theta);
- Assert.assertEquals(theta, result);
- Assert.assertEquals(1, theta.keySet().size());
- Assert.assertTrue(theta.keySet().contains(var1));
- Assert.assertEquals(constant, theta.get(var1));
- }
-
- @Test
- public void testSimpleVariableUnification() {
- Variable var1 = new Variable("x");
- List<Term> terms1 = new ArrayList<Term>();
- terms1.add(var1);
- Predicate p1 = new Predicate("King", terms1); // King(x)
-
- List<Term> terms2 = new ArrayList<Term>();
- terms2.add(new Constant("John"));
- Predicate p2 = new Predicate("King", terms2); // King(John)
-
- Map<Variable, Term> result = unifier.unify(p1, p2, theta);
- Assert.assertEquals(theta, result);
- Assert.assertEquals(1, theta.keySet().size());
- Assert.assertTrue(theta.keySet().contains(new Variable("x"))); // x =
- Assert.assertEquals(new Constant("John"), theta.get(var1)); // John
- }
-
- @Test
- public void testKnows1() {
- Sentence query = parser.parse("Knows(John,x)");
- Sentence johnKnowsJane = parser.parse("Knows(John,Jane)");
- Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
- Assert.assertEquals(theta, result);
- Assert.assertTrue(theta.keySet().contains(new Variable("x"))); // x =
- Assert.assertEquals(new Constant("Jane"), theta.get(new Variable("x"))); // Jane
- }
-
- @Test
- public void testKnows2() {
- Sentence query = parser.parse("Knows(John,x)");
- Sentence johnKnowsJane = parser.parse("Knows(y,Bill)");
- Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
-
- Assert.assertEquals(2, result.size());
-
- Assert.assertEquals(new Constant("Bill"), theta.get(new Variable("x"))); // x
- // =
- // Bill
- Assert.assertEquals(new Constant("John"), theta.get(new Variable("y"))); // y
- // =
- // John
- }
-
- @Test
- public void testKnows3() {
- Sentence query = parser.parse("Knows(John,x)");
- Sentence johnKnowsJane = parser.parse("Knows(y,Mother(y))");
- Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
-
- Assert.assertEquals(2, result.size());
-
- List<Term> terms = new ArrayList<Term>();
- terms.add(new Constant("John"));
- Function mother = new Function("Mother", terms);
- Assert.assertEquals(mother, theta.get(new Variable("x")));
- Assert.assertEquals(new Constant("John"), theta.get(new Variable("y")));
- }
-
- @Test
- public void testKnows5() {
- Sentence query = parser.parse("Knows(John,x)");
- Sentence johnKnowsJane = parser.parse("Knows(y,z)");
- Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
-
- Assert.assertEquals(2, result.size());
-
- Assert.assertEquals(new Variable("z"), theta.get(new Variable("x"))); // x
- // =
- // z
- Assert.assertEquals(new Constant("John"), theta.get(new Variable("y"))); // y
- // =
- // John
- }
-
- @Test
- public void testCascadedOccursCheck() {
- FOLDomain domain = new FOLDomain();
- domain.addPredicate("P");
- domain.addFunction("F");
- domain.addFunction("SF0");
- domain.addFunction("SF1");
- FOLParser parser = new FOLParser(domain);
-
- Sentence s1 = parser.parse("P(SF1(v2),v2)");
- Sentence s2 = parser.parse("P(v3,SF0(v3))");
- Map<Variable, Term> result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("P(v1,SF0(v1),SF0(v1),SF0(v1),SF0(v1))");
- s2 = parser.parse("P(v2,SF0(v2),v2, v3, v2)");
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser
- .parse("P(v1, F(v2),F(v2),F(v2),v1, F(F(v1)),F(F(F(v1))),v2)");
- s2 = parser
- .parse("P(F(v3),v4, v5, v6, F(F(v5)),v4, F(v3), F(F(v5)))");
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
- }
-
- /**
- * From: TPTP:LCL418-1 Am performing an incorrect unification for:
- * [is_a_theorem
- * (equivalent(equivalent(c1744,c1743),equivalent(c1742,c1743))),
- * is_a_theorem(equivalent(equivalent(c1752,c1751),c1752))]
- *
- * which is giving the following substitution:
- *
- * subst={c1744=equivalent(c1742,c1743), c1743=c1751,
- * c1752=equivalent(c1742,c1751)}
- *
- * which is incorrect as c1743 in the first function term needs to be c1751
- * as this is the second substitution.
- */
- @Test
- public void testBadCascadeSubstitution_LCL418_1() {
- FOLDomain domain = new FOLDomain();
- domain.addPredicate("ISATHEOREM");
- domain.addFunction("EQUIVALENT");
- FOLParser parser = new FOLParser(domain);
-
- Sentence s1 = parser
- .parse("ISATHEOREM(EQUIVALENT(EQUIVALENT(c1744,c1743),EQUIVALENT(c1742,c1743)))");
- Sentence s2 = parser
- .parse("ISATHEOREM(EQUIVALENT(EQUIVALENT(c1752,c1751),c1752))");
- Map<Variable, Term> result = unifier.unify(s1, s2);
-
- Assert.assertEquals(
- "{c1744=EQUIVALENT(c1742,c1751), c1743=c1751, c1752=EQUIVALENT(c1742,c1751)}",
- result.toString());
- }
-
- @Test
- public void testAdditionalVariableMixtures() {
- FOLDomain domain = new FOLDomain();
- domain.addConstant("A");
- domain.addConstant("B");
- domain.addFunction("F");
- domain.addFunction("G");
- domain.addFunction("H");
- domain.addPredicate("P");
-
- FOLParser parser = new FOLParser(domain);
-
- // Test Cascade Substitutions handled correctly
- Sentence s1 = parser.parse("P(z, x)");
- Sentence s2 = parser.parse("P(x, a)");
- Map<Variable, Term> result = unifier.unify(s1, s2);
-
- Assert.assertEquals("{z=a, x=a}", result.toString());
-
- s1 = parser.parse("P(x, z)");
- s2 = parser.parse("P(a, x)");
- result = unifier.unify(s1, s2);
-
- Assert.assertEquals("{x=a, z=a}", result.toString());
-
- s1 = parser.parse("P(w, w, w)");
- s2 = parser.parse("P(x, y, z)");
- result = unifier.unify(s1, s2);
-
- Assert.assertEquals("{w=z, x=z, y=z}", result.toString());
-
- s1 = parser.parse("P(x, y, z)");
- s2 = parser.parse("P(w, w, w)");
- result = unifier.unify(s1, s2);
-
- Assert.assertEquals("{x=w, y=w, z=w}", result.toString());
-
- s1 = parser.parse("P(x, B, F(y))");
- s2 = parser.parse("P(A, y, F(z))");
- result = unifier.unify(s1, s2);
-
- Assert.assertEquals("{x=A, y=B, z=B}", result.toString());
-
- s1 = parser.parse("P(F(x,B), G(y), F(z,A))");
- s2 = parser.parse("P(y, G(F(G(w),w)), F(w,z))");
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("P(F(G(A)), x, F(H(z,z)), H(y, G(w)))");
- s2 = parser.parse("P(y, G(z), F(v ), H(F(w), x ))");
- result = unifier.unify(s1, s2);
-
- Assert.assertEquals(
- "{y=F(G(A)), x=G(G(A)), v=H(G(A),G(A)), w=G(A), z=G(A)}",
- result.toString());
- }
-
- @Test
- public void testTermEquality() {
- FOLDomain domain = new FOLDomain();
- domain.addConstant("A");
- domain.addConstant("B");
- domain.addFunction("Plus");
-
- FOLParser parser = new FOLParser(domain);
-
- TermEquality te1 = (TermEquality) parser.parse("x = x");
- TermEquality te2 = (TermEquality) parser.parse("x = x");
-
- // Both term equalities the same,
- // should unify but no substitutions.
- Map<Variable, Term> result = unifier.unify(te1, te2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- // Different variable names but should unify.
- te1 = (TermEquality) parser.parse("x1 = x1");
- te2 = (TermEquality) parser.parse("x2 = x2");
-
- result = unifier.unify(te1, te2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals("{x1=x2}", result.toString());
-
- // Test simple unification with reflexivity axiom
- te1 = (TermEquality) parser.parse("x1 = x1");
- te2 = (TermEquality) parser.parse("Plus(A,B) = Plus(A,B)");
-
- result = unifier.unify(te1, te2);
-
- Assert.assertNotNull(result);
-
- Assert.assertEquals(1, result.size());
- Assert.assertEquals("{x1=Plus(A,B)}", result.toString());
-
- // Test more complex unification with reflexivity axiom
- te1 = (TermEquality) parser.parse("x1 = x1");
- te2 = (TermEquality) parser.parse("Plus(A,B) = Plus(A,z1)");
-
- result = unifier.unify(te1, te2);
-
- Assert.assertNotNull(result);
-
- Assert.assertEquals(2, result.size());
- Assert.assertEquals("{x1=Plus(A,B), z1=B}", result.toString());
-
- // Test reverse of previous unification with reflexivity axiom
- // Should still be the same.
- te1 = (TermEquality) parser.parse("x1 = x1");
- te2 = (TermEquality) parser.parse("Plus(A,z1) = Plus(A,B)");
-
- result = unifier.unify(te1, te2);
-
- Assert.assertNotNull(result);
-
- Assert.assertEquals(2, result.size());
- Assert.assertEquals("{x1=Plus(A,B), z1=B}", result.toString());
-
- // Test with nested terms
- te1 = (TermEquality) parser
- .parse("Plus(Plus(Plus(A,B),B, A)) = Plus(Plus(Plus(A,B),B, A))");
- te2 = (TermEquality) parser
- .parse("Plus(Plus(Plus(A,B),B, A)) = Plus(Plus(Plus(A,B),B, A))");
-
- result = unifier.unify(te1, te2);
-
- Assert.assertNotNull(result);
-
- Assert.assertEquals(0, result.size());
-
- // Simple term equality unification fails
- te1 = (TermEquality) parser.parse("Plus(A,B) = Plus(B,A)");
- te2 = (TermEquality) parser.parse("Plus(A,B) = Plus(A,B)");
-
- result = unifier.unify(te1, te2);
-
- Assert.assertNull(result);
- }
-
- @Test
- public void testNOTSentence() {
- FOLDomain domain = new FOLDomain();
- domain.addConstant("A");
- domain.addConstant("B");
- domain.addConstant("C");
- domain.addFunction("Plus");
- domain.addPredicate("P");
-
- FOLParser parser = new FOLParser(domain);
-
- Sentence s1 = parser.parse("NOT(P(A))");
- Sentence s2 = parser.parse("NOT(P(A))");
-
- Map<Variable, Term> result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("NOT(P(A))");
- s2 = parser.parse("NOT(P(B))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("NOT(P(A))");
- s2 = parser.parse("NOT(P(x))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("A"), result.get(new Variable("x")));
- }
-
- @Test
- public void testConnectedSentence() {
- FOLDomain domain = new FOLDomain();
- domain.addConstant("A");
- domain.addConstant("B");
- domain.addConstant("C");
- domain.addFunction("Plus");
- domain.addPredicate("P");
-
- FOLParser parser = new FOLParser(domain);
-
- Sentence s1 = parser.parse("(P(A) AND P(B))");
- Sentence s2 = parser.parse("(P(A) AND P(B))");
-
- Map<Variable, Term> result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("(P(A) AND P(B))");
- s2 = parser.parse("(P(A) AND P(C))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("(P(A) AND P(B))");
- s2 = parser.parse("(P(A) AND P(x))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
-
- s1 = parser.parse("(P(A) OR P(B))");
- s2 = parser.parse("(P(A) OR P(B))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("(P(A) OR P(B))");
- s2 = parser.parse("(P(A) OR P(C))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("(P(A) OR P(B))");
- s2 = parser.parse("(P(A) OR P(x))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
-
- s1 = parser.parse("(P(A) => P(B))");
- s2 = parser.parse("(P(A) => P(B))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("(P(A) => P(B))");
- s2 = parser.parse("(P(A) => P(C))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("(P(A) => P(B))");
- s2 = parser.parse("(P(A) => P(x))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
-
- s1 = parser.parse("(P(A) <=> P(B))");
- s2 = parser.parse("(P(A) <=> P(B))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("(P(A) <=> P(B))");
- s2 = parser.parse("(P(A) <=> P(C))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("(P(A) <=> P(B))");
- s2 = parser.parse("(P(A) <=> P(x))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
-
- s1 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
- s2 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
- s2 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(A))))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
- s2 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(x))))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("C"), result.get(new Variable("x")));
- }
-
- @Test
- public void testQuantifiedSentence() {
- FOLDomain domain = new FOLDomain();
- domain.addConstant("A");
- domain.addConstant("B");
- domain.addConstant("C");
- domain.addFunction("Plus");
- domain.addPredicate("P");
-
- FOLParser parser = new FOLParser(domain);
-
- Sentence s1 = parser
- .parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- Sentence s2 = parser
- .parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
-
- Map<Variable, Term> result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- s2 = parser.parse("FORALL x ((P(x) AND P(A)) OR (P(A) => P(y)))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- s2 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(B) => P(y)))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- s2 = parser.parse("FORALL x,y ((P(A) AND P(A)) OR (P(A) => P(y)))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("A"), result.get(new Variable("x")));
-
- //
- s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- s2 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(0, result.size());
-
- s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- s2 = parser.parse("EXISTS x ((P(x) AND P(A)) OR (P(A) => P(y)))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- s2 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(B) => P(y)))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNull(result);
-
- s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
- s2 = parser.parse("EXISTS x,y ((P(A) AND P(A)) OR (P(A) => P(y)))");
-
- result = unifier.unify(s1, s2);
-
- Assert.assertNotNull(result);
- Assert.assertEquals(1, result.size());
- Assert.assertEquals(new Constant("A"), result.get(new Variable("x")));
- }
- }