001 /* 002 * Created on Dec 8, 2004 003 * 004 */ 005 package aima.logic.propositional.algorithms; 006 007 import java.util.ArrayList; 008 import java.util.Collections; 009 import java.util.HashSet; 010 import java.util.Iterator; 011 import java.util.List; 012 import java.util.Set; 013 014 import aima.logic.propositional.parsing.PEParser; 015 import aima.logic.propositional.parsing.ast.BinarySentence; 016 import aima.logic.propositional.parsing.ast.Sentence; 017 import aima.logic.propositional.parsing.ast.Symbol; 018 import aima.logic.propositional.parsing.ast.SymbolComparator; 019 import aima.logic.propositional.parsing.ast.UnarySentence; 020 import aima.logic.propositional.visitors.CNFClauseGatherer; 021 import aima.logic.propositional.visitors.CNFTransformer; 022 import aima.logic.propositional.visitors.SymbolClassifier; 023 import aima.util.Converter; 024 import aima.util.LogicUtils; 025 import aima.util.SetOps; 026 027 /** 028 * @author Ravi Mohan 029 * 030 */ 031 032 public class PLResolution { 033 034 public boolean plResolution(KnowledgeBase kb, String alpha) { 035 return plResolution(kb, (Sentence) new PEParser().parse(alpha)); 036 } 037 038 public boolean plResolution(KnowledgeBase kb, Sentence alpha) { 039 Sentence kBAndNotAlpha = new BinarySentence("AND", kb.asSentence(), 040 new UnarySentence(alpha)); 041 Set<Sentence> clauses = new CNFClauseGatherer() 042 .getClausesFrom(new CNFTransformer().transform(kBAndNotAlpha)); 043 clauses = filterOutClausesWithTwoComplementaryLiterals(clauses); 044 Set<Sentence> newClauses = new HashSet<Sentence>(); 045 while (true) { 046 List<List<Sentence>> pairs = getCombinationPairs(new Converter<Sentence>() 047 .setToList(clauses)); 048 049 for (int i = 0; i < pairs.size(); i++) { 050 List<Sentence> pair = pairs.get(i); 051 // System.out.println("pair number" + i+" of "+pairs.size()); 052 Set<Sentence> resolvents = plResolve(pair.get(0), pair.get(1)); 053 resolvents = filterOutClausesWithTwoComplementaryLiterals(resolvents); 054 055 if (resolvents.contains(new Symbol("EMPTY_CLAUSE"))) { 056 return true; 057 } 058 newClauses = new SetOps<Sentence>().union(newClauses, 059 resolvents); 060 // System.out.println("clauseslist size = " +clauses.size()); 061 062 } 063 if (new SetOps<Sentence>().intersection(newClauses, clauses).size() == newClauses 064 .size()) {// subset test 065 return false; 066 } 067 clauses = new SetOps<Sentence>().union(newClauses, clauses); 068 clauses = filterOutClausesWithTwoComplementaryLiterals(clauses); 069 } 070 071 } 072 073 private Set<Sentence> filterOutClausesWithTwoComplementaryLiterals( 074 Set<Sentence> clauses) { 075 Set<Sentence> filtered = new HashSet<Sentence>(); 076 SymbolClassifier classifier = new SymbolClassifier(); 077 Iterator iter = clauses.iterator(); 078 while (iter.hasNext()) { 079 Sentence clause = (Sentence) iter.next(); 080 Set<Symbol> positiveSymbols = classifier 081 .getPositiveSymbolsIn(clause); 082 Set<Symbol> negativeSymbols = classifier 083 .getNegativeSymbolsIn(clause); 084 if ((new SetOps<Symbol>().intersection(positiveSymbols, 085 negativeSymbols).size() == 0)) { 086 filtered.add(clause); 087 } 088 } 089 return filtered; 090 } 091 092 public Set<Sentence> plResolve(Sentence clause1, Sentence clause2) { 093 Set<Sentence> resolvents = new HashSet<Sentence>(); 094 ClauseSymbols cs = new ClauseSymbols(clause1, clause2); 095 Iterator iter = cs.getComplementedSymbols().iterator(); 096 while (iter.hasNext()) { 097 Symbol symbol = (Symbol) iter.next(); 098 resolvents.add(createResolventClause(cs, symbol)); 099 } 100 101 return resolvents; 102 } 103 104 private Sentence createResolventClause(ClauseSymbols cs, Symbol toRemove) { 105 List<Symbol> positiveSymbols = new Converter<Symbol>() 106 .setToList(new SetOps<Symbol>().union( 107 cs.clause1PositiveSymbols, cs.clause2PositiveSymbols)); 108 List<Symbol> negativeSymbols = new Converter<Symbol>() 109 .setToList(new SetOps<Symbol>().union( 110 cs.clause1NegativeSymbols, cs.clause2NegativeSymbols)); 111 if (positiveSymbols.contains(toRemove)) { 112 positiveSymbols.remove(toRemove); 113 } 114 if (negativeSymbols.contains(toRemove)) { 115 negativeSymbols.remove(toRemove); 116 } 117 118 Collections.sort(positiveSymbols, new SymbolComparator()); 119 Collections.sort(negativeSymbols, new SymbolComparator()); 120 121 List<Sentence> sentences = new ArrayList<Sentence>(); 122 for (int i = 0; i < positiveSymbols.size(); i++) { 123 sentences.add(positiveSymbols.get(i)); 124 } 125 for (int i = 0; i < negativeSymbols.size(); i++) { 126 sentences.add(new UnarySentence(negativeSymbols.get(i))); 127 } 128 if (sentences.size() == 0) { 129 return new Symbol("EMPTY_CLAUSE"); // == empty clause 130 } else { 131 return LogicUtils.chainWith("OR", sentences); 132 } 133 134 } 135 136 private List<List<Sentence>> getCombinationPairs(List<Sentence> clausesList) { 137 int odd = clausesList.size() % 2; 138 int midpoint = 0; 139 if (odd == 1) { 140 midpoint = (clausesList.size() / 2) + 1; 141 } else { 142 midpoint = (clausesList.size() / 2); 143 } 144 145 List<List<Sentence>> pairs = new ArrayList<List<Sentence>>(); 146 for (int i = 0; i < clausesList.size(); i++) { 147 for (int j = i; j < clausesList.size(); j++) { 148 List<Sentence> pair = new ArrayList<Sentence>(); 149 Sentence first = clausesList.get(i); 150 Sentence second = clausesList.get(j); 151 152 if (!(first.equals(second))) { 153 pair.add(first); 154 pair.add(second); 155 pairs.add(pair); 156 } 157 } 158 } 159 return pairs; 160 } 161 162 class ClauseSymbols { 163 Set<Symbol> clause1Symbols, clause1PositiveSymbols, 164 clause1NegativeSymbols; 165 166 Set<Symbol> clause2Symbols, clause2PositiveSymbols, 167 clause2NegativeSymbols; 168 169 Set<Symbol> positiveInClause1NegativeInClause2, 170 negativeInClause1PositiveInClause2; 171 172 public ClauseSymbols(Sentence clause1, Sentence clause2) { 173 174 SymbolClassifier classifier = new SymbolClassifier(); 175 176 clause1Symbols = classifier.getSymbolsIn(clause1); 177 clause1PositiveSymbols = classifier.getPositiveSymbolsIn(clause1); 178 clause1NegativeSymbols = classifier.getNegativeSymbolsIn(clause1); 179 180 clause2Symbols = classifier.getSymbolsIn(clause2); 181 clause2PositiveSymbols = classifier.getPositiveSymbolsIn(clause2); 182 clause2NegativeSymbols = classifier.getNegativeSymbolsIn(clause2); 183 184 positiveInClause1NegativeInClause2 = new SetOps<Symbol>() 185 .intersection(clause1PositiveSymbols, 186 clause2NegativeSymbols); 187 negativeInClause1PositiveInClause2 = new SetOps<Symbol>() 188 .intersection(clause1NegativeSymbols, 189 clause2PositiveSymbols); 190 191 } 192 193 public Set getComplementedSymbols() { 194 return new SetOps<Symbol>().union( 195 positiveInClause1NegativeInClause2, 196 negativeInClause1PositiveInClause2); 197 } 198 199 } 200 201 public boolean plResolution(String kbs, String alphaString) { 202 KnowledgeBase kb = new KnowledgeBase(); 203 kb.tell(kbs); 204 Sentence alpha = (Sentence) new PEParser().parse(alphaString); 205 return plResolution(kb, alpha); 206 } 207 }