package aima.test.core.unit.logic.propositional.inference;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import aima.core.logic.propositional.inference.PLResolution;
import aima.core.logic.propositional.kb.KnowledgeBase;
import aima.core.logic.propositional.kb.data.Clause;
import aima.core.logic.propositional.parsing.PLParser;
import aima.core.logic.propositional.parsing.ast.Sentence;
import aima.core.logic.propositional.visitors.ConvertToConjunctionOfClauses;
import aima.core.util.SetOps;
/**
* @author Ravi Mohan
* @author Ciaran O'Reilly
*
*/
@RunWith(Parameterized.class)
public class PLResolutionTest {
private PLResolution resolution;
private PLParser parser;
@Parameters(name = "{index}: discardTautologies={0}")
public static Collection<Object[]> inferenceAlgorithmSettings() {
return Arrays.asList(new Object[][] {
{false}, // will not discard tautological clauses - slower!
{true} // will discard tautological clauses - faster!
});
}
public PLResolutionTest(boolean discardTautologies) {
this.resolution = new PLResolution(discardTautologies);
parser = new PLParser();
}
@Test
public void testPLResolveWithOneLiteralMatching() {
Clause one = ConvertToConjunctionOfClauses
.convert(parser.parse("A | B")).getClauses().iterator().next();
Clause two = ConvertToConjunctionOfClauses
.convert(parser.parse("~B | C")).getClauses().iterator().next();
Clause expected = ConvertToConjunctionOfClauses
.convert(parser.parse("A | C")).getClauses().iterator().next();
Set<Clause> resolvents = resolution.plResolve(one, two);
Assert.assertEquals(1, resolvents.size());
Assert.assertTrue(resolvents.contains(expected));
}
@Test
public void testPLResolveWithNoLiteralMatching() {
Clause one = ConvertToConjunctionOfClauses
.convert(parser.parse("A | B")).getClauses().iterator().next();
Clause two = ConvertToConjunctionOfClauses
.convert(parser.parse("C | D")).getClauses().iterator().next();
Set<Clause> resolvents = resolution.plResolve(one, two);
Assert.assertEquals(0, resolvents.size());
}
@Test
public void testPLResolveWithOneLiteralSentencesMatching() {
Clause one = ConvertToConjunctionOfClauses.convert(parser.parse("A"))
.getClauses().iterator().next();
Clause two = ConvertToConjunctionOfClauses.convert(parser.parse("~A"))
.getClauses().iterator().next();
Set<Clause> resolvents = resolution.plResolve(one, two);
Assert.assertEquals(1, resolvents.size());
Assert.assertTrue(resolvents.iterator().next().isEmpty());
Assert.assertTrue(resolvents.iterator().next().isFalse());
}
@Test
public void testPLResolveWithTwoLiteralsMatching() {
Clause one = ConvertToConjunctionOfClauses
.convert(parser.parse("~P21 | B11")).getClauses().iterator()
.next();
Clause two = ConvertToConjunctionOfClauses
.convert(parser.parse("~B11 | P21 | P12")).getClauses()
.iterator().next();
Set<Clause> expected = ConvertToConjunctionOfClauses.convert(
parser.parse("(P12 | P21 | ~P21) & (B11 | P12 | ~B11)"))
.getClauses();
Set<Clause> resolvents = resolution.plResolve(one, two);
int numberExpectedResolvents = 2;
if (resolution.isDiscardTautologies()) {
numberExpectedResolvents = 0; // due to being tautologies
}
Assert.assertEquals(numberExpectedResolvents, resolvents.size());
Assert.assertEquals(numberExpectedResolvents, SetOps.intersection(expected, resolvents).size());
}
@Test
public void testPLResolve1() {
KnowledgeBase kb = new KnowledgeBase();
kb.tell("(B11 => ~P11) & B11");
Sentence alpha = parser.parse("P11");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(false, b);
}
@Test
public void testPLResolve2() {
KnowledgeBase kb = new KnowledgeBase();
kb.tell("A & B");
Sentence alpha = parser.parse("B");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(true, b);
}
@Test
public void testPLResolve3() {
KnowledgeBase kb = new KnowledgeBase();
kb.tell("(B11 => ~P11) & B11");
Sentence alpha = parser.parse("~P11");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(true, b);
}
@Test
public void testPLResolve4() {
KnowledgeBase kb = new KnowledgeBase();
kb.tell("A | B");
Sentence alpha = parser.parse("B");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(false, b);
}
@Test
public void testPLResolve5() {
KnowledgeBase kb = new KnowledgeBase();
kb.tell("(B11 => ~P11) & B11");
Sentence alpha = parser.parse("~B11");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(false, b);
}
@Test
public void testPLResolve6() {
KnowledgeBase kb = new KnowledgeBase();
// e.g. from AIMA3e pg. 254
kb.tell("(B11 <=> P12 | P21) & ~B11");
Sentence alpha = parser.parse("~P21");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(true, b);
}
@Test
public void testMultipleClauseResolution() {
// test (and fix) suggested by Huy Dinh. Thanks Huy!
KnowledgeBase kb = new KnowledgeBase();
kb.tell("(B11 <=> P12 | P21) & ~B11");
Sentence alpha = parser.parse("B");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(false, b); // false as KB says nothing about B
}
@Test
public void testPLResolutionWithChadCarfBugReportData() {
KnowledgeBase kb = new KnowledgeBase();
kb.tell("B12 <=> P11 | P13 | P22 | P02");
kb.tell("B21 <=> P20 | P22 | P31 | P11");
kb.tell("B01 <=> P00 | P02 | P11");
kb.tell("B10 <=> P11 | P20 | P00");
kb.tell("~B21");
kb.tell("~B12");
kb.tell("B10");
kb.tell("B01");
Sentence alpha = parser.parse("P00");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(true, b);
}
@Test
public void testPLResolutionSucceedsWithChadCarffsBugReport2() {
KnowledgeBase kb = new KnowledgeBase();
kb.tell("B10 <=> P11 | P20 | P00");
kb.tell("B01 <=> P00 | P02 | P11");
kb.tell("B21 <=> P20 | P22 | P31 | P11");
kb.tell("B12 <=> P11 | P13 | P22 | P02");
kb.tell("~B21");
kb.tell("~B12");
kb.tell("B10");
kb.tell("B01");
Sentence alpha = parser.parse("P00");
boolean b = resolution.plResolution(kb, alpha);
Assert.assertEquals(true, b);
}
}