001 package aima.test.logictest.foltest; 002 003 import java.util.ArrayList; 004 import java.util.LinkedHashSet; 005 import java.util.List; 006 import java.util.Set; 007 008 import junit.framework.TestCase; 009 import aima.logic.fol.CNFConverter; 010 import aima.logic.fol.StandardizeApartIndexicalFactory; 011 import aima.logic.fol.domain.DomainFactory; 012 import aima.logic.fol.domain.FOLDomain; 013 import aima.logic.fol.kb.FOLKnowledgeBase; 014 import aima.logic.fol.kb.data.CNF; 015 import aima.logic.fol.kb.data.Clause; 016 import aima.logic.fol.kb.data.Literal; 017 import aima.logic.fol.parsing.FOLParser; 018 import aima.logic.fol.parsing.ast.AtomicSentence; 019 import aima.logic.fol.parsing.ast.Constant; 020 import aima.logic.fol.parsing.ast.Function; 021 import aima.logic.fol.parsing.ast.Predicate; 022 import aima.logic.fol.parsing.ast.Sentence; 023 import aima.logic.fol.parsing.ast.Term; 024 import aima.logic.fol.parsing.ast.Variable; 025 026 /** 027 * @author Ciaran O'Reilly 028 * 029 */ 030 public class ClauseTest extends TestCase { 031 032 public void setUp() { 033 StandardizeApartIndexicalFactory.flush(); 034 } 035 036 public void testImmutable() { 037 Clause c = new Clause(); 038 039 assertFalse(c.isImmutable()); 040 041 c.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 042 c.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 043 044 c.setImmutable(); 045 046 assertTrue(c.isImmutable()); 047 048 try { 049 c.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>())); 050 051 fail("Should have thrown an IllegalStateException"); 052 } catch (IllegalStateException ise) { 053 // Ok, Expected 054 } 055 056 try { 057 c.addPositiveLiteral(new Predicate("Pred3", new ArrayList<Term>())); 058 059 fail("Should have thrown an IllegalStateException"); 060 } catch (IllegalStateException ise) { 061 // Ok, Expected 062 } 063 } 064 065 public void testIsEmpty() { 066 Clause c1 = new Clause(); 067 assertTrue(c1.isEmpty()); 068 069 c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 070 assertFalse(c1.isEmpty()); 071 072 Clause c2 = new Clause(); 073 assertTrue(c2.isEmpty()); 074 075 c2.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 076 assertFalse(c2.isEmpty()); 077 078 Clause c3 = new Clause(); 079 assertTrue(c3.isEmpty()); 080 081 c3.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 082 c3.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 083 // Should be empty as they resolved with each other 084 assertFalse(c3.isEmpty()); 085 086 c3.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 087 c3.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 088 assertFalse(c3.isEmpty()); 089 } 090 091 public void testIsHornClause() { 092 Clause c1 = new Clause(); 093 assertFalse(c1.isHornClause()); 094 095 c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 096 assertTrue(c1.isHornClause()); 097 098 c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 099 assertTrue(c1.isHornClause()); 100 101 c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>())); 102 assertTrue(c1.isHornClause()); 103 c1.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>())); 104 assertTrue(c1.isHornClause()); 105 106 c1.addPositiveLiteral(new Predicate("Pred5", new ArrayList<Term>())); 107 assertFalse(c1.isHornClause()); 108 } 109 110 public void testIsDefiniteClause() { 111 Clause c1 = new Clause(); 112 assertFalse(c1.isDefiniteClause()); 113 114 c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 115 assertFalse(c1.isDefiniteClause()); 116 117 c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 118 assertTrue(c1.isDefiniteClause()); 119 120 c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>())); 121 assertTrue(c1.isDefiniteClause()); 122 c1.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>())); 123 assertTrue(c1.isDefiniteClause()); 124 125 c1.addPositiveLiteral(new Predicate("Pred5", new ArrayList<Term>())); 126 assertFalse(c1.isDefiniteClause()); 127 } 128 129 public void testIsUnitClause() { 130 Clause c1 = new Clause(); 131 assertFalse(c1.isUnitClause()); 132 133 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 134 assertTrue(c1.isUnitClause()); 135 136 c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 137 assertFalse(c1.isUnitClause()); 138 139 140 c1 = new Clause(); 141 assertFalse(c1.isUnitClause()); 142 143 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 144 assertTrue(c1.isUnitClause()); 145 146 c1.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>())); 147 assertFalse(c1.isUnitClause()); 148 149 c1 = new Clause(); 150 assertFalse(c1.isUnitClause()); 151 152 c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 153 assertTrue(c1.isUnitClause()); 154 155 c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 156 assertFalse(c1.isUnitClause()); 157 } 158 159 public void testIsImplicationDefiniteClause() { 160 Clause c1 = new Clause(); 161 assertFalse(c1.isImplicationDefiniteClause()); 162 163 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 164 assertFalse(c1.isImplicationDefiniteClause()); 165 166 c1.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>())); 167 assertTrue(c1.isImplicationDefiniteClause()); 168 c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>())); 169 assertTrue(c1.isImplicationDefiniteClause()); 170 171 c1.addPositiveLiteral(new Predicate("Pred4", new ArrayList<Term>())); 172 assertFalse(c1.isImplicationDefiniteClause()); 173 } 174 175 public void testBinaryResolvents() { 176 FOLDomain domain = new FOLDomain(); 177 domain.addPredicate("Pred1"); 178 domain.addPredicate("Pred2"); 179 domain.addPredicate("Pred3"); 180 domain.addPredicate("Pred4"); 181 182 Clause c1 = new Clause(); 183 184 // Ensure that resolving to self when empty returns an empty clause 185 assertNotNull(c1.binaryResolvents(c1)); 186 assertEquals(1, c1.binaryResolvents(c1).size()); 187 assertTrue(c1.binaryResolvents(c1).iterator().next().isEmpty()); 188 189 // Check if resolve with self to an empty clause 190 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 191 c1.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 192 assertNotNull(c1.binaryResolvents(c1)); 193 assertEquals(1, c1.binaryResolvents(c1).size()); 194 // i.e. resolving a tautology with a tautology gives you 195 // back a tautology. 196 assertEquals("[~Pred1(), Pred1()]", c1.binaryResolvents(c1).iterator() 197 .next().toString()); 198 199 // Check if try to resolve with self and no resolvents 200 c1 = new Clause(); 201 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 202 assertEquals(0, c1.binaryResolvents(c1).size()); 203 204 c1 = new Clause(); 205 Clause c2 = new Clause(); 206 // Ensure that two empty clauses resolve to an empty clause 207 assertNotNull(c1.binaryResolvents(c2)); 208 assertEquals(1, c1.binaryResolvents(c2).size()); 209 assertTrue(c1.binaryResolvents(c2).iterator().next().isEmpty()); 210 assertNotNull(c2.binaryResolvents(c1)); 211 assertEquals(1, c2.binaryResolvents(c1).size()); 212 assertTrue(c2.binaryResolvents(c1).iterator().next().isEmpty()); 213 214 // Enusre the two complementary clauses resolve 215 // to the empty clause 216 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 217 c2.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 218 assertNotNull(c1.binaryResolvents(c2)); 219 assertEquals(1, c1.binaryResolvents(c2).size()); 220 assertTrue(c1.binaryResolvents(c2).iterator().next().isEmpty()); 221 assertNotNull(c2.binaryResolvents(c1)); 222 assertEquals(1, c2.binaryResolvents(c1).size()); 223 assertTrue(c2.binaryResolvents(c1).iterator().next().isEmpty()); 224 225 // Ensure that two clauses that have two complementaries 226 // resolve with two resolvents 227 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 228 c2.addNegativeLiteral(new Predicate("Pred1", new ArrayList<Term>())); 229 c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 230 c2.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>())); 231 assertNotNull(c1.binaryResolvents(c2)); 232 assertEquals(2, c1.binaryResolvents(c2).size()); 233 assertNotNull(c2.binaryResolvents(c1)); 234 assertEquals(2, c2.binaryResolvents(c1).size()); 235 236 // Ensure two clauses that factor are not 237 // considered resolved 238 c1 = new Clause(); 239 c2 = new Clause(); 240 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 241 c1.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 242 c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>())); 243 c1.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>())); 244 c2.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 245 c2.addNegativeLiteral(new Predicate("Pred4", new ArrayList<Term>())); 246 assertNotNull(c1.binaryResolvents(c2)); 247 assertEquals(0, c1.binaryResolvents(c2).size()); 248 assertNotNull(c2.binaryResolvents(c1)); 249 assertEquals(0, c2.binaryResolvents(c1).size()); 250 251 // Ensure the resolvent is a subset of the originals 252 c1 = new Clause(); 253 c2 = new Clause(); 254 c1.addPositiveLiteral(new Predicate("Pred1", new ArrayList<Term>())); 255 c1.addNegativeLiteral(new Predicate("Pred2", new ArrayList<Term>())); 256 c1.addNegativeLiteral(new Predicate("Pred3", new ArrayList<Term>())); 257 c2.addPositiveLiteral(new Predicate("Pred2", new ArrayList<Term>())); 258 assertNotNull(c1.binaryResolvents(c2)); 259 assertNotNull(c2.binaryResolvents(c1)); 260 assertEquals(1, c1.binaryResolvents(c2).iterator().next() 261 .getNumberPositiveLiterals()); 262 assertEquals(1, c1.binaryResolvents(c2).iterator().next() 263 .getNumberNegativeLiterals()); 264 assertEquals(1, c2.binaryResolvents(c1).iterator().next() 265 .getNumberPositiveLiterals()); 266 assertEquals(1, c2.binaryResolvents(c1).iterator().next() 267 .getNumberNegativeLiterals()); 268 } 269 270 public void testBinaryResolventsOrderDoesNotMatter() { 271 // This is a regression test, to ensure 272 // the ordering of resolvents does not matter. 273 // If the order ends up mattering, then likely 274 // a problem was introduced in the Clause class 275 // unifier, or related class. 276 277 // Set up the initial set of clauses based on the 278 // loves animal domain as it contains functions 279 // new clauses will always be created (i.e. is an 280 // infinite universe of discourse). 281 FOLKnowledgeBase kb = new FOLKnowledgeBase(DomainFactory 282 .lovesAnimalDomain()); 283 284 kb 285 .tell("FORALL x (FORALL y (Animal(y) => Loves(x, y)) => EXISTS y Loves(y, x))"); 286 kb 287 .tell("FORALL x (EXISTS y (Animal(y) AND Kills(x, y)) => FORALL z NOT(Loves(z, x)))"); 288 kb.tell("FORALL x (Animal(x) => Loves(Jack, x))"); 289 kb.tell("(Kills(Jack, Tuna) OR Kills(Curiosity, Tuna))"); 290 kb.tell("Cat(Tuna)"); 291 kb.tell("FORALL x (Cat(x) => Animal(x))"); 292 293 Set<Clause> clauses = new LinkedHashSet<Clause>(); 294 clauses.addAll(kb.getAllClauses()); 295 296 Set<Clause> newClauses = new LinkedHashSet<Clause>(); 297 long maxRunTime = 30 * 1000; // 30 seconds 298 long finishTime = System.currentTimeMillis() + maxRunTime; 299 do { 300 clauses.addAll(newClauses); 301 newClauses.clear(); 302 Clause[] clausesA = new Clause[clauses.size()]; 303 clauses.toArray(clausesA); 304 for (int i = 0; i < clausesA.length; i++) { 305 Clause cI = clausesA[i]; 306 for (int j = 0; j < clausesA.length; j++) { 307 Clause cJ = clausesA[j]; 308 309 newClauses.addAll(cI.getFactors()); 310 newClauses.addAll(cJ.getFactors()); 311 312 Set<Clause> cIresolvents = cI.binaryResolvents(cJ); 313 Set<Clause> cJresolvents = cJ.binaryResolvents(cI); 314 if (!cIresolvents.equals(cJresolvents)) { 315 System.err.println("cI=" + cI); 316 System.err.println("cJ=" + cJ); 317 System.err.println("cIR=" + cIresolvents); 318 System.err.println("cJR=" + cJresolvents); 319 fail("Ordering of binary resolvents has become important, which should not be the case"); 320 } 321 322 for (Clause r : cIresolvents) { 323 newClauses.addAll(r.getFactors()); 324 } 325 326 if (System.currentTimeMillis() > finishTime) { 327 break; 328 } 329 } 330 if (System.currentTimeMillis() > finishTime) { 331 break; 332 } 333 } 334 } while (System.currentTimeMillis() < finishTime); 335 } 336 337 public void testEqualityBinaryResolvents() { 338 FOLDomain domain = new FOLDomain(); 339 domain.addConstant("A"); 340 domain.addConstant("B"); 341 342 FOLParser parser = new FOLParser(domain); 343 344 // B = A 345 Clause c1 = new Clause(); 346 c1.addPositiveLiteral((AtomicSentence) parser.parse("B = A")); 347 348 Clause c2 = new Clause(); 349 c2.addNegativeLiteral((AtomicSentence) parser.parse("B = A")); 350 c2.addPositiveLiteral((AtomicSentence) parser.parse("B = A")); 351 352 Set<Clause> resolvents = c1.binaryResolvents(c2); 353 354 assertEquals(1, resolvents.size()); 355 assertEquals("[[B = A]]", resolvents.toString()); 356 } 357 358 public void testHashCode() { 359 Term cons1 = new Constant("C1"); 360 Term cons2 = new Constant("C2"); 361 Term var1 = new Variable("v1"); 362 List<Term> pts1 = new ArrayList<Term>(); 363 List<Term> pts2 = new ArrayList<Term>(); 364 pts1.add(cons1); 365 pts1.add(cons2); 366 pts1.add(var1); 367 pts2.add(cons2); 368 pts2.add(cons1); 369 pts2.add(var1); 370 371 Clause c1 = new Clause(); 372 Clause c2 = new Clause(); 373 assertEquals(c1.hashCode(), c2.hashCode()); 374 375 c1.addNegativeLiteral(new Predicate("Pred1", pts1)); 376 assertNotSame(c1.hashCode(), c2.hashCode()); 377 c2.addNegativeLiteral(new Predicate("Pred1", pts1)); 378 assertEquals(c1.hashCode(), c2.hashCode()); 379 380 c1.addPositiveLiteral(new Predicate("Pred1", pts1)); 381 assertNotSame(c1.hashCode(), c2.hashCode()); 382 c2.addPositiveLiteral(new Predicate("Pred1", pts1)); 383 assertEquals(c1.hashCode(), c2.hashCode()); 384 } 385 386 public void testSimpleEquals() { 387 Term cons1 = new Constant("C1"); 388 Term cons2 = new Constant("C2"); 389 Term var1 = new Variable("v1"); 390 List<Term> pts1 = new ArrayList<Term>(); 391 List<Term> pts2 = new ArrayList<Term>(); 392 pts1.add(cons1); 393 pts1.add(cons2); 394 pts1.add(var1); 395 pts2.add(cons2); 396 pts2.add(cons1); 397 pts2.add(var1); 398 399 Clause c1 = new Clause(); 400 Clause c2 = new Clause(); 401 assertTrue(c1.equals(c1)); 402 assertTrue(c2.equals(c2)); 403 assertTrue(c1.equals(c2)); 404 assertTrue(c2.equals(c1)); 405 406 // Check negatives 407 c1.addNegativeLiteral(new Predicate("Pred1", pts1)); 408 assertFalse(c1.equals(c2)); 409 assertFalse(c2.equals(c1)); 410 c2.addNegativeLiteral(new Predicate("Pred1", pts1)); 411 assertTrue(c1.equals(c2)); 412 assertTrue(c2.equals(c1)); 413 414 c1.addNegativeLiteral(new Predicate("Pred2", pts2)); 415 assertFalse(c1.equals(c2)); 416 assertFalse(c2.equals(c1)); 417 c2.addNegativeLiteral(new Predicate("Pred2", pts2)); 418 assertTrue(c1.equals(c2)); 419 assertTrue(c2.equals(c1)); 420 // Check same but added in different order 421 c1.addNegativeLiteral(new Predicate("Pred3", pts1)); 422 assertFalse(c1.equals(c2)); 423 assertFalse(c2.equals(c1)); 424 c1.addNegativeLiteral(new Predicate("Pred4", pts1)); 425 assertFalse(c1.equals(c2)); 426 assertFalse(c2.equals(c1)); 427 c2.addNegativeLiteral(new Predicate("Pred4", pts1)); 428 assertFalse(c1.equals(c2)); 429 assertFalse(c2.equals(c1)); 430 c2.addNegativeLiteral(new Predicate("Pred3", pts1)); 431 assertTrue(c1.equals(c2)); 432 assertTrue(c2.equals(c1)); 433 434 // Check positives 435 c1.addPositiveLiteral(new Predicate("Pred1", pts1)); 436 assertFalse(c1.equals(c2)); 437 assertFalse(c2.equals(c1)); 438 c2.addPositiveLiteral(new Predicate("Pred1", pts1)); 439 assertTrue(c1.equals(c2)); 440 assertTrue(c2.equals(c1)); 441 442 c1.addPositiveLiteral(new Predicate("Pred2", pts2)); 443 assertFalse(c1.equals(c2)); 444 assertFalse(c2.equals(c1)); 445 c2.addPositiveLiteral(new Predicate("Pred2", pts2)); 446 assertTrue(c1.equals(c2)); 447 assertTrue(c2.equals(c1)); 448 // Check same but added in different order 449 c1.addPositiveLiteral(new Predicate("Pred3", pts1)); 450 assertFalse(c1.equals(c2)); 451 assertFalse(c2.equals(c1)); 452 c1.addPositiveLiteral(new Predicate("Pred4", pts1)); 453 assertFalse(c1.equals(c2)); 454 assertFalse(c2.equals(c1)); 455 c2.addPositiveLiteral(new Predicate("Pred4", pts1)); 456 assertFalse(c1.equals(c2)); 457 assertFalse(c2.equals(c1)); 458 c2.addPositiveLiteral(new Predicate("Pred3", pts1)); 459 assertTrue(c1.equals(c2)); 460 assertTrue(c2.equals(c1)); 461 } 462 463 public void testComplexEquals() { 464 FOLDomain domain = new FOLDomain(); 465 domain.addConstant("A"); 466 domain.addConstant("B"); 467 domain.addConstant("C"); 468 domain.addConstant("D"); 469 domain.addPredicate("P"); 470 domain.addPredicate("Animal"); 471 domain.addPredicate("Kills"); 472 domain.addFunction("F"); 473 domain.addFunction("SF0"); 474 475 FOLParser parser = new FOLParser(domain); 476 477 CNFConverter cnfConverter = new CNFConverter(parser); 478 Sentence s1 = parser.parse("((x1 = y1 AND y1 = z1) => x1 = z1)"); 479 Sentence s2 = parser.parse("((x2 = y2 AND F(y2) = z2) => F(x2) = z2)"); 480 CNF cnf1 = cnfConverter.convertToCNF(s1); 481 CNF cnf2 = cnfConverter.convertToCNF(s2); 482 483 Clause c1 = cnf1.getConjunctionOfClauses().get(0); 484 Clause c2 = cnf2.getConjunctionOfClauses().get(0); 485 486 assertFalse(c1.equals(c2)); 487 488 s1 = parser.parse("((x1 = y1 AND y1 = z1) => x1 = z1)"); 489 s2 = parser.parse("((x2 = y2 AND y2 = z2) => x2 = z2)"); 490 cnf1 = cnfConverter.convertToCNF(s1); 491 cnf2 = cnfConverter.convertToCNF(s2); 492 493 c1 = cnf1.getConjunctionOfClauses().get(0); 494 c2 = cnf2.getConjunctionOfClauses().get(0); 495 496 assertTrue(c1.equals(c2)); 497 498 s1 = parser.parse("((x1 = y1 AND y1 = z1) => x1 = z1)"); 499 s2 = parser.parse("((y2 = z2 AND x2 = y2) => x2 = z2)"); 500 cnf1 = cnfConverter.convertToCNF(s1); 501 cnf2 = cnfConverter.convertToCNF(s2); 502 503 c1 = cnf1.getConjunctionOfClauses().get(0); 504 c2 = cnf2.getConjunctionOfClauses().get(0); 505 506 assertTrue(c1.equals(c2)); 507 508 s1 = parser.parse("(((x1 = y1 AND y1 = z1) AND z1 = r1) => x1 = r1)"); 509 s2 = parser.parse("(((x2 = y2 AND y2 = z2) AND z2 = r2) => x2 = r2)"); 510 cnf1 = cnfConverter.convertToCNF(s1); 511 cnf2 = cnfConverter.convertToCNF(s2); 512 513 c1 = cnf1.getConjunctionOfClauses().get(0); 514 c2 = cnf2.getConjunctionOfClauses().get(0); 515 516 assertTrue(c1.equals(c2)); 517 518 s1 = parser.parse("(((x1 = y1 AND y1 = z1) AND z1 = r1) => x1 = r1)"); 519 s2 = parser.parse("(((z2 = r2 AND y2 = z2) AND x2 = y2) => x2 = r2)"); 520 cnf1 = cnfConverter.convertToCNF(s1); 521 cnf2 = cnfConverter.convertToCNF(s2); 522 523 c1 = cnf1.getConjunctionOfClauses().get(0); 524 c2 = cnf2.getConjunctionOfClauses().get(0); 525 526 assertTrue(c1.equals(c2)); 527 528 s1 = parser.parse("(((x1 = y1 AND y1 = z1) AND z1 = r1) => x1 = r1)"); 529 s2 = parser.parse("(((x2 = y2 AND y2 = z2) AND z2 = y2) => x2 = r2)"); 530 cnf1 = cnfConverter.convertToCNF(s1); 531 cnf2 = cnfConverter.convertToCNF(s2); 532 533 c1 = cnf1.getConjunctionOfClauses().get(0); 534 c2 = cnf2.getConjunctionOfClauses().get(0); 535 536 assertFalse(c1.equals(c2)); 537 538 s1 = parser 539 .parse("(((((x1 = y1 AND y1 = z1) AND z1 = r1) AND r1 = q1) AND q1 = s1) => x1 = r1)"); 540 s2 = parser 541 .parse("(((((x2 = y2 AND y2 = z2) AND z2 = r2) AND r2 = q2) AND q2 = s2) => x2 = r2)"); 542 cnf1 = cnfConverter.convertToCNF(s1); 543 cnf2 = cnfConverter.convertToCNF(s2); 544 545 c1 = cnf1.getConjunctionOfClauses().get(0); 546 c2 = cnf2.getConjunctionOfClauses().get(0); 547 548 assertTrue(c1.equals(c2)); 549 550 s1 = parser 551 .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))))"); 552 s2 = parser 553 .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))))"); 554 cnf1 = cnfConverter.convertToCNF(s1); 555 cnf2 = cnfConverter.convertToCNF(s2); 556 557 c1 = cnf1.getConjunctionOfClauses().get(0); 558 c2 = cnf2.getConjunctionOfClauses().get(0); 559 560 assertTrue(c1.equals(c2)); 561 } 562 563 public void testNonTrivialFactors() { 564 FOLDomain domain = new FOLDomain(); 565 domain.addConstant("A"); 566 domain.addConstant("B"); 567 domain.addFunction("F"); 568 domain.addFunction("G"); 569 domain.addFunction("H"); 570 domain.addPredicate("P"); 571 domain.addPredicate("Q"); 572 573 FOLParser parser = new FOLParser(domain); 574 575 // p(x,y), q(a,b), ¬p(b,a), q(y,x) 576 Clause c = new Clause(); 577 c.addPositiveLiteral((Predicate) parser.parse("P(x,y)")); 578 c.addPositiveLiteral((Predicate) parser.parse("Q(A,B)")); 579 c.addNegativeLiteral((Predicate) parser.parse("P(B,A)")); 580 c.addPositiveLiteral((Predicate) parser.parse("Q(y,x)")); 581 582 assertEquals("[[~P(B,A), P(B,A), Q(A,B)]]", c.getNonTrivialFactors() 583 .toString()); 584 585 // p(x,y), q(a,b), ¬p(b,a), ¬q(y,x) 586 c = new Clause(); 587 c.addPositiveLiteral((Predicate) parser.parse("P(x,y)")); 588 c.addPositiveLiteral((Predicate) parser.parse("Q(A,B)")); 589 c.addNegativeLiteral((Predicate) parser.parse("P(B,A)")); 590 c.addNegativeLiteral((Predicate) parser.parse("Q(y,x)")); 591 592 assertEquals("[]", c.getNonTrivialFactors().toString()); 593 594 // p(x,f(y)), p(g(u),x), p(f(y),u) 595 c = new Clause(); 596 c.addPositiveLiteral((Predicate) parser.parse("P(x,F(y))")); 597 c.addPositiveLiteral((Predicate) parser.parse("P(G(u),x)")); 598 c.addPositiveLiteral((Predicate) parser.parse("P(F(y),u)")); 599 600 // Should be: [{P(F(c#),F(c#)),P(G(F(c#)),F(c#))}] 601 c = c.getNonTrivialFactors().iterator().next(); 602 Literal p = c.getPositiveLiterals().get(0); 603 assertEquals("P", p.getAtomicSentence().getSymbolicName()); 604 Function f = (Function) p.getAtomicSentence().getArgs().get(0); 605 assertEquals("F", f.getFunctionName()); 606 Variable v = (Variable) f.getTerms().get(0); 607 f = (Function) p.getAtomicSentence().getArgs().get(1); 608 assertEquals("F", f.getFunctionName()); 609 assertEquals(v, f.getTerms().get(0)); 610 611 // 612 p = c.getPositiveLiterals().get(1); 613 f = (Function) p.getAtomicSentence().getArgs().get(0); 614 assertEquals("G", f.getFunctionName()); 615 f = (Function) f.getTerms().get(0); 616 assertEquals("F", f.getFunctionName()); 617 assertEquals(v, f.getTerms().get(0)); 618 f = (Function) p.getAtomicSentence().getArgs().get(1); 619 assertEquals("F", f.getFunctionName()); 620 assertEquals(v, f.getTerms().get(0)); 621 622 623 // p(g(x)), q(x), p(f(a)), p(x), p(g(f(x))), q(f(a)) 624 c = new Clause(); 625 c.addPositiveLiteral((Predicate) parser.parse("P(G(x))")); 626 c.addPositiveLiteral((Predicate) parser.parse("Q(x)")); 627 c.addPositiveLiteral((Predicate) parser.parse("P(F(A))")); 628 c.addPositiveLiteral((Predicate) parser.parse("P(x)")); 629 c.addPositiveLiteral((Predicate) parser.parse("P(G(F(x)))")); 630 c.addPositiveLiteral((Predicate) parser.parse("Q(F(A))")); 631 632 assertEquals("[[P(F(A)), P(G(F(F(A)))), P(G(F(A))), Q(F(A))]]", c 633 .getNonTrivialFactors().toString()); 634 } 635 636 // Note: Tests derived from: 637 // http://logic.stanford.edu/classes/cs157/2008/notes/chap09.pdf 638 // page 16. 639 public void testIsTautology() { 640 FOLDomain domain = new FOLDomain(); 641 domain.addConstant("A"); 642 domain.addPredicate("P"); 643 domain.addPredicate("Q"); 644 domain.addPredicate("R"); 645 domain.addFunction("F"); 646 647 FOLParser parser = new FOLParser(domain); 648 649 // {p(f(a)),~p(f(a))} 650 Clause c = new Clause(); 651 c.addPositiveLiteral((Predicate) parser.parse("P(F(A))")); 652 assertFalse(c.isTautology()); 653 c.addNegativeLiteral((Predicate) parser.parse("P(F(A))")); 654 assertTrue(c.isTautology()); 655 656 // {p(x),q(y),~q(y),r(z)} 657 c = new Clause(); 658 c.addPositiveLiteral((Predicate) parser.parse("P(x)")); 659 assertFalse(c.isTautology()); 660 c.addPositiveLiteral((Predicate) parser.parse("Q(y)")); 661 assertFalse(c.isTautology()); 662 c.addNegativeLiteral((Predicate) parser.parse("Q(y)")); 663 assertTrue(c.isTautology()); 664 c.addPositiveLiteral((Predicate) parser.parse("R(z)")); 665 assertTrue(c.isTautology()); 666 667 // {~p(a),p(x)} 668 c = new Clause(); 669 c.addNegativeLiteral((Predicate) parser.parse("P(A)")); 670 assertFalse(c.isTautology()); 671 c.addPositiveLiteral((Predicate) parser.parse("P(x)")); 672 assertFalse(c.isTautology()); 673 } 674 675 // Note: Tests derived from: 676 // http://logic.stanford.edu/classes/cs157/2008/lectures/lecture12.pdf 677 // slides 17 and 18. 678 public void testSubsumes() { 679 FOLDomain domain = new FOLDomain(); 680 domain.addConstant("A"); 681 domain.addConstant("B"); 682 domain.addConstant("C"); 683 domain.addConstant("D"); 684 domain.addConstant("E"); 685 domain.addConstant("F"); 686 domain.addConstant("G"); 687 domain.addConstant("H"); 688 domain.addConstant("I"); 689 domain.addConstant("J"); 690 domain.addPredicate("P"); 691 domain.addPredicate("Q"); 692 693 FOLParser parser = new FOLParser(domain); 694 695 // Example 696 // {~p(a,b),q(c)} 697 Clause psi = new Clause(); 698 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 699 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 700 // {~p(x,y)} 701 Clause phi = new Clause(); 702 phi.addNegativeLiteral((Predicate) parser.parse("P(x,y)")); 703 704 assertTrue(phi.subsumes(psi)); 705 // Non-Example 706 // {~p(x,b),q(x)} 707 psi = new Clause(); 708 psi.addNegativeLiteral((Predicate) parser.parse("P(x,B)")); 709 psi.addPositiveLiteral((Predicate) parser.parse("Q(x)")); 710 // {~p(a,y)} 711 phi = new Clause(); 712 phi.addNegativeLiteral((Predicate) parser.parse("P(A,y)")); 713 // Reason for Non-Example: 714 // {p(b,b)} 715 // {~q(b)} 716 assertFalse(phi.subsumes(psi)); 717 718 // 719 // Additional Examples 720 721 // Non-Example 722 // {~p(x,b),q(z)} 723 psi = new Clause(); 724 psi.addNegativeLiteral((Predicate) parser.parse("P(x,B)")); 725 psi.addPositiveLiteral((Predicate) parser.parse("Q(z)")); 726 // {~p(a,y)} 727 phi = new Clause(); 728 phi.addNegativeLiteral((Predicate) parser.parse("P(A,y)")); 729 730 assertFalse(phi.subsumes(psi)); 731 732 // Example 733 // {~p(a,b),~p(w,z),q(c)} 734 psi = new Clause(); 735 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 736 psi.addNegativeLiteral((Predicate) parser.parse("P(w,z)")); 737 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 738 // {~p(x,y),~p(a,b)} 739 phi = new Clause(); 740 phi.addNegativeLiteral((Predicate) parser.parse("P(x,y)")); 741 phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 742 743 assertTrue(phi.subsumes(psi)); 744 745 // Non-Example 746 // {~p(v,b),~p(w,z),q(c)} 747 psi = new Clause(); 748 psi.addNegativeLiteral((Predicate) parser.parse("P(v,B)")); 749 psi.addNegativeLiteral((Predicate) parser.parse("P(w,z)")); 750 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 751 // {~p(x,y),~p(a,b)} 752 phi = new Clause(); 753 phi.addNegativeLiteral((Predicate) parser.parse("P(x,y)")); 754 phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 755 756 assertFalse(phi.subsumes(psi)); 757 758 // Example 759 // {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(c)} 760 psi = new Clause(); 761 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 762 psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 763 psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 764 psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)")); 765 psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 766 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 767 // {~p(i,j)} 768 phi = new Clause(); 769 phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 770 771 assertTrue(phi.subsumes(psi)); 772 773 // Example 774 // {~p(a,b),~p(c,d),~p(e,f),q(c)} 775 psi = new Clause(); 776 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 777 psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 778 psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 779 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 780 // {~p(e,f),~p(a,b),~p(c,d)} 781 phi = new Clause(); 782 phi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 783 phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 784 phi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 785 786 assertTrue(phi.subsumes(psi)); 787 788 // Example 789 // {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(c)} 790 psi = new Clause(); 791 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 792 psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 793 psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 794 psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)")); 795 psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 796 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 797 // {~p(i,j),~p(c,d)} 798 phi = new Clause(); 799 phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 800 phi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 801 802 assertTrue(phi.subsumes(psi)); 803 804 // Non-Example 805 // {~p(a,b),~p(x,d),~p(e,f),~p(g,h),~p(i,j),q(c)} 806 psi = new Clause(); 807 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 808 psi.addNegativeLiteral((Predicate) parser.parse("P(x,D)")); 809 psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 810 psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)")); 811 psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 812 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 813 // {~p(i,j),~p(c,d)} 814 phi = new Clause(); 815 phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 816 phi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 817 818 assertFalse(phi.subsumes(psi)); 819 820 // Example 821 // {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(c)} 822 psi = new Clause(); 823 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 824 psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 825 psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 826 psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)")); 827 psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 828 psi.addPositiveLiteral((Predicate) parser.parse("Q(C)")); 829 // {~p(i,j),~p(a,x)} 830 phi = new Clause(); 831 phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 832 phi.addNegativeLiteral((Predicate) parser.parse("P(A,x)")); 833 834 assertTrue(phi.subsumes(psi)); 835 836 // Example 837 // {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(a,b),q(c,d),q(e,f)} 838 psi = new Clause(); 839 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 840 psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 841 psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 842 psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)")); 843 psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 844 psi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)")); 845 psi.addPositiveLiteral((Predicate) parser.parse("Q(C,D)")); 846 psi.addPositiveLiteral((Predicate) parser.parse("Q(E,F)")); 847 // {~p(i,j),~p(a,b),q(e,f),q(a,b)} 848 phi = new Clause(); 849 phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 850 phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 851 phi.addPositiveLiteral((Predicate) parser.parse("Q(E,F)")); 852 phi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)")); 853 854 assertTrue(phi.subsumes(psi)); 855 856 // Non-Example 857 // {~p(a,b),~p(c,d),~p(e,f),~p(g,h),~p(i,j),q(a,b),q(c,d),q(e,f)} 858 psi = new Clause(); 859 psi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 860 psi.addNegativeLiteral((Predicate) parser.parse("P(C,D)")); 861 psi.addNegativeLiteral((Predicate) parser.parse("P(E,F)")); 862 psi.addNegativeLiteral((Predicate) parser.parse("P(G,H)")); 863 psi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 864 psi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)")); 865 psi.addPositiveLiteral((Predicate) parser.parse("Q(C,D)")); 866 psi.addPositiveLiteral((Predicate) parser.parse("Q(E,F)")); 867 // {~p(i,j),~p(a,b),q(e,f),q(a,b)} 868 phi = new Clause(); 869 phi.addNegativeLiteral((Predicate) parser.parse("P(I,J)")); 870 phi.addNegativeLiteral((Predicate) parser.parse("P(A,B)")); 871 phi.addPositiveLiteral((Predicate) parser.parse("Q(E,A)")); 872 phi.addPositiveLiteral((Predicate) parser.parse("Q(A,B)")); 873 874 assertFalse(phi.subsumes(psi)); 875 } 876 }