Package aima.core.logic.fol.inference

Source Code of aima.core.logic.fol.inference.FOLTFMResolution$TFMAnswerHandler

package aima.core.logic.fol.inference;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import aima.core.logic.fol.Connectors;
import aima.core.logic.fol.inference.proof.Proof;
import aima.core.logic.fol.inference.proof.ProofFinal;
import aima.core.logic.fol.inference.proof.ProofStepGoal;
import aima.core.logic.fol.inference.trace.FOLTFMResolutionTracer;
import aima.core.logic.fol.kb.FOLKnowledgeBase;
import aima.core.logic.fol.kb.data.Clause;
import aima.core.logic.fol.kb.data.Literal;
import aima.core.logic.fol.parsing.ast.ConnectedSentence;
import aima.core.logic.fol.parsing.ast.NotSentence;
import aima.core.logic.fol.parsing.ast.Sentence;
import aima.core.logic.fol.parsing.ast.Term;
import aima.core.logic.fol.parsing.ast.Variable;

/**
* Artificial Intelligence A Modern Approach (3rd Edition): page 347.<br>
* <br>
* The algorithmic approach is identical to the propositional case, described in
* Figure 7.12.<br>
* <br>
* However, this implementation will use the T)wo F)inger M)ethod for looking
* for resolvents between clauses, which is very inefficient.<br>
* <br>
* see:<br>
* <a
* href="http://logic.stanford.edu/classes/cs157/2008/lectures/lecture04.pdf">
* http://logic.stanford.edu/classes/cs157/2008/lectures/lecture04.pdf</a>,
* slide 21 for the propositional case. In addition, an Answer literal will be
* used so that queries with Variables may be answered (see pg. 350 of AIMA3e).
*
* @author Ciaran O'Reilly
*
*/
public class FOLTFMResolution implements InferenceProcedure {

  private long maxQueryTime = 10 * 1000;

  private FOLTFMResolutionTracer tracer = null;

  public FOLTFMResolution() {

  }

  public FOLTFMResolution(long maxQueryTime) {
    setMaxQueryTime(maxQueryTime);
  }

  public FOLTFMResolution(FOLTFMResolutionTracer tracer) {
    setTracer(tracer);
  }

  public long getMaxQueryTime() {
    return maxQueryTime;
  }

  public void setMaxQueryTime(long maxQueryTime) {
    this.maxQueryTime = maxQueryTime;
  }

  public FOLTFMResolutionTracer getTracer() {
    return tracer;
  }

  public void setTracer(FOLTFMResolutionTracer tracer) {
    this.tracer = tracer;
  }

  //
  // START-InferenceProcedure
  public InferenceResult ask(FOLKnowledgeBase KB, Sentence alpha) {

    // clauses <- the set of clauses in CNF representation of KB ^ ~alpha
    Set<Clause> clauses = new LinkedHashSet<Clause>();
    for (Clause c : KB.getAllClauses()) {
      c = KB.standardizeApart(c);
      c.setStandardizedApartCheckNotRequired();
      clauses.addAll(c.getFactors());
    }
    Sentence notAlpha = new NotSentence(alpha);
    // Want to use an answer literal to pull
    // query variables where necessary
    Literal answerLiteral = KB.createAnswerLiteral(notAlpha);
    Set<Variable> answerLiteralVariables = KB
        .collectAllVariables(answerLiteral.getAtomicSentence());
    Clause answerClause = new Clause();

    if (answerLiteralVariables.size() > 0) {
      Sentence notAlphaWithAnswer = new ConnectedSentence(Connectors.OR,
          notAlpha, answerLiteral.getAtomicSentence());
      for (Clause c : KB.convertToClauses(notAlphaWithAnswer)) {
        c = KB.standardizeApart(c);
        c.setProofStep(new ProofStepGoal(c));
        c.setStandardizedApartCheckNotRequired();
        clauses.addAll(c.getFactors());
      }

      answerClause.addLiteral(answerLiteral);
    } else {
      for (Clause c : KB.convertToClauses(notAlpha)) {
        c = KB.standardizeApart(c);
        c.setProofStep(new ProofStepGoal(c));
        c.setStandardizedApartCheckNotRequired();
        clauses.addAll(c.getFactors());
      }
    }

    TFMAnswerHandler ansHandler = new TFMAnswerHandler(answerLiteral,
        answerLiteralVariables, answerClause, maxQueryTime);

    // new <- {}
    Set<Clause> newClauses = new LinkedHashSet<Clause>();
    Set<Clause> toAdd = new LinkedHashSet<Clause>();
    // loop do
    int noOfPrevClauses = clauses.size();
    do {
      if (null != tracer) {
        tracer.stepStartWhile(clauses, clauses.size(),
            newClauses.size());
      }

      newClauses.clear();

      // for each Ci, Cj in clauses do
      Clause[] clausesA = new Clause[clauses.size()];
      clauses.toArray(clausesA);
      // Basically, using the simple T)wo F)inger M)ethod here.
      for (int i = 0; i < clausesA.length; i++) {
        Clause cI = clausesA[i];
        if (null != tracer) {
          tracer.stepOuterFor(cI);
        }
        for (int j = i; j < clausesA.length; j++) {
          Clause cJ = clausesA[j];

          if (null != tracer) {
            tracer.stepInnerFor(cI, cJ);
          }

          // resolvent <- FOL-RESOLVE(Ci, Cj)
          Set<Clause> resolvents = cI.binaryResolvents(cJ);

          if (resolvents.size() > 0) {
            toAdd.clear();
            // new <- new <UNION> resolvent
            for (Clause rc : resolvents) {
              toAdd.addAll(rc.getFactors());
            }

            if (null != tracer) {
              tracer.stepResolved(cI, cJ, toAdd);
            }

            ansHandler.checkForPossibleAnswers(toAdd);

            if (ansHandler.isComplete()) {
              break;
            }

            newClauses.addAll(toAdd);
          }

          if (ansHandler.isComplete()) {
            break;
          }
        }
        if (ansHandler.isComplete()) {
          break;
        }
      }

      noOfPrevClauses = clauses.size();

      // clauses <- clauses <UNION> new
      clauses.addAll(newClauses);

      if (ansHandler.isComplete()) {
        break;
      }

      // if new is a <SUBSET> of clauses then finished
      // searching for an answer
      // (i.e. when they were added the # clauses
      // did not increase).
    } while (noOfPrevClauses < clauses.size());

    if (null != tracer) {
      tracer.stepFinished(clauses, ansHandler);
    }

    return ansHandler;
  }

