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    }