All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aima.core.logic.fol.inference.FOLBCAsk Maven / Gradle / Ivy

Go to download

AIMA-Java Core Algorithms from the book Artificial Intelligence a Modern Approach 3rd Ed.

The newest version!
package aima.core.logic.fol.inference;

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

import aima.core.logic.fol.inference.proof.Proof;
import aima.core.logic.fol.inference.proof.ProofFinal;
import aima.core.logic.fol.inference.proof.ProofStepBwChGoal;
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.AtomicSentence;
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 (2nd Edition): Figure 9.6, page
 * 288.
*
* *
 * function FOL-BC-ASK(KB, goals, theta) returns a set of substitutions
 *   input: KB, a knowledge base
 *          goals, a list of conjuncts forming a query (theta already applied)
 *          theta, the current substitution, initially the empty substitution {}
 *   local variables: answers, a set of substitutions, initially empty
 *   
 *   if goals is empty then return {theta}
 *   qDelta <- SUBST(theta, FIRST(goals))
 *   for each sentence r in KB where STANDARDIZE-APART(r) = (p1 ˆ ... ˆ pn => q)
 *          and thetaDelta <- UNIFY(q, qDelta) succeeds
 *       new_goals <- [p1,...,pn|REST(goals)]
 *       answers <- FOL-BC-ASK(KB, new_goals, COMPOSE(thetaDelta, theta)) U answers
 *   return answers
 * 
* * Figure 9.6 A simple backward-chaining algorithm. * * @author Ciaran O'Reilly * @author Mike Stampone */ public class FOLBCAsk implements InferenceProcedure { public FOLBCAsk() { } // // START-InferenceProcedure /** * Returns a set of substitutions * * @param KB * a knowledge base * @param query * goals, a list of conjuncts forming a query * * @return a set of substitutions */ public InferenceResult ask(FOLKnowledgeBase KB, Sentence query) { // Assertions on the type queries this Inference procedure // supports if (!(query instanceof AtomicSentence)) { throw new IllegalArgumentException( "Only Atomic Queries are supported."); } List goals = new ArrayList(); goals.add(new Literal((AtomicSentence) query)); BCAskAnswerHandler ansHandler = new BCAskAnswerHandler(); List> allProofSteps = folbcask(KB, ansHandler, goals, new HashMap()); ansHandler.setAllProofSteps(allProofSteps); return ansHandler; } // END-InferenceProcedure // // // PRIVATE METHODS // /** * * function FOL-BC-ASK(KB, goals, theta) returns a set of substitutions * input: KB, a knowledge base * goals, a list of conjuncts forming a query (theta already applied) * theta, the current substitution, initially the empty substitution {} * */ private List> folbcask(FOLKnowledgeBase KB, BCAskAnswerHandler ansHandler, List goals, Map theta) { List> thisLevelProofSteps = new ArrayList>(); // local variables: answers, a set of substitutions, initially empty // if goals is empty then return {theta} if (goals.isEmpty()) { thisLevelProofSteps.add(new ArrayList()); return thisLevelProofSteps; } // qDelta <- SUBST(theta, FIRST(goals)) Literal qDelta = KB.subst(theta, goals.get(0)); // for each sentence r in KB where // STANDARDIZE-APART(r) = (p1 ^ ... ^ pn => q) for (Clause r : KB.getAllDefiniteClauses()) { r = KB.standardizeApart(r); // and thetaDelta <- UNIFY(q, qDelta) succeeds Map thetaDelta = KB.unify(r.getPositiveLiterals() .get(0).getAtomicSentence(), qDelta.getAtomicSentence()); if (null != thetaDelta) { // new_goals <- [p1,...,pn|REST(goals)] List newGoals = new ArrayList( r.getNegativeLiterals()); newGoals.addAll(goals.subList(1, goals.size())); // answers <- FOL-BC-ASK(KB, new_goals, COMPOSE(thetaDelta, // theta)) U answers Map composed = compose(KB, thetaDelta, theta); List> lowerLevelProofSteps = folbcask( KB, ansHandler, newGoals, composed); ansHandler.addProofStep(lowerLevelProofSteps, r, qDelta, composed); thisLevelProofSteps.addAll(lowerLevelProofSteps); } } // return answers return thisLevelProofSteps; } // Artificial Intelligence A Modern Approach (2nd Edition): page 288. // COMPOSE(delta, tau) is the substitution whose effect is identical to // the effect of applying each substitution in turn. That is, // SUBST(COMPOSE(theta1, theta2), p) = SUBST(theta2, SUBST(theta1, p)) private Map compose(FOLKnowledgeBase KB, Map theta1, Map theta2) { Map composed = new HashMap(); // So that it behaves like: // SUBST(theta2, SUBST(theta1, p)) // There are two steps involved here. // See: http://logic.stanford.edu/classes/cs157/2008/notes/chap09.pdf // for a detailed discussion: // 1. Apply theta2 to the range of theta1. for (Variable v : theta1.keySet()) { composed.put(v, KB.subst(theta2, theta1.get(v))); } // 2. Adjoin to delta all pairs from tau with different // domain variables. for (Variable v : theta2.keySet()) { if (!theta1.containsKey(v)) { composed.put(v, theta2.get(v)); } } return cascadeSubstitutions(KB, composed); } // See: // http://logic.stanford.edu/classes/cs157/2008/miscellaneous/faq.html#jump165 // for need for this. private Map cascadeSubstitutions(FOLKnowledgeBase KB, Map theta) { for (Variable v : theta.keySet()) { Term t = theta.get(v); theta.put(v, KB.subst(theta, t)); } return theta; } class BCAskAnswerHandler implements InferenceResult { private List proofs = new ArrayList(); public BCAskAnswerHandler() { } // // START-InferenceResult public boolean isPossiblyFalse() { return proofs.size() == 0; } public boolean isTrue() { return proofs.size() > 0; } public boolean isUnknownDueToTimeout() { return false; } public boolean isPartialResultDueToTimeout() { return false; } public List getProofs() { return proofs; } // END-InferenceResult // public void setAllProofSteps(List> allProofSteps) { for (List steps : allProofSteps) { ProofStepBwChGoal lastStep = steps.get(steps.size() - 1); Map theta = lastStep.getBindings(); proofs.add(new ProofFinal(lastStep, theta)); } } public void addProofStep( List> currentLevelProofSteps, Clause toProve, Literal currentGoal, Map bindings) { if (currentLevelProofSteps.size() > 0) { ProofStepBwChGoal predecessor = new ProofStepBwChGoal(toProve, currentGoal, bindings); for (List steps : currentLevelProofSteps) { if (steps.size() > 0) { steps.get(0).setPredecessor(predecessor); } steps.add(0, predecessor); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy