package aima.core.logic.fol; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import aima.core.logic.fol.kb.data.Clause; /** * Artificial Intelligence A Modern Approach (3rd Edition): page 356.<br> * <br> * The subsumption method eliminates all sentences that are subsumed by (that * is, more specific than) an existing sentence in the KB. For example, P(x) is * in the KB, then there is no sense in adding P(A) and even less sense in * adding P(A) V Q(B). Subsumption helps keep the KB small and thus helps keep * the search space small.<br> * <br> * <b>Note:</b> <a * href="http://logic.stanford.edu/classes/cs157/2008/lectures/lecture12.pdf" * >From slide 17.</a> <br> * <br> * Relational Subsumption<br> * <br> * A relational clause Φ subsumes Ψ if and only if there is a * substitution δ that, when applied to Φ, produces a clause Φ' * that is a subset of Ψ. * * @author Ciaran O'Reilly * @author Mike Stampone */ public class SubsumptionElimination { /** * Returns the clauses that are subsumed by (that is, more specific than) an * existing clause in the specified set of clauses. * * @param clauses * a set of clauses in first order logic * * @return the clauses that are subsumed by (that is, more specific than) an * existing clause in the specified set of clauses. */ public static Set<Clause> findSubsumedClauses(Set<Clause> clauses) { Set<Clause> subsumed = new HashSet<Clause>(); // Group the clauses by their # of literals. // Keep track of the min and max # of literals. int min = Integer.MAX_VALUE; int max = 0; Map<Integer, Set<Clause>> clausesGroupedBySize = new HashMap<Integer, Set<Clause>>(); for (Clause c : clauses) { int size = c.getNumberLiterals(); if (size < min) { min = size; } if (size > max) { max = size; } Set<Clause> cforsize = clausesGroupedBySize.get(size); if (null == cforsize) { cforsize = new HashSet<Clause>(); clausesGroupedBySize.put(size, cforsize); } cforsize.add(c); } // Check if each smaller clause // subsumes any of the larger clauses. for (int i = min; i < max; i++) { Set<Clause> scs = clausesGroupedBySize.get(i); // Ensure there are clauses with this # of literals if (null != scs) { for (int j = i + 1; j <= max; j++) { Set<Clause> lcs = clausesGroupedBySize.get(j); // Ensure there are clauses with this # of literals if (null != lcs) { for (Clause sc : scs) { // Don't bother checking clauses // that are already subsumed. if (!subsumed.contains(sc)) { for (Clause lc : lcs) { if (!subsumed.contains(lc)) { if (sc.subsumes(lc)) { subsumed.add(lc); } } } } } } } } } return subsumed; } }