001    package aima.logic.fol;
002    
003    import java.util.ArrayList;
004    import java.util.HashMap;
005    import java.util.HashSet;
006    import java.util.List;
007    import java.util.Map;
008    import java.util.Set;
009    
010    import aima.logic.fol.kb.data.Clause;
011    
012    /**
013     * Note: From slide 17.  
014     * http://logic.stanford.edu/classes/cs157/2008/lectures/lecture12.pdf
015     * 
016     * Relational Subsumption
017     * 
018     * A relational clause Phi subsumes Psi is and only if there
019     * is a substitution delta that, when applied to Phi, produces a
020     * clause Phidelta that is a subset of Psi.
021     */
022    
023    /**
024     * @author Ciaran O'Reilly
025     * 
026     */
027    public class SubsumptionElimination {
028            public static Set<Clause> findSubsumedClauses(Set<Clause> clauses) {
029                    Set<Clause> subsumed = new HashSet<Clause>();
030    
031                    // Group the clauses by their # of literals.
032                    // Keep track of the min and max # of literals.
033                    int min = Integer.MAX_VALUE;
034                    int max = 0;
035                    Map<Integer, Set<Clause>> clausesGroupedBySize = new HashMap<Integer, Set<Clause>>();
036                    for (Clause c : clauses) {
037                            int size = c.getNumberLiterals();
038                            if (size < min) {
039                                    min = size;
040                            }
041                            if (size > max) {
042                                    max = size;
043                            }
044                            Set<Clause> cforsize = clausesGroupedBySize.get(size);
045                            if (null == cforsize) {
046                                    cforsize = new HashSet<Clause>();
047                                    clausesGroupedBySize.put(size, cforsize);
048                            }
049                            cforsize.add(c);
050                    }
051                    // Check if each smaller clause
052                    // subsumes any of the larger clauses.
053                    for (int i = min; i < max; i++) {
054                            Set<Clause> scs = clausesGroupedBySize.get(i);
055                            // Ensure there are clauses with this # of literals
056                            if (null != scs) {
057                                    for (int j = i + 1; j <= max; j++) {
058                                            Set<Clause> lcs = clausesGroupedBySize.get(j);
059                                            // Ensure there are clauses with this # of literals
060                                            if (null != lcs) {
061                                                    for (Clause sc : scs) {
062                                                            // Don't bother checking clauses
063                                                            // that are already subsumed.
064                                                            if (!subsumed.contains(sc)) {
065                                                                    for (Clause lc : lcs) {
066                                                                            if (!subsumed.contains(lc)) {
067                                                                                    if (sc.subsumes(lc)) {
068                                                                                            subsumed.add(lc);
069                                                                                    }
070                                                                            }
071                                                                    }
072                                                            }
073                                                    }
074                                            }
075                                    }
076                            }
077                    }
078    
079                    return subsumed;
080            }
081    }