/// <summary> /// <code> /// function FOL-FC-ASK(KB, alpha) returns a substitution or false /// inputs: KB, the knowledge base, a set of first order definite clauses /// alpha, the query, an atomic sentence /// </code> /// </summary> /// <param name="KB"></param> /// <param name="query"></param> /// <returns></returns> public IInferenceResult Ask(FOLKnowledgeBase KB, ISentence query) { // Assertions on the type of queries this Inference procedure // supports if (!(query is IAtomicSentence)) { throw new ArgumentOutOfRangeException("query", "Only Atomic Queries are supported."); } var ansHandler = new FCAskAnswerHandler(); var alpha = new Literal((IAtomicSentence)query); // local variables: new, the new sentences inferred on each iteration IList <Literal> newSentences = new List <Literal>(); // Ensure query is not already a know fact before // attempting forward chaining. ISet <IDictionary <Variable, ITerm> > answers = KB.Fetch(alpha); if (answers.Count > 0) { ansHandler.AddProofStep(new ProofStepFoChAlreadyAFact(alpha)); ansHandler.SetAnswers(answers); return(ansHandler); } // repeat until new is empty do { // new <- {} newSentences.Clear(); // for each rule in KB do // (p1 ^ ... ^ pn => q) <-STANDARDIZE-VARIABLES(rule) foreach (Clause impl in KB.GetAllDefiniteClauseImplications()) { var standardizedImpl = KB.StandardizeApart(impl); // for each theta such that SUBST(theta, p1 ^ ... ^ pn) = // SUBST(theta, p'1 ^ ... ^ p'n) // --- for some p'1,...,p'n in KB foreach (IDictionary <Variable, ITerm> theta in KB.Fetch(this.Invert(standardizedImpl.GetNegativeLiterals()))) { // q' <- SUBST(theta, q) Literal qPrime = KB.Subst(theta, standardizedImpl.GetPositiveLiterals()[0]); // if q' does not unify with some sentence already in KB or // new then do if (!KB.IsRenaming(qPrime) && !KB.IsRenaming(qPrime, newSentences)) { // add q' to new newSentences.Add(qPrime); ansHandler.AddProofStep(standardizedImpl, qPrime, theta); // theta <- UNIFY(q', alpha) // if theta is not fail then return theta if (KB.Unify(qPrime.AtomicSentence, alpha.AtomicSentence) != null) { foreach (Literal l in newSentences) { ISentence s; if (l.IsPositiveLiteral()) { s = l.AtomicSentence; } else { s = new NotSentence(l.AtomicSentence); } KB.tell(s); } ansHandler.SetAnswers(KB.Fetch(alpha)); return(ansHandler); } } } } // add new to KB foreach (Literal l in newSentences) { ISentence s; if (l.IsPositiveLiteral()) { s = l.AtomicSentence; } else { s = new NotSentence(l.AtomicSentence); } KB.tell(s); } } while (newSentences.Count > 0); // return false return(ansHandler); }