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.inference.proof.ProofStepClauseDemodulation; 009 import aima.logic.fol.kb.data.Clause; 010 import aima.logic.fol.kb.data.Literal; 011 import aima.logic.fol.parsing.ast.AtomicSentence; 012 import aima.logic.fol.parsing.ast.Term; 013 import aima.logic.fol.parsing.ast.TermEquality; 014 import aima.logic.fol.parsing.ast.Variable; 015 016 /** 017 * Artificial Intelligence A Modern Approach (2nd Edition): page 304.<br> 018 * Demodulation: For any terms x, y, z, where UNIFY(x,z) = theta and m<sub>n</sub>[z] is a 019 * literal containing z:<br> 020 * <pre> 021 * x=y, m1 OR ... OR m<sub>n</sub>[z] 022 * ---------------------------------- 023 * m1 OR ... m<sub>n</sub>[SUBST(theta,y)] 024 * </pre> 025 * Demodulation is typically used for simplifying expressions using collections of assertions 026 * such as x + 0 = x, x<sup>1</sup> = x, and so on.<br> 027 * <br> 028 * Some additional restrictions/clarifications highlighted in:<br> 029 * http://logic.stanford.edu/classes/cs157/2008/lectures/lecture15.pdf<br> 030 * 1. Unit Equations Only.<br> 031 * 2. Variables substituted in Equation Only.<br> 032 */ 033 034 /** 035 * @author Ciaran O'Reilly 036 * 037 */ 038 public class Demodulation extends AbstractModulation { 039 public Demodulation() { 040 } 041 042 public Clause apply(TermEquality assertion, Clause clExpression) { 043 Clause altClExpression = null; 044 045 for (Literal l1 : clExpression.getLiterals()) { 046 AtomicSentence altExpression = apply(assertion, l1 047 .getAtomicSentence()); 048 if (null != altExpression) { 049 // I have an alternative, create a new clause 050 // with the alternative and return 051 List<Literal> newLits = new ArrayList<Literal>(); 052 for (Literal l2 : clExpression.getLiterals()) { 053 if (l1.equals(l2)) { 054 newLits.add(l1.newInstance(altExpression)); 055 } else { 056 newLits.add(l2); 057 } 058 } 059 // Only apply demodulation at most once on 060 // each call. 061 altClExpression = new Clause(newLits); 062 altClExpression.setProofStep(new ProofStepClauseDemodulation( 063 altClExpression, clExpression, assertion)); 064 if (clExpression.isImmutable()) { 065 altClExpression.setImmutable(); 066 } 067 if (!clExpression.isStandardizedApartCheckRequired()) { 068 altClExpression.setStandardizedApartCheckNotRequired(); 069 } 070 break; 071 } 072 } 073 074 return altClExpression; 075 } 076 077 public AtomicSentence apply(TermEquality assertion, 078 AtomicSentence expression) { 079 AtomicSentence altExpression = null; 080 081 IdentifyCandidateMatchingTerm icm = getMatchingSubstitution(assertion 082 .getTerm1(), 083 expression); 084 085 if (null != icm) { 086 Term replaceWith = substVisitor.subst( 087 icm.getMatchingSubstitution(), assertion.getTerm2()); 088 // Want to ignore reflexivity axiom situation, i.e. x = x 089 if (!icm.getMatchingTerm().equals(replaceWith)) { 090 ReplaceMatchingTerm rmt = new ReplaceMatchingTerm(); 091 092 // Only apply demodulation at most once on each call. 093 altExpression = rmt.replace(expression, icm.getMatchingTerm(), 094 replaceWith); 095 } 096 } 097 098 return altExpression; 099 } 100 101 // 102 // PROTECTED METHODS 103 // 104 protected boolean isValidMatch(Term toMatch, 105 Set<Variable> toMatchVariables, Term possibleMatch, 106 Map<Variable, Term> substitution) { 107 // Demodulation only allows substitution in the equation only, 108 // if the substitution contains variables not in the toMatch 109 // side of the equation (i.e. left hand side), then 110 // it is not a legal demodulation match. 111 // Note: see: 112 // http://logic.stanford.edu/classes/cs157/2008/lectures/lecture15.pdf 113 // slide 23 for an example. 114 if (toMatchVariables.containsAll(substitution.keySet())) { 115 return true; 116 } 117 118 return false; 119 } 120 }