001    package aima.logic.fol.inference;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    import java.util.Map;
006    import java.util.Set;
007    
008    import aima.logic.fol.SubstVisitor;
009    import aima.logic.fol.Unifier;
010    import aima.logic.fol.VariableCollector;
011    import aima.logic.fol.parsing.FOLVisitor;
012    import aima.logic.fol.parsing.ast.AtomicSentence;
013    import aima.logic.fol.parsing.ast.ConnectedSentence;
014    import aima.logic.fol.parsing.ast.Constant;
015    import aima.logic.fol.parsing.ast.Function;
016    import aima.logic.fol.parsing.ast.NotSentence;
017    import aima.logic.fol.parsing.ast.Predicate;
018    import aima.logic.fol.parsing.ast.QuantifiedSentence;
019    import aima.logic.fol.parsing.ast.Term;
020    import aima.logic.fol.parsing.ast.TermEquality;
021    import aima.logic.fol.parsing.ast.Variable;
022    
023    /**
024     * Abstract base class for Demodulation and Paramodulation algorithms. 
025     */
026    
027    /**
028     * @author Ciaran O'Reilly
029     * 
030     */
031    public abstract class AbstractModulation {
032            //
033            // PROTECTED ATTRIBUTES
034            protected VariableCollector variableCollector = new VariableCollector();
035            protected Unifier unifier = new Unifier();
036            protected SubstVisitor substVisitor = new SubstVisitor();
037            
038            //
039            // PROTECTED METODS
040            //
041            protected abstract boolean isValidMatch(Term toMatch,
042                            Set<Variable> toMatchVariables, Term possibleMatch,
043                            Map<Variable, Term> substitution);
044            
045            protected IdentifyCandidateMatchingTerm getMatchingSubstitution(
046                            Term toMatch, AtomicSentence expression) {
047    
048                    IdentifyCandidateMatchingTerm icm = new IdentifyCandidateMatchingTerm(
049                                    toMatch, expression);
050    
051                    if (icm.isMatch()) {
052                            return icm;
053                    }
054    
055                    // indicates no match
056                    return null;
057            }
058    
059            protected class IdentifyCandidateMatchingTerm implements FOLVisitor {
060                    private Term toMatch = null;
061                    private Set<Variable> toMatchVariables = null;
062                    private Term matchingTerm = null;
063                    private Map<Variable, Term> substitution = null;
064    
065                    public IdentifyCandidateMatchingTerm(Term toMatch,
066                                    AtomicSentence expression) {
067                            this.toMatch = toMatch;
068                            this.toMatchVariables = variableCollector
069                                            .collectAllVariables(toMatch);
070    
071                            expression.accept(this, null);
072                    }
073    
074                    public boolean isMatch() {
075                            return null != matchingTerm;
076                    }
077    
078                    public Term getMatchingTerm() {
079                            return matchingTerm;
080                    }
081    
082                    public Map<Variable, Term> getMatchingSubstitution() {
083                            return substitution;
084                    }
085    
086                    //
087                    // START-FOLVisitor
088                    public Object visitPredicate(Predicate p, Object arg) {
089                            for (Term t : p.getArgs()) {
090                                    // Finish processing if have found a match
091                                    if (null != matchingTerm) {
092                                            break;
093                                    }
094                                    t.accept(this, null);
095                            }
096                            return p;
097                    }
098    
099                    public Object visitTermEquality(TermEquality equality, Object arg) {
100                            for (Term t : equality.getArgs()) {
101                                    // Finish processing if have found a match
102                                    if (null != matchingTerm) {
103                                            break;
104                                    }
105                                    t.accept(this, null);
106                            }
107                            return equality;
108                    }
109    
110                    public Object visitVariable(Variable variable, Object arg) {
111    
112                            if (null != (substitution = unifier.unify(toMatch, variable))) {
113                                    if (isValidMatch(toMatch, toMatchVariables, variable,
114                                                    substitution)) {
115                                            matchingTerm = variable;
116                                    }
117                            }
118    
119                            return variable;
120                    }
121    
122                    public Object visitConstant(Constant constant, Object arg) {
123                            if (null != (substitution = unifier.unify(toMatch, constant))) {
124                                    if (isValidMatch(toMatch, toMatchVariables, constant,
125                                                    substitution)) {
126                                            matchingTerm = constant;
127                                    }
128                            }
129    
130                            return constant;
131                    }
132    
133                    public Object visitFunction(Function function, Object arg) {
134                            if (null != (substitution = unifier.unify(toMatch, function))) {
135                                    if (isValidMatch(toMatch, toMatchVariables, function,
136                                                    substitution)) {
137                                            matchingTerm = function;
138                                    }
139                            }
140    
141                            if (null == matchingTerm) {
142                                    // Try the Function's arguments
143                                    for (Term t : function.getArgs()) {
144                                            // Finish processing if have found a match
145                                            if (null != matchingTerm) {
146                                                    break;
147                                            }
148                                            t.accept(this, null);
149                                    }
150                            }
151    
152                            return function;
153                    }
154    
155                    public Object visitNotSentence(NotSentence sentence, Object arg) {
156                            throw new IllegalStateException(
157                                            "visitNotSentence() should not be called.");
158                    }
159    
160                    public Object visitConnectedSentence(ConnectedSentence sentence,
161                                    Object arg) {
162                            throw new IllegalStateException(
163                                            "visitConnectedSentence() should not be called.");
164                    }
165    
166                    public Object visitQuantifiedSentence(QuantifiedSentence sentence,
167                                    Object arg) {
168                            throw new IllegalStateException(
169                                            "visitQuantifiedSentence() should not be called.");
170                    }
171    
172                    // END-FOLVisitor
173                    //
174            }
175    
176            protected class ReplaceMatchingTerm implements FOLVisitor {
177                    private Term toReplace = null;
178                    private Term replaceWith = null;
179                    private boolean replaced = false;
180    
181                    public ReplaceMatchingTerm() {
182                    }
183    
184                    public AtomicSentence replace(AtomicSentence expression,
185                                    Term toReplace, Term replaceWith) {
186                            this.toReplace = toReplace;
187                            this.replaceWith = replaceWith;
188    
189                            return (AtomicSentence) expression.accept(this, null);
190                    }
191    
192                    //
193                    // START-FOLVisitor
194                    public Object visitPredicate(Predicate p, Object arg) {
195                            List<Term> newTerms = new ArrayList<Term>();
196                            for (Term t : p.getTerms()) {
197                                    Term subsTerm = (Term) t.accept(this, arg);
198                                    newTerms.add(subsTerm);
199                            }
200                            return new Predicate(p.getPredicateName(), newTerms);
201                    }
202    
203                    public Object visitTermEquality(TermEquality equality, Object arg) {
204                            Term newTerm1 = (Term) equality.getTerm1().accept(this, arg);
205                            Term newTerm2 = (Term) equality.getTerm2().accept(this, arg);
206                            return new TermEquality(newTerm1, newTerm2);
207                    }
208    
209                    public Object visitVariable(Variable variable, Object arg) {
210                            if (!replaced) {
211                                    if (toReplace.equals(variable)) {
212                                            replaced = true;
213                                            return replaceWith;
214                                    }
215                            }
216                            return variable;
217                    }
218    
219                    public Object visitConstant(Constant constant, Object arg) {
220                            if (!replaced) {
221                                    if (toReplace.equals(constant)) {
222                                            replaced = true;
223                                            return replaceWith;
224                                    }
225                            }
226                            return constant;
227                    }
228    
229                    public Object visitFunction(Function function, Object arg) {
230                            if (!replaced) {
231                                    if (toReplace.equals(function)) {
232                                            replaced = true;
233                                            return replaceWith;
234                                    }
235                            }
236    
237                            List<Term> newTerms = new ArrayList<Term>();
238                            for (Term t : function.getTerms()) {
239                                    Term subsTerm = (Term) t.accept(this, arg);
240                                    newTerms.add(subsTerm);
241                            }
242                            return new Function(function.getFunctionName(), newTerms);
243                    }
244    
245                    public Object visitNotSentence(NotSentence sentence, Object arg) {
246                            throw new IllegalStateException(
247                                            "visitNotSentence() should not be called.");
248                    }
249    
250                    public Object visitConnectedSentence(ConnectedSentence sentence,
251                                    Object arg) {
252                            throw new IllegalStateException(
253                                            "visitConnectedSentence() should not be called.");
254                    }
255    
256                    public Object visitQuantifiedSentence(QuantifiedSentence sentence,
257                                    Object arg) {
258                            throw new IllegalStateException(
259                                            "visitQuantifiedSentence() should not be called.");
260                    }
261    
262                    // END-FOLVisitor
263                    //
264            }
265    }