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    }