PageRenderTime 26ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/aima-core/src/test/java/aima/test/core/unit/logic/fol/UnifierTest.java

http://aima-java.googlecode.com/
Java | 606 lines | 407 code | 162 blank | 37 comment | 0 complexity | 8b6cae8a572138184b4f475b57d2bb14 MD5 | raw file
Possible License(s): GPL-3.0, Apache-2.0
  1. package aima.test.core.unit.logic.fol;
  2. import java.util.ArrayList;
  3. import java.util.Hashtable;
  4. import java.util.List;
  5. import java.util.Map;
  6. import org.junit.Assert;
  7. import org.junit.Before;
  8. import org.junit.Test;
  9. import aima.core.logic.fol.Unifier;
  10. import aima.core.logic.fol.domain.DomainFactory;
  11. import aima.core.logic.fol.domain.FOLDomain;
  12. import aima.core.logic.fol.parsing.FOLParser;
  13. import aima.core.logic.fol.parsing.ast.Constant;
  14. import aima.core.logic.fol.parsing.ast.Function;
  15. import aima.core.logic.fol.parsing.ast.Predicate;
  16. import aima.core.logic.fol.parsing.ast.Sentence;
  17. import aima.core.logic.fol.parsing.ast.Term;
  18. import aima.core.logic.fol.parsing.ast.TermEquality;
  19. import aima.core.logic.fol.parsing.ast.Variable;
  20. /**
  21. * @author Ravi Mohan
  22. * @author Ciaran O'Reilly
  23. */
  24. public class UnifierTest {
  25. private FOLParser parser;
  26. private Unifier unifier;
  27. private Map<Variable, Term> theta;
  28. @Before
  29. public void setUp() {
  30. parser = new FOLParser(DomainFactory.knowsDomain());
  31. unifier = new Unifier();
  32. theta = new Hashtable<Variable, Term>();
  33. }
  34. @Test
  35. public void testFailureIfThetaisNull() {
  36. Variable var = new Variable("x");
  37. Sentence sentence = parser.parse("Knows(x)");
  38. theta = null;
  39. Map<Variable, Term> result = unifier.unify(var, sentence, theta);
  40. Assert.assertNull(result);
  41. }
  42. @Test
  43. public void testUnificationFailure() {
  44. Variable var = new Variable("x");
  45. Sentence sentence = parser.parse("Knows(y)");
  46. theta = null;
  47. Map<Variable, Term> result = unifier.unify(var, sentence, theta);
  48. Assert.assertNull(result);
  49. }
  50. @Test
  51. public void testThetaPassedBackIfXEqualsYBothVariables() {
  52. Variable var1 = new Variable("x");
  53. Variable var2 = new Variable("x");
  54. theta.put(new Variable("dummy"), new Variable("dummy"));
  55. Map<Variable, Term> result = unifier.unify(var1, var2, theta);
  56. Assert.assertEquals(theta, result);
  57. Assert.assertEquals(1, theta.keySet().size());
  58. Assert.assertTrue(theta.containsKey(new Variable("dummy")));
  59. }
  60. @Test
  61. public void testVariableEqualsConstant() {
  62. Variable var1 = new Variable("x");
  63. Constant constant = new Constant("John");
  64. Map<Variable, Term> result = unifier.unify(var1, constant, theta);
  65. Assert.assertEquals(theta, result);
  66. Assert.assertEquals(1, theta.keySet().size());
  67. Assert.assertTrue(theta.keySet().contains(var1));
  68. Assert.assertEquals(constant, theta.get(var1));
  69. }
  70. @Test
  71. public void testSimpleVariableUnification() {
  72. Variable var1 = new Variable("x");
  73. List<Term> terms1 = new ArrayList<Term>();
  74. terms1.add(var1);
  75. Predicate p1 = new Predicate("King", terms1); // King(x)
  76. List<Term> terms2 = new ArrayList<Term>();
  77. terms2.add(new Constant("John"));
  78. Predicate p2 = new Predicate("King", terms2); // King(John)
  79. Map<Variable, Term> result = unifier.unify(p1, p2, theta);
  80. Assert.assertEquals(theta, result);
  81. Assert.assertEquals(1, theta.keySet().size());
  82. Assert.assertTrue(theta.keySet().contains(new Variable("x"))); // x =
  83. Assert.assertEquals(new Constant("John"), theta.get(var1)); // John
  84. }
  85. @Test
  86. public void testKnows1() {
  87. Sentence query = parser.parse("Knows(John,x)");
  88. Sentence johnKnowsJane = parser.parse("Knows(John,Jane)");
  89. Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
  90. Assert.assertEquals(theta, result);
  91. Assert.assertTrue(theta.keySet().contains(new Variable("x"))); // x =
  92. Assert.assertEquals(new Constant("Jane"), theta.get(new Variable("x"))); // Jane
  93. }
  94. @Test
  95. public void testKnows2() {
  96. Sentence query = parser.parse("Knows(John,x)");
  97. Sentence johnKnowsJane = parser.parse("Knows(y,Bill)");
  98. Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
  99. Assert.assertEquals(2, result.size());
  100. Assert.assertEquals(new Constant("Bill"), theta.get(new Variable("x"))); // x
  101. // =
  102. // Bill
  103. Assert.assertEquals(new Constant("John"), theta.get(new Variable("y"))); // y
  104. // =
  105. // John
  106. }
  107. @Test
  108. public void testKnows3() {
  109. Sentence query = parser.parse("Knows(John,x)");
  110. Sentence johnKnowsJane = parser.parse("Knows(y,Mother(y))");
  111. Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
  112. Assert.assertEquals(2, result.size());
  113. List<Term> terms = new ArrayList<Term>();
  114. terms.add(new Constant("John"));
  115. Function mother = new Function("Mother", terms);
  116. Assert.assertEquals(mother, theta.get(new Variable("x")));
  117. Assert.assertEquals(new Constant("John"), theta.get(new Variable("y")));
  118. }
  119. @Test
  120. public void testKnows5() {
  121. Sentence query = parser.parse("Knows(John,x)");
  122. Sentence johnKnowsJane = parser.parse("Knows(y,z)");
  123. Map<Variable, Term> result = unifier.unify(query, johnKnowsJane, theta);
  124. Assert.assertEquals(2, result.size());
  125. Assert.assertEquals(new Variable("z"), theta.get(new Variable("x"))); // x
  126. // =
  127. // z
  128. Assert.assertEquals(new Constant("John"), theta.get(new Variable("y"))); // y
  129. // =
  130. // John
  131. }
  132. @Test
  133. public void testCascadedOccursCheck() {
  134. FOLDomain domain = new FOLDomain();
  135. domain.addPredicate("P");
  136. domain.addFunction("F");
  137. domain.addFunction("SF0");
  138. domain.addFunction("SF1");
  139. FOLParser parser = new FOLParser(domain);
  140. Sentence s1 = parser.parse("P(SF1(v2),v2)");
  141. Sentence s2 = parser.parse("P(v3,SF0(v3))");
  142. Map<Variable, Term> result = unifier.unify(s1, s2);
  143. Assert.assertNull(result);
  144. s1 = parser.parse("P(v1,SF0(v1),SF0(v1),SF0(v1),SF0(v1))");
  145. s2 = parser.parse("P(v2,SF0(v2),v2, v3, v2)");
  146. result = unifier.unify(s1, s2);
  147. Assert.assertNull(result);
  148. s1 = parser
  149. .parse("P(v1, F(v2),F(v2),F(v2),v1, F(F(v1)),F(F(F(v1))),v2)");
  150. s2 = parser
  151. .parse("P(F(v3),v4, v5, v6, F(F(v5)),v4, F(v3), F(F(v5)))");
  152. result = unifier.unify(s1, s2);
  153. Assert.assertNull(result);
  154. }
  155. /**
  156. * From: TPTP:LCL418-1 Am performing an incorrect unification for:
  157. * [is_a_theorem
  158. * (equivalent(equivalent(c1744,c1743),equivalent(c1742,c1743))),
  159. * is_a_theorem(equivalent(equivalent(c1752,c1751),c1752))]
  160. *
  161. * which is giving the following substitution:
  162. *
  163. * subst={c1744=equivalent(c1742,c1743), c1743=c1751,
  164. * c1752=equivalent(c1742,c1751)}
  165. *
  166. * which is incorrect as c1743 in the first function term needs to be c1751
  167. * as this is the second substitution.
  168. */
  169. @Test
  170. public void testBadCascadeSubstitution_LCL418_1() {
  171. FOLDomain domain = new FOLDomain();
  172. domain.addPredicate("ISATHEOREM");
  173. domain.addFunction("EQUIVALENT");
  174. FOLParser parser = new FOLParser(domain);
  175. Sentence s1 = parser
  176. .parse("ISATHEOREM(EQUIVALENT(EQUIVALENT(c1744,c1743),EQUIVALENT(c1742,c1743)))");
  177. Sentence s2 = parser
  178. .parse("ISATHEOREM(EQUIVALENT(EQUIVALENT(c1752,c1751),c1752))");
  179. Map<Variable, Term> result = unifier.unify(s1, s2);
  180. Assert.assertEquals(
  181. "{c1744=EQUIVALENT(c1742,c1751), c1743=c1751, c1752=EQUIVALENT(c1742,c1751)}",
  182. result.toString());
  183. }
  184. @Test
  185. public void testAdditionalVariableMixtures() {
  186. FOLDomain domain = new FOLDomain();
  187. domain.addConstant("A");
  188. domain.addConstant("B");
  189. domain.addFunction("F");
  190. domain.addFunction("G");
  191. domain.addFunction("H");
  192. domain.addPredicate("P");
  193. FOLParser parser = new FOLParser(domain);
  194. // Test Cascade Substitutions handled correctly
  195. Sentence s1 = parser.parse("P(z, x)");
  196. Sentence s2 = parser.parse("P(x, a)");
  197. Map<Variable, Term> result = unifier.unify(s1, s2);
  198. Assert.assertEquals("{z=a, x=a}", result.toString());
  199. s1 = parser.parse("P(x, z)");
  200. s2 = parser.parse("P(a, x)");
  201. result = unifier.unify(s1, s2);
  202. Assert.assertEquals("{x=a, z=a}", result.toString());
  203. s1 = parser.parse("P(w, w, w)");
  204. s2 = parser.parse("P(x, y, z)");
  205. result = unifier.unify(s1, s2);
  206. Assert.assertEquals("{w=z, x=z, y=z}", result.toString());
  207. s1 = parser.parse("P(x, y, z)");
  208. s2 = parser.parse("P(w, w, w)");
  209. result = unifier.unify(s1, s2);
  210. Assert.assertEquals("{x=w, y=w, z=w}", result.toString());
  211. s1 = parser.parse("P(x, B, F(y))");
  212. s2 = parser.parse("P(A, y, F(z))");
  213. result = unifier.unify(s1, s2);
  214. Assert.assertEquals("{x=A, y=B, z=B}", result.toString());
  215. s1 = parser.parse("P(F(x,B), G(y), F(z,A))");
  216. s2 = parser.parse("P(y, G(F(G(w),w)), F(w,z))");
  217. result = unifier.unify(s1, s2);
  218. Assert.assertNull(result);
  219. s1 = parser.parse("P(F(G(A)), x, F(H(z,z)), H(y, G(w)))");
  220. s2 = parser.parse("P(y, G(z), F(v ), H(F(w), x ))");
  221. result = unifier.unify(s1, s2);
  222. Assert.assertEquals(
  223. "{y=F(G(A)), x=G(G(A)), v=H(G(A),G(A)), w=G(A), z=G(A)}",
  224. result.toString());
  225. }
  226. @Test
  227. public void testTermEquality() {
  228. FOLDomain domain = new FOLDomain();
  229. domain.addConstant("A");
  230. domain.addConstant("B");
  231. domain.addFunction("Plus");
  232. FOLParser parser = new FOLParser(domain);
  233. TermEquality te1 = (TermEquality) parser.parse("x = x");
  234. TermEquality te2 = (TermEquality) parser.parse("x = x");
  235. // Both term equalities the same,
  236. // should unify but no substitutions.
  237. Map<Variable, Term> result = unifier.unify(te1, te2);
  238. Assert.assertNotNull(result);
  239. Assert.assertEquals(0, result.size());
  240. // Different variable names but should unify.
  241. te1 = (TermEquality) parser.parse("x1 = x1");
  242. te2 = (TermEquality) parser.parse("x2 = x2");
  243. result = unifier.unify(te1, te2);
  244. Assert.assertNotNull(result);
  245. Assert.assertEquals(1, result.size());
  246. Assert.assertEquals("{x1=x2}", result.toString());
  247. // Test simple unification with reflexivity axiom
  248. te1 = (TermEquality) parser.parse("x1 = x1");
  249. te2 = (TermEquality) parser.parse("Plus(A,B) = Plus(A,B)");
  250. result = unifier.unify(te1, te2);
  251. Assert.assertNotNull(result);
  252. Assert.assertEquals(1, result.size());
  253. Assert.assertEquals("{x1=Plus(A,B)}", result.toString());
  254. // Test more complex unification with reflexivity axiom
  255. te1 = (TermEquality) parser.parse("x1 = x1");
  256. te2 = (TermEquality) parser.parse("Plus(A,B) = Plus(A,z1)");
  257. result = unifier.unify(te1, te2);
  258. Assert.assertNotNull(result);
  259. Assert.assertEquals(2, result.size());
  260. Assert.assertEquals("{x1=Plus(A,B), z1=B}", result.toString());
  261. // Test reverse of previous unification with reflexivity axiom
  262. // Should still be the same.
  263. te1 = (TermEquality) parser.parse("x1 = x1");
  264. te2 = (TermEquality) parser.parse("Plus(A,z1) = Plus(A,B)");
  265. result = unifier.unify(te1, te2);
  266. Assert.assertNotNull(result);
  267. Assert.assertEquals(2, result.size());
  268. Assert.assertEquals("{x1=Plus(A,B), z1=B}", result.toString());
  269. // Test with nested terms
  270. te1 = (TermEquality) parser
  271. .parse("Plus(Plus(Plus(A,B),B, A)) = Plus(Plus(Plus(A,B),B, A))");
  272. te2 = (TermEquality) parser
  273. .parse("Plus(Plus(Plus(A,B),B, A)) = Plus(Plus(Plus(A,B),B, A))");
  274. result = unifier.unify(te1, te2);
  275. Assert.assertNotNull(result);
  276. Assert.assertEquals(0, result.size());
  277. // Simple term equality unification fails
  278. te1 = (TermEquality) parser.parse("Plus(A,B) = Plus(B,A)");
  279. te2 = (TermEquality) parser.parse("Plus(A,B) = Plus(A,B)");
  280. result = unifier.unify(te1, te2);
  281. Assert.assertNull(result);
  282. }
  283. @Test
  284. public void testNOTSentence() {
  285. FOLDomain domain = new FOLDomain();
  286. domain.addConstant("A");
  287. domain.addConstant("B");
  288. domain.addConstant("C");
  289. domain.addFunction("Plus");
  290. domain.addPredicate("P");
  291. FOLParser parser = new FOLParser(domain);
  292. Sentence s1 = parser.parse("NOT(P(A))");
  293. Sentence s2 = parser.parse("NOT(P(A))");
  294. Map<Variable, Term> result = unifier.unify(s1, s2);
  295. Assert.assertNotNull(result);
  296. Assert.assertEquals(0, result.size());
  297. s1 = parser.parse("NOT(P(A))");
  298. s2 = parser.parse("NOT(P(B))");
  299. result = unifier.unify(s1, s2);
  300. Assert.assertNull(result);
  301. s1 = parser.parse("NOT(P(A))");
  302. s2 = parser.parse("NOT(P(x))");
  303. result = unifier.unify(s1, s2);
  304. Assert.assertNotNull(result);
  305. Assert.assertEquals(1, result.size());
  306. Assert.assertEquals(new Constant("A"), result.get(new Variable("x")));
  307. }
  308. @Test
  309. public void testConnectedSentence() {
  310. FOLDomain domain = new FOLDomain();
  311. domain.addConstant("A");
  312. domain.addConstant("B");
  313. domain.addConstant("C");
  314. domain.addFunction("Plus");
  315. domain.addPredicate("P");
  316. FOLParser parser = new FOLParser(domain);
  317. Sentence s1 = parser.parse("(P(A) AND P(B))");
  318. Sentence s2 = parser.parse("(P(A) AND P(B))");
  319. Map<Variable, Term> result = unifier.unify(s1, s2);
  320. Assert.assertNotNull(result);
  321. Assert.assertEquals(0, result.size());
  322. s1 = parser.parse("(P(A) AND P(B))");
  323. s2 = parser.parse("(P(A) AND P(C))");
  324. result = unifier.unify(s1, s2);
  325. Assert.assertNull(result);
  326. s1 = parser.parse("(P(A) AND P(B))");
  327. s2 = parser.parse("(P(A) AND P(x))");
  328. result = unifier.unify(s1, s2);
  329. Assert.assertNotNull(result);
  330. Assert.assertEquals(1, result.size());
  331. Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
  332. s1 = parser.parse("(P(A) OR P(B))");
  333. s2 = parser.parse("(P(A) OR P(B))");
  334. result = unifier.unify(s1, s2);
  335. Assert.assertNotNull(result);
  336. Assert.assertEquals(0, result.size());
  337. s1 = parser.parse("(P(A) OR P(B))");
  338. s2 = parser.parse("(P(A) OR P(C))");
  339. result = unifier.unify(s1, s2);
  340. Assert.assertNull(result);
  341. s1 = parser.parse("(P(A) OR P(B))");
  342. s2 = parser.parse("(P(A) OR P(x))");
  343. result = unifier.unify(s1, s2);
  344. Assert.assertNotNull(result);
  345. Assert.assertEquals(1, result.size());
  346. Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
  347. s1 = parser.parse("(P(A) => P(B))");
  348. s2 = parser.parse("(P(A) => P(B))");
  349. result = unifier.unify(s1, s2);
  350. Assert.assertNotNull(result);
  351. Assert.assertEquals(0, result.size());
  352. s1 = parser.parse("(P(A) => P(B))");
  353. s2 = parser.parse("(P(A) => P(C))");
  354. result = unifier.unify(s1, s2);
  355. Assert.assertNull(result);
  356. s1 = parser.parse("(P(A) => P(B))");
  357. s2 = parser.parse("(P(A) => P(x))");
  358. result = unifier.unify(s1, s2);
  359. Assert.assertNotNull(result);
  360. Assert.assertEquals(1, result.size());
  361. Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
  362. s1 = parser.parse("(P(A) <=> P(B))");
  363. s2 = parser.parse("(P(A) <=> P(B))");
  364. result = unifier.unify(s1, s2);
  365. Assert.assertNotNull(result);
  366. Assert.assertEquals(0, result.size());
  367. s1 = parser.parse("(P(A) <=> P(B))");
  368. s2 = parser.parse("(P(A) <=> P(C))");
  369. result = unifier.unify(s1, s2);
  370. Assert.assertNull(result);
  371. s1 = parser.parse("(P(A) <=> P(B))");
  372. s2 = parser.parse("(P(A) <=> P(x))");
  373. result = unifier.unify(s1, s2);
  374. Assert.assertNotNull(result);
  375. Assert.assertEquals(1, result.size());
  376. Assert.assertEquals(new Constant("B"), result.get(new Variable("x")));
  377. s1 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
  378. s2 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
  379. result = unifier.unify(s1, s2);
  380. Assert.assertNotNull(result);
  381. Assert.assertEquals(0, result.size());
  382. s1 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
  383. s2 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(A))))");
  384. result = unifier.unify(s1, s2);
  385. Assert.assertNull(result);
  386. s1 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(C))))");
  387. s2 = parser.parse("((P(A) AND P(B)) OR (P(C) => (P(A) <=> P(x))))");
  388. result = unifier.unify(s1, s2);
  389. Assert.assertNotNull(result);
  390. Assert.assertEquals(1, result.size());
  391. Assert.assertEquals(new Constant("C"), result.get(new Variable("x")));
  392. }
  393. @Test
  394. public void testQuantifiedSentence() {
  395. FOLDomain domain = new FOLDomain();
  396. domain.addConstant("A");
  397. domain.addConstant("B");
  398. domain.addConstant("C");
  399. domain.addFunction("Plus");
  400. domain.addPredicate("P");
  401. FOLParser parser = new FOLParser(domain);
  402. Sentence s1 = parser
  403. .parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  404. Sentence s2 = parser
  405. .parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  406. Map<Variable, Term> result = unifier.unify(s1, s2);
  407. Assert.assertNotNull(result);
  408. Assert.assertEquals(0, result.size());
  409. s1 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  410. s2 = parser.parse("FORALL x ((P(x) AND P(A)) OR (P(A) => P(y)))");
  411. result = unifier.unify(s1, s2);
  412. Assert.assertNull(result);
  413. s1 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  414. s2 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(B) => P(y)))");
  415. result = unifier.unify(s1, s2);
  416. Assert.assertNull(result);
  417. s1 = parser.parse("FORALL x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  418. s2 = parser.parse("FORALL x,y ((P(A) AND P(A)) OR (P(A) => P(y)))");
  419. result = unifier.unify(s1, s2);
  420. Assert.assertNotNull(result);
  421. Assert.assertEquals(1, result.size());
  422. Assert.assertEquals(new Constant("A"), result.get(new Variable("x")));
  423. //
  424. s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  425. s2 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  426. result = unifier.unify(s1, s2);
  427. Assert.assertNotNull(result);
  428. Assert.assertEquals(0, result.size());
  429. s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  430. s2 = parser.parse("EXISTS x ((P(x) AND P(A)) OR (P(A) => P(y)))");
  431. result = unifier.unify(s1, s2);
  432. Assert.assertNull(result);
  433. s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  434. s2 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(B) => P(y)))");
  435. result = unifier.unify(s1, s2);
  436. Assert.assertNull(result);
  437. s1 = parser.parse("EXISTS x,y ((P(x) AND P(A)) OR (P(A) => P(y)))");
  438. s2 = parser.parse("EXISTS x,y ((P(A) AND P(A)) OR (P(A) => P(y)))");
  439. result = unifier.unify(s1, s2);
  440. Assert.assertNotNull(result);
  441. Assert.assertEquals(1, result.size());
  442. Assert.assertEquals(new Constant("A"), result.get(new Variable("x")));
  443. }
  444. }