001    package aima.logic.fol.inference;
002    
003    import java.util.ArrayList;
004    import java.util.LinkedHashSet;
005    import java.util.List;
006    import java.util.Map;
007    import java.util.Set;
008    
009    import aima.logic.fol.StandardizeApart;
010    import aima.logic.fol.StandardizeApartIndexical;
011    import aima.logic.fol.StandardizeApartIndexicalFactory;
012    import aima.logic.fol.inference.proof.ProofStepClauseParamodulation;
013    import aima.logic.fol.kb.data.Clause;
014    import aima.logic.fol.kb.data.Literal;
015    import aima.logic.fol.parsing.ast.AtomicSentence;
016    import aima.logic.fol.parsing.ast.Term;
017    import aima.logic.fol.parsing.ast.TermEquality;
018    import aima.logic.fol.parsing.ast.Variable;
019    
020    /**
021     * Artificial Intelligence A Modern Approach (2nd Edition): page 304.<br>
022     * Paramodulation: For any terms x, y, z, where UNIFY(x,z) = theta,<br>
023     * <pre>
024     *     l1 OR ... l<sub>k</sub> OR x=y,     m1 OR ... OR m<sub>n</sub>[z]
025     *     -----------------------------------------------------------------
026     *     SUBST(theta, l1 OR ... l<sub>k</sub> OR m1 OR ... OR m<sub>n</sub>[y])
027     * </pre>
028     * Unlike demodulation, paramodulation yields a complete inference procedure for first-order
029     * logic with equality.
030     */
031    
032    /**
033     * @author Ciaran O'Reilly
034     * 
035     */
036    public class Paramodulation extends AbstractModulation {
037            private static StandardizeApartIndexical _saIndexical = StandardizeApartIndexicalFactory
038                            .newStandardizeApartIndexical('p');
039            private static List<Literal> _emptyLiteralList = new ArrayList<Literal>();
040            //
041            private StandardizeApart sApart = new StandardizeApart();
042    
043            public Paramodulation() {
044            }
045    
046            public Set<Clause> apply(Clause c1, Clause c2) {
047                    return apply(c1, c2, false);
048            }
049    
050            public Set<Clause> apply(Clause c1, Clause c2, boolean standardizeApart) {
051                    Set<Clause> paraExpressions = new LinkedHashSet<Clause>();
052    
053                    for (int i = 0; i < 2; i++) {
054                            Clause topClause, equalityClause;
055                            if (i == 0) {
056                                    topClause = c1;
057                                    equalityClause = c2;
058                            } else {
059                                    topClause = c2;
060                                    equalityClause = c1;
061                            }
062    
063                            for (Literal possEqLit : equalityClause.getLiterals()) {
064                                    // Must be a positive term equality to be used
065                                    // for paramodulation.
066                                    if (possEqLit.isPositiveLiteral()
067                                                    && possEqLit.getAtomicSentence() instanceof TermEquality) {
068                                            TermEquality assertion = (TermEquality) possEqLit
069                                                            .getAtomicSentence();
070    
071                                            // Test matching for both sides of the equality
072                                            for (int x = 0; x < 2; x++) {
073                                                    Term toMatch, toReplaceWith;
074                                                    if (x == 0) {
075                                                            toMatch = assertion.getTerm1();
076                                                            toReplaceWith = assertion.getTerm2();
077                                                    } else {
078                                                            toMatch = assertion.getTerm2();
079                                                            toReplaceWith = assertion.getTerm1();
080                                                    }
081    
082                                                    for (Literal l1 : topClause.getLiterals()) {
083                                                            IdentifyCandidateMatchingTerm icm = getMatchingSubstitution(
084                                                                            toMatch, l1.getAtomicSentence());
085    
086                                                            if (null != icm) {
087                                                                    Term replaceWith = substVisitor.subst(icm
088                                                                                    .getMatchingSubstitution(),
089                                                                                    toReplaceWith);
090    
091                                                                    // Want to ignore reflexivity axiom situation,
092                                                                    // i.e. x = x
093                                                                    if (icm.getMatchingTerm().equals(replaceWith)) {
094                                                                            continue;
095                                                                    }
096    
097                                                                    ReplaceMatchingTerm rmt = new ReplaceMatchingTerm();
098    
099                                                                    AtomicSentence altExpression = rmt.replace(l1
100                                                                                    .getAtomicSentence(), icm
101                                                                                    .getMatchingTerm(), replaceWith);
102    
103                                                                    // I have an alternative, create a new clause
104                                                                    // with the alternative and the substitution
105                                                                    // applied to all the literals before returning
106                                                                    List<Literal> newLits = new ArrayList<Literal>();
107                                                                    for (Literal l2 : topClause.getLiterals()) {
108                                                                            if (l1.equals(l2)) {
109                                                                                    newLits
110                                                                                                    .add(l1
111                                                                                                                    .newInstance((AtomicSentence) substVisitor
112                                                                                                                                    .subst(
113                                                                                                                                                    icm
114                                                                                                                                                                    .getMatchingSubstitution(),
115                                                                                                                                                    altExpression)));
116                                                                            } else {
117                                                                                    newLits
118                                                                                                    .add(substVisitor
119                                                                                                                    .subst(
120                                                                                                                                    icm
121                                                                                                                                                    .getMatchingSubstitution(),
122                                                                                                                                    l2));
123                                                                            }
124                                                                    }
125                                                                    // Assign the equality clause literals,
126                                                                    // excluding
127                                                                    // the term equality used.
128                                                                    for (Literal l2 : equalityClause.getLiterals()) {
129                                                                            if (possEqLit.equals(l2)) {
130                                                                                    continue;
131                                                                            }
132                                                                            newLits.add(substVisitor.subst(icm
133                                                                                            .getMatchingSubstitution(), l2));
134                                                                    }
135    
136                                                                    // Only apply paramodulation at most once
137                                                                    // for each term equality.
138                                                                    Clause nc = null;
139                                                                    if (standardizeApart) {
140                                                                            sApart.standardizeApart(newLits,
141                                                                                            _emptyLiteralList, _saIndexical);
142                                                                            nc = new Clause(newLits);
143                                                                                                                                            
144                                                                    } else {
145                                                                            nc = new Clause(newLits);
146                                                                    }
147                                                                    nc
148                                                                                    .setProofStep(new ProofStepClauseParamodulation(
149                                                                                                    nc, topClause, equalityClause,
150                                                                                                    assertion));
151                                                                    if (c1.isImmutable()) {
152                                                                            nc.setImmutable();
153                                                                    }
154                                                                    if (!c1.isStandardizedApartCheckRequired()) {
155                                                                            c1.setStandardizedApartCheckNotRequired();
156                                                                    }
157                                                                    paraExpressions.add(nc);
158                                                                    break;
159                                                            }
160                                                    }
161                                            }
162                                    }
163                            }
164                    }
165    
166                    return paraExpressions;
167            }
168    
169            //
170            // PROTECTED METHODS
171            //
172            protected boolean isValidMatch(Term toMatch,
173                            Set<Variable> toMatchVariables, Term possibleMatch,
174                            Map<Variable, Term> substitution) {
175    
176                    if (possibleMatch != null && substitution != null) {
177                            // Note:
178                            // [Brand 1975] showed that paramodulation into
179                            // variables is unnecessary.
180                            if (!(possibleMatch instanceof Variable)) {
181                                    // TODO: Find out whether the following statement from:
182                                    // http://www.cs.miami.edu/~geoff/Courses/CSC648-07F/Content/Paramodulation.shtml
183                                    // is actually the case, as it was not positive but
184                                    // intuitively makes sense:
185                                    // "Similarly, depending on how paramodulation is used, it is
186                                    // often unnecessary to paramodulate from variables."
187                                    // if (!(toMatch instanceof Variable)) {
188                                    return true;
189                                    // }
190                            }
191                    }
192                    return false;
193            }
194    }