  // END-InferenceProcedure
  //

  //
  // PRIVATE METHODS
  //
  class TFMAnswerHandler implements InferenceResult {
    private Literal answerLiteral = null;
    private Set<Variable> answerLiteralVariables = null;
    private Clause answerClause = null;
    private long finishTime = 0L;
    private boolean complete = false;
    private List<Proof> proofs = new ArrayList<Proof>();
    private boolean timedOut = false;

    public TFMAnswerHandler(Literal answerLiteral,
        Set<Variable> answerLiteralVariables, Clause answerClause,
        long maxQueryTime) {
      this.answerLiteral = answerLiteral;
      this.answerLiteralVariables = answerLiteralVariables;
      this.answerClause = answerClause;
      //
      this.finishTime = System.currentTimeMillis() + maxQueryTime;
    }

    //
    // START-InferenceResult
    public boolean isPossiblyFalse() {
      return !timedOut && proofs.size() == 0;
    }

    public boolean isTrue() {
      return proofs.size() > 0;
    }

    public boolean isUnknownDueToTimeout() {
      return timedOut && proofs.size() == 0;
    }

    public boolean isPartialResultDueToTimeout() {
      return timedOut && proofs.size() > 0;
    }

    public List<Proof> getProofs() {
      return proofs;
    }

    // END-InferenceResult
    //

    public boolean isComplete() {
      return complete;
    }

    private void checkForPossibleAnswers(Set<Clause> resolvents) {
      // If no bindings being looked for, then
      // is just a true false query.
      for (Clause aClause : resolvents) {
        if (answerClause.isEmpty()) {
          if (aClause.isEmpty()) {
            proofs.add(new ProofFinal(aClause.getProofStep(),
                new HashMap<Variable, Term>()));
            complete = true;
          }
        } else {
          if (aClause.isEmpty()) {
            // This should not happen
            // as added an answer literal, which
            // implies the database (i.e. premises) are
            // unsatisfiable to begin with.
            throw new IllegalStateException(
                "Generated an empty clause while looking for an answer, implies original KB is unsatisfiable");
          }

          if (aClause.isUnitClause()
              && aClause.isDefiniteClause()
              && aClause
                  .getPositiveLiterals()
                  .get(0)
                  .getAtomicSentence()
                  .getSymbolicName()
                  .equals(answerLiteral.getAtomicSentence()
                      .getSymbolicName())) {
            Map<Variable, Term> answerBindings = new HashMap<Variable, Term>();
            List<Term> answerTerms = aClause.getPositiveLiterals()
                .get(0).getAtomicSentence().getArgs();
            int idx = 0;
            for (Variable v : answerLiteralVariables) {
              answerBindings.put(v, answerTerms.get(idx));
              idx++;
            }
            boolean addNewAnswer = true;
            for (Proof p : proofs) {
              if (p.getAnswerBindings().equals(answerBindings)) {
                addNewAnswer = false;
                break;
              }
            }
            if (addNewAnswer) {
              proofs.add(new ProofFinal(aClause.getProofStep(),
                  answerBindings));
            }
          }
        }

        if (System.currentTimeMillis() > finishTime) {
          complete = true;
          // Indicate that I have run out of query time
          timedOut = true;
        }
      }
    }

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder();
      sb.append("isComplete=" + complete);
      sb.append("\n");
      sb.append("result=" + proofs);
      return sb.toString();
    }
  }
}
TOP

Related Classes of aima.core.logic.fol.inference.FOLTFMResolution$TFMAnswerHandler

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.