package de.tu_dresden.inf.ggp06_2.resolver; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; /** * This class is a special HashMap implementation that contains the relation * between a variable and a term commonly known as a substitution.<br> * <br> * Definition: { v_1/t_1, v_2/t_2, ..., v_m/t_m },<br> * t_i - Expression,<br> * v_i - Variable<br> * <br> * In this HashMap the key is v_i and the value is t_i.<br> * <br> * Following method should be used:<br> * <ul> * <li> * containsKey() to check if substitution contains a variable mapping * </li> * <li> * get() to get a expression for a variable * </li> * <li> * isUnificator() to check if a substitution is a unificator * </li> * </ul> * * @author Ingo Keller - General Game Playing course student at TUD * @author Arsen Kostenko - General Game Playing course student at TUD * */ public class Substitution extends HashMap<Variable, Expression> { private static final long serialVersionUID = 8066780545882482804L; /* Stores the logger for this class */ public static Logger logger = Logger.getLogger(Substitution.class); /** * Constructs a new empty substitution object. */ public Substitution () { super(); } /** * Constructs a new subtitution object based on the copy substitution. * @param copy Substitution */ public Substitution ( Substitution copy ) { super(); this.putAll( copy ); } /** * This method adds a association if the variable has not already one. * * Does not add a already known association or a identity association. * @param var * @param replacement * @return Returns true if the association was added; otherwise false. */ public void addAssociation(Variable var, Expression replacement) { // TODO: Check if we could remove this check if ( containsKey(var) || var.equals(replacement) ) return; put( var, replacement ); } public Substitution apply(Substitution substitution) { Substitution sigma = new Substitution(); Substitution psi = substitution.factor(); // iterate over every entry of this substitution for ( Map.Entry<Variable, Expression> entry : this.entrySet() ) sigma.addAssociation( entry.getKey(), entry.getValue().apply(psi) ); // iterate over every entry of the other substitution for ( Map.Entry<Variable, Expression> entry : substitution.entrySet() ) sigma.addAssociation( entry.getKey(), entry.getValue().apply(psi) ); return sigma; } /** * Apply the substitution to itself repeatedly until every mapping maps out * of the domain of the substitution. * * @return */ public Substitution factor() { Substitution psi = new Substitution(); // iterate over every entry for ( Map.Entry<Variable, Expression> entry : this.entrySet() ) { Variable var = entry.getKey(); Expression mapNew = entry.getKey(); Expression mapOld = entry.getKey(); while (true) { mapNew = mapOld.apply(this); if ( mapNew == null ) { mapNew = mapOld; break; } else if ( mapNew.equals( mapOld ) ) { break; } else mapOld = mapNew; } psi.addAssociation( var, mapNew ); } return psi; } public Substitution canonize(Substitution canon) { Substitution canonical = new Substitution(); for(Map.Entry<Variable, Expression> association : this.entrySet()){ Variable canonicalKey = (Variable) canon.get( association.getKey() ); Expression value = association.getValue(); Expression canonicalValue = value.apply( canon ); canonical.put(canonicalKey, canonicalValue); } return canonical; } /** * This method returns a subset of the substitution that contains only the * variables occuring in the given expression. * * TODO: Check if the factor calling can be removed in favor of keeping the * results from factor within this object. * @param expression * @return */ public Substitution restrict(Expression expression) { Substitution sigma = new Substitution(); Substitution psi = this.factor(); // iterate over all variables gotten from expression for ( Variable var : expression.getVariables() ){ if (psi.containsKey( var )){ Expression expression2 = psi.get(var); sigma.addAssociation( var, expression2 ); } } return sigma; } /** * This method tests if the substitution object is a unificator for a list * of expressions. * * Definition: A substitution is a unificator if * L_1 sigma = L_2 sigma = ... = L_m sigma is true, where * L_n - Expression, * sigma - Substitution * * @param expressions * @return */ public boolean isUnificator ( ExpressionList expressions ) { // only check if we have something to check if ( expressions == null || expressions.size() == 0 ) return false; // every substitution is a unificator if we have only one expression if ( expressions.size() == 1 ) return true; // initialising with first expression Expression tmpExp = expressions.get(0).apply(this); // if we have a difference in at least one expression it means that // there is no unificator for ( Expression exp: expressions ) if ( !( tmpExp.equals( exp.apply(this) ) ) ) return false; return true; } /** * Returns a string representation of the substitution. */ @Override public String toString() { StringBuilder sb = new StringBuilder("[ "); for ( Map.Entry<Variable, Expression> entry : this.entrySet() ) sb.append("{").append( entry.getKey()).append( "->" ).append( entry.getValue() ).append( "}, "); sb.append( " ]" ); return sb.toString(); } }