Package aima.core.logic.fol

Source Code of aima.core.logic.fol.Unifier

package aima.core.logic.fol;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import aima.core.logic.fol.parsing.ast.FOLNode;
import aima.core.logic.fol.parsing.ast.Function;
import aima.core.logic.fol.parsing.ast.Term;
import aima.core.logic.fol.parsing.ast.Variable;

/**
* Artificial Intelligence A Modern Approach (3rd Edition): Figure 9.1, page
* 328.<br>
* <br>
*
* <pre>
* function UNIFY(x, y, theta) returns a substitution to make x and y identical
*   inputs: x, a variable, constant, list, or compound
*           y, a variable, constant, list, or compound
*           theta, the substitution built up so far (optional, defaults to empty)
*          
*   if theta = failure then return failure
*   else if x = y the return theta
*   else if VARIABLE?(x) then return UNIVY-VAR(x, y, theta)
*   else if VARIABLE?(y) then return UNIFY-VAR(y, x, theta)
*   else if COMPOUND?(x) and COMPOUND?(y) then
*       return UNIFY(x.ARGS, y.ARGS, UNIFY(x.OP, y.OP, theta))
*   else if LIST?(x) and LIST?(y) then
*       return UNIFY(x.REST, y.REST, UNIFY(x.FIRST, y.FIRST, theta))
*   else return failure
*  
* ---------------------------------------------------------------------------------------------------
*
* function UNIFY-VAR(var, x, theta) returns a substitution
*           
*   if {var/val} E theta then return UNIFY(val, x, theta)
*   else if {x/val} E theta then return UNIFY(var, val, theta)
*   else if OCCUR-CHECK?(var, x) then return failure
*   else return add {var/x} to theta
* </pre>
*
* Figure 9.1 The unification algorithm. The algorithm works by comparing the
* structures of the inputs, elements by element. The substitution theta that is
* the argument to UNIFY is built up along the way and is used to make sure that
* later comparisons are consistent with bindings that were established earlier.
* In a compound expression, such as F(A, B), the OP field picks out the
* function symbol F and the ARGS field picks out the argument list (A, B).
*
* @author Ciaran O'Reilly
* @author Ravi Mohan
* @author Mike Stampone
*
*/
public class Unifier {
  //
  private static SubstVisitor _substVisitor = new SubstVisitor();

  public Unifier() {

  }

  /**
   * Returns a Map<Variable, Term> representing the substitution (i.e. a set
   * of variable/term pairs) or null which is used to indicate a failure to
   * unify.
   *
   * @param x
   *            a variable, constant, list, or compound
   * @param y
   *            a variable, constant, list, or compound
   *
   * @return a Map<Variable, Term> representing the substitution (i.e. a set
   *         of variable/term pairs) or null which is used to indicate a
   *         failure to unify.
   */
  public Map<Variable, Term> unify(FOLNode x, FOLNode y) {
    return unify(x, y, new LinkedHashMap<Variable, Term>());
  }

  /**
   * Returns a Map<Variable, Term> representing the substitution (i.e. a set
   * of variable/term pairs) or null which is used to indicate a failure to
   * unify.
   *
   * @param x
   *            a variable, constant, list, or compound
   * @param y
   *            a variable, constant, list, or compound
   * @param theta
   *            the substitution built up so far
   *
   * @return a Map<Variable, Term> representing the substitution (i.e. a set
   *         of variable/term pairs) or null which is used to indicate a
   *         failure to unify.
   */
  public Map<Variable, Term> unify(FOLNode x, FOLNode y,
      Map<Variable, Term> theta) {
    // if theta = failure then return failure
    if (theta == null) {
      return null;
    } else if (x.equals(y)) {
      // else if x = y then return theta
      return theta;
    } else if (x instanceof Variable) {
      // else if VARIABLE?(x) then return UNIVY-VAR(x, y, theta)
      return unifyVar((Variable) x, y, theta);
    } else if (y instanceof Variable) {
      // else if VARIABLE?(y) then return UNIFY-VAR(y, x, theta)
      return unifyVar((Variable) y, x, theta);
    } else if (isCompound(x) && isCompound(y)) {
      // else if COMPOUND?(x) and COMPOUND?(y) then
      // return UNIFY(x.ARGS, y.ARGS, UNIFY(x.OP, y.OP, theta))
      return unify(args(x), args(y), unifyOps(op(x), op(y), theta));
    } else {
      // else return failure
      return null;
    }
  }

  /**
   * Returns a Map<Variable, Term> representing the substitution (i.e. a set
   * of variable/term pairs) or null which is used to indicate a failure to
   * unify.
   *
   * @param x
   *            a variable, constant, list, or compound
   * @param y
   *            a variable, constant, list, or compound
   * @param theta
   *            the substitution built up so far
   *
   * @return a Map<Variable, Term> representing the substitution (i.e. a set
   *         of variable/term pairs) or null which is used to indicate a
   *         failure to unify.
   */
  // else if LIST?(x) and LIST?(y) then
  // return UNIFY(x.REST, y.REST, UNIFY(x.FIRST, y.FIRST, theta))
  public Map<Variable, Term> unify(List<? extends FOLNode> x,
      List<? extends FOLNode> y, Map<Variable, Term> theta) {
    if (theta == null) {
      return null;
    } else if (x.size() != y.size()) {
      return null;
    } else if (x.size() == 0 && y.size() == 0) {
      return theta;
    } else if (x.size() == 1 && y.size() == 1) {
      return unify(x.get(0), y.get(0), theta);
    } else {
      return unify(x.subList(1, x.size()), y.subList(1, y.size()),
          unify(x.get(0), y.get(0), theta));
    }
  }

  //
  // PROTECTED METHODS
  //

  // Note: You can subclass and override this method in order
  // to re-implement the OCCUR-CHECK?() to always
  // return false if you want that to be the default
  // behavior, as is the case with Prolog.
  // Note: Implementation is based on unify-bug.pdf document by Peter Norvig:
  // http://norvig.com/unify-bug.pdf
  protected boolean occurCheck(Map<Variable, Term> theta, Variable var,
      FOLNode x) {
    // ((equal var x) t)
    if (var.equals(x)) {
      return true;
      // ((bound? x subst)
    } else if (theta.containsKey(x)) {
      // (occurs-in? var (lookup x subst) subst))
      return occurCheck(theta, var, theta.get(x));
      // ((consp x) (or (occurs-in? var (first x) subst) (occurs-in? var
      // (rest x) subst)))
    } else if (x instanceof Function) {
      // (or (occurs-in? var (first x) subst) (occurs-in? var (rest x)
      // subst)))
      Function fx = (Function) x;
      for (Term fxt : fx.getArgs()) {
        if (occurCheck(theta, var, fxt)) {
          return true;
        }
      }
    }
    return false;
  }

  //
  // PRIVATE METHODS
  //

  /**
   * <code>
   * function UNIFY-VAR(var, x, theta) returns a substitution
   *   inputs: var, a variable
   *       x, any expression
   *       theta, the substitution built up so far
   * </code>
   */
  private Map<Variable, Term> unifyVar(Variable var, FOLNode x,
      Map<Variable, Term> theta) {

    if (!Term.class.isInstance(x)) {
      return null;
    } else if (theta.keySet().contains(var)) {
      // if {var/val} E theta then return UNIFY(val, x, theta)
      return unify(theta.get(var), x, theta);
    } else if (theta.keySet().contains(x)) {
      // else if {x/val} E theta then return UNIFY(var, val, theta)
      return unify(var, theta.get(x), theta);
    } else if (occurCheck(theta, var, x)) {
      // else if OCCUR-CHECK?(var, x) then return failure
      return null;
    } else {
      // else return add {var/x} to theta
      cascadeSubstitution(theta, var, (Term) x);
      return theta;
    }
  }

  private Map<Variable, Term> unifyOps(String x, String y,
      Map<Variable, Term> theta) {
    if (theta == null) {
      return null;
    } else if (x.equals(y)) {
      return theta;
    } else {
      return null;
    }
  }

  private List<? extends FOLNode> args(FOLNode x) {
    return x.getArgs();
  }

  private String op(FOLNode x) {
    return x.getSymbolicName();
  }

  private boolean isCompound(FOLNode x) {
    return x.isCompound();
  }

  // See:
  // http://logic.stanford.edu/classes/cs157/2008/miscellaneous/faq.html#jump165
  // for need for this.
  private Map<Variable, Term> cascadeSubstitution(Map<Variable, Term> theta,
      Variable var, Term x) {
    theta.put(var, x);
    for (Variable v : theta.keySet()) {
      theta.put(v, _substVisitor.subst(theta, theta.get(v)));
    }
    // Ensure Function Terms are correctly updates by passing over them
    // again. Fix for testBadCascadeSubstitution_LCL418_1()
    for (Variable v : theta.keySet()) {
      Term t = theta.get(v);
      if (t instanceof Function) {
        theta.put(v, _substVisitor.subst(theta, t));
      }
    }
    return theta;
  }
}
TOP

Related Classes of aima.core.logic.fol.Unifier

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.