All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aima.core.logic.propositional.inference.PLResolution Maven / Gradle / Ivy

Go to download

AIMA-Java Core Algorithms from the book Artificial Intelligence a Modern Approach 3rd Ed.

The newest version!
package aima.core.logic.propositional.inference;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import aima.core.logic.propositional.kb.KnowledgeBase;
import aima.core.logic.propositional.kb.data.Clause;
import aima.core.logic.propositional.kb.data.Literal;
import aima.core.logic.propositional.parsing.ast.ComplexSentence;
import aima.core.logic.propositional.parsing.ast.Connective;
import aima.core.logic.propositional.parsing.ast.PropositionSymbol;
import aima.core.logic.propositional.parsing.ast.Sentence;
import aima.core.logic.propositional.visitors.ConvertToConjunctionOfClauses;
import aima.core.util.SetOps;

/**
 * Artificial Intelligence A Modern Approach (3rd Edition): page 255.
*
* *
 * 
 * function PL-RESOLUTION(KB, α) returns true or false
 *    inputs: KB, the knowledge base, a sentence in propositional logic
 *            α, the query, a sentence in propositional logic
 *            
 *    clauses ← the set of clauses in the CNF representation of KB ∧ ¬α
 *    new ← {}
 *    loop do
 *       for each pair of clauses Ci, Cj in clauses do
 *          resolvents ← PL-RESOLVE(Ci, Cj)
 *          if resolvents contains the empty clause then return true
 *          new ← new ∪ resolvents
 *       if new ⊆ clauses then return false
 *       clauses ← clauses ∪ new
 * 
 * 
* * Figure 7.12 A simple resolution algorithm for propositional logic. The * function PL-RESOLVE returns the set of all possible clauses obtained by * resolving its two inputs.
*
* Note: Optional optimization added to implementation whereby tautological * clauses can be removed during processing of the algorithm - see pg. 254 of * AIMA3e:
*
Inspection of Figure 7.13 reveals that many resolution steps are * pointless. For example, the clause B1,1 ∨ ¬B1,1 * ∨ P1,2 is equivalent to True ∨ P1,2 which * is equivalent to True. Deducing that True is true is not very * helpful. Therefore, any clauses in which two complementary literals appear * can be discarded.
* * @see Clause#isTautology() * * @author Ciaran O'Reilly * @author Ravi Mohan * @author Mike Stampone */ public class PLResolution { /** * PL-RESOLUTION(KB, α)
* A simple resolution algorithm for propositional logic. * * @param kb * the knowledge base, a sentence in propositional logic. * @param alpha * the query, a sentence in propositional logic. * @return true if KB |= α, false otherwise. */ public boolean plResolution(KnowledgeBase kb, Sentence alpha) { // clauses <- the set of clauses in the CNF representation // of KB & ~alpha Set clauses = setOfClausesInTheCNFRepresentationOfKBAndNotAlpha( kb, alpha); // new <- {} Set newClauses = new LinkedHashSet(); // loop do do { // for each pair of clauses C_i, C_j in clauses do List clausesAsList = new ArrayList(clauses); for (int i = 0; i < clausesAsList.size() - 1; i++) { Clause ci = clausesAsList.get(i); for (int j = i + 1; j < clausesAsList.size(); j++) { Clause cj = clausesAsList.get(j); // resolvents <- PL-RESOLVE(C_i, C_j) Set resolvents = plResolve(ci, cj); // if resolvents contains the empty clause then return true if (resolvents.contains(Clause.EMPTY)) { return true; } // new <- new U resolvents newClauses.addAll(resolvents); } } // if new is subset of clauses then return false if (clauses.containsAll(newClauses)) { return false; } // clauses <- clauses U new clauses.addAll(newClauses); } while (true); } /** * PL-RESOLVE(Ci, Cj)
* Calculate the set of all possible clauses by resolving its two inputs. * * @param ci * clause 1 * @param cj * clause 2 * @return the set of all possible clauses obtained by resolving its two * inputs. */ public Set plResolve(Clause ci, Clause cj) { Set resolvents = new LinkedHashSet(); // The complementary positive literals from C_i resolvePositiveWithNegative(ci, cj, resolvents); // The complementary negative literals from C_i resolvePositiveWithNegative(cj, ci, resolvents); return resolvents; } // // SUPPORTING CODE // private boolean discardTautologies = true; /** * Default constructor, which will set the algorithm to discard tautologies * by default. */ public PLResolution() { this(true); } /** * Constructor. * * @param discardTautologies * true if the algorithm is to discard tautological clauses * during processing, false otherwise. */ public PLResolution(boolean discardTautologies) { setDiscardTautologies(discardTautologies); } /** * @return true if the algorithm will discard tautological clauses during * processing. */ public boolean isDiscardTautologies() { return discardTautologies; } /** * Determine whether or not the algorithm should discard tautological * clauses during processing. * * @param discardTautologies */ public void setDiscardTautologies(boolean discardTautologies) { this.discardTautologies = discardTautologies; } // // PROTECTED // protected Set setOfClausesInTheCNFRepresentationOfKBAndNotAlpha( KnowledgeBase kb, Sentence alpha) { // KB & ~alpha; Sentence isContradiction = new ComplexSentence(Connective.AND, kb.asSentence(), new ComplexSentence(Connective.NOT, alpha)); // the set of clauses in the CNF representation Set clauses = new LinkedHashSet( ConvertToConjunctionOfClauses.convert(isContradiction) .getClauses()); discardTautologies(clauses); return clauses; } protected void resolvePositiveWithNegative(Clause c1, Clause c2, Set resolvents) { // Calculate the complementary positive literals from c1 with // the negative literals from c2 Set complementary = SetOps.intersection( c1.getPositiveSymbols(), c2.getNegativeSymbols()); // Construct a resolvent clause for each complement found for (PropositionSymbol complement : complementary) { List resolventLiterals = new ArrayList(); // Retrieve the literals from c1 that are not the complement for (Literal c1l : c1.getLiterals()) { if (c1l.isNegativeLiteral() || !c1l.getAtomicSentence().equals(complement)) { resolventLiterals.add(c1l); } } // Retrieve the literals from c2 that are not the complement for (Literal c2l : c2.getLiterals()) { if (c2l.isPositiveLiteral() || !c2l.getAtomicSentence().equals(complement)) { resolventLiterals.add(c2l); } } // Construct the resolvent clause Clause resolvent = new Clause(resolventLiterals); // Discard tautological clauses if this optimization is turned on. if (!(isDiscardTautologies() && resolvent.isTautology())) { resolvents.add(resolvent); } } } // Utility routine for removing the tautological clauses from a set (in // place). protected void discardTautologies(Set clauses) { if (isDiscardTautologies()) { Set toDiscard = new HashSet(); for (Clause c : clauses) { if (c.isTautology()) { toDiscard.add(c); } } clauses.removeAll(toDiscard); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy