private void calculateFactors(List <Clause> parentFactors) { nonTrivialFactors = new List <Clause>(); Dictionary <Variable, Term> theta = new Dictionary <Variable, Term>(); List <Literal> lits = new List <Literal>(); for (int i = 0; i < 2; i++) { lits.Clear(); if (i == 0) { // Look at the positive literals lits.AddRange(positiveLiterals); } else { // Look at the negative literals lits.AddRange(negativeLiterals); } for (int x = 0; x < lits.Count; x++) { for (int y = x + 1; y < lits.Count; y++) { Literal litX = lits[x]; Literal litY = lits[y]; theta.Clear(); Dictionary <Variable, Term> substitution = _unifier.unify(litX .getAtomicSentence(), litY.getAtomicSentence(), theta); if (null != substitution) { List <Literal> posLits = new List <Literal>(); List <Literal> negLits = new List <Literal>(); if (i == 0) { posLits .Add(_substVisitor .subst(substitution, litX)); } else { negLits .Add(_substVisitor .subst(substitution, litX)); } foreach (Literal pl in positiveLiterals) { if (pl == litX || pl == litY) { continue; } posLits.Add(_substVisitor.subst(substitution, pl)); } foreach (Literal nl in negativeLiterals) { if (nl == litX || nl == litY) { continue; } negLits.Add(_substVisitor.subst(substitution, nl)); } // Ensure the non trivial factor is standardized apart _standardizeApart.standardizeApart(posLits, negLits, _saIndexical); Clause c = new Clause(posLits, negLits); c.setProofStep(new ProofStepClauseFactor(c, this)); if (isImmutable()) { c.setImmutable(); } if (!isStandardizedApartCheckRequired()) { c.setStandardizedApartCheckNotRequired(); } if (null == parentFactors) { c.calculateFactors(nonTrivialFactors); nonTrivialFactors.AddRange(c.getFactors()); } else { if (!parentFactors.Contains(c)) { c.calculateFactors(nonTrivialFactors); nonTrivialFactors.AddRange(c.getFactors()); } } } } } } factors = new List <Clause>(); // Need to add self, even though a non-trivial // factor. See: slide 30 // http://logic.stanford.edu/classes/cs157/2008/lectures/lecture10.pdf // for example of incompleteness when // trivial factor not included. factors.Add(this); factors.AddRange(nonTrivialFactors); }
private bool checkSubsumes(Clause othC, Dictionary <String, List <Literal> > thisToTry, Dictionary <String, List <Literal> > othCToTry) { bool subsumes = false; List <Term> thisTerms = new List <Term>(); List <Term> othCTerms = new List <Term>(); // Want to track possible number of permuations List <int> radixs = new List <int>(); foreach (String literalName in thisToTry.Keys) { int sizeT = thisToTry[literalName].Count; int sizeO = othCToTry[literalName].Count; if (sizeO > 1) { // The following is being used to // track the number of permutations // that can be mapped from the // other clauses like literals to this // clauses like literals. // i.e. n!/(n-r)! // where n=sizeO and r =sizeT for (int i = 0; i < sizeT; i++) { int r = sizeO - i; if (r > 1) { radixs.Add(r); } } } // Track the terms for this clause foreach (Literal tl in thisToTry[literalName]) { List <FOLNode> folNodes = tl.getAtomicSentence().getArgs(); foreach (FOLNode n in folNodes) { thisTerms.Add((Term)n); } } } MixedRadixNumber permutation = null; long numPermutations = 1L; if (radixs.Count > 0) { permutation = new MixedRadixNumber(0, radixs); numPermutations = permutation.getMaxAllowedValue() + 1; } // Want to ensure none of the othCVariables are // part of the key set of a unification as // this indicates it is not a legal subsumption. List <Variable> othCVariables = _variableCollector .collectAllVariables(othC); Dictionary <Variable, Term> theta = new Dictionary <Variable, Term>(); List <Literal> literalPermuations = new List <Literal>(); for (long l = 0L; l < numPermutations; l++) { // Track the other clause's terms for this // permutation. othCTerms.Clear(); int radixIdx = 0; foreach (String literalName in thisToTry.Keys) { int sizeT = thisToTry[literalName].Count; literalPermuations.Clear(); literalPermuations.AddRange(othCToTry[literalName]); int sizeO = literalPermuations.Count; if (sizeO > 1) { for (int i = 0; i < sizeT; i++) { int r = sizeO - i; if (r > 1) { // If not a 1 to 1 mapping then you need // to use the correct permuation int numPos = permutation .getCurrentNumeralValue(radixIdx); Literal lit = literalPermuations[numPos]; literalPermuations.Remove(lit); foreach (FOLNode arg in lit.getAtomicSentence().getArgs()) { othCTerms.Add((Term)arg); } radixIdx++; } else { // is the last mapping, therefore // won't be on the radix foreach (FOLNode arg in literalPermuations[0].getAtomicSentence().getArgs()) { othCTerms.Add((Term)arg); } } } } else { // a 1 to 1 mapping foreach (FOLNode arg in literalPermuations[0].getAtomicSentence().getArgs()) { othCTerms.Add((Term)arg); } } } // Note: on unifier // unifier.unify(P(w, x), P(y, z)))={w=y, x=z} // unifier.unify(P(y, z), P(w, x)))={y=w, z=x} // Therefore want this clause to be the first // so can do the othCVariables check for an invalid // subsumes. theta.Clear(); List <FOLNode> termNodes = new List <FOLNode>(); foreach (Term t in thisTerms) { termNodes.Add((FOLNode)t); } List <FOLNode> othCNodes = new List <FOLNode>(); foreach (Term t in othCTerms) { othCNodes.Add((FOLNode)t); } if (null != _unifier.unify(termNodes, othCNodes, theta)) { bool containsAny = false; foreach (Variable v in theta.Keys) { if (othCVariables.Contains(v)) { containsAny = true; break; } } if (!containsAny) { subsumes = true; break; } } // If there is more than 1 mapping // keep track of where I am in the // possible number of mapping permutations. if (null != permutation) { permutation.increment(); } } return(subsumes); }
public Literal subst(Dictionary<Variable, Term> theta, Literal aLiteral) { return aLiteral.newInstance((AtomicSentence)aLiteral .getAtomicSentence().accept(this, theta)); }
private String getFactKey(Literal l) { StringBuilder key = new StringBuilder(); if (l.isPositiveLiteral()) { key.Append("+"); } else { key.Append("-"); } key.Append(l.getAtomicSentence().getSymbolicName()); return key.ToString(); }
// Note: see pg. 281 public bool isRenaming(Literal l, List<Literal> possibleMatches) { foreach (Literal q in possibleMatches) { if (l.isPositiveLiteral() != q.isPositiveLiteral()) { continue; } Dictionary<Variable, Term> subst = unifier.unify(l.getAtomicSentence(), q .getAtomicSentence()); if (null != subst) { int cntVarTerms = 0; foreach (Term t in subst.Values) { if (t is Variable) { cntVarTerms++; } } // If all the substitutions, even if none, map to Variables // then this is a renaming if (subst.Count == cntVarTerms) { return true; } } } return false; }
// Note: pg 278, FETCH(q) concept. public /* lock */ List<Dictionary<Variable, Term>> fetch(Literal l) { // Get all of the substitutions in the KB that p unifies with List<Dictionary<Variable, Term>> allUnifiers = new List<Dictionary<Variable, Term>>(); List<Literal> matchingFacts = fetchMatchingFacts(l); if (null != matchingFacts) { foreach (Literal fact in matchingFacts) { Dictionary<Variable, Term> substitution = unifier.unify(l .getAtomicSentence(), fact.getAtomicSentence()); if (null != substitution) { allUnifiers.Add(substitution); } } } return allUnifiers; }
// // START-InferenceProcedure /** * <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> */ public InferenceResult ask(FOLKnowledgeBase KB, Sentence query) { // Assertions on the type of queries this Inference procedure // supports if (!(query is AtomicSentence)) { throw new ArgumentException( "Only Atomic Queries are supported."); } FCAskAnswerHandler ansHandler = new FCAskAnswerHandler(); Literal alpha = new Literal((AtomicSentence)query); // local variables: new, the new sentences inferred on each iteration List<Literal> newSentences = new List<Literal>(); // Ensure query is not already a know fact before // attempting forward chaining. List<Dictionary<Variable, Term>> 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()) { Clause impl2 = 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 (Dictionary<Variable, Term> theta in KB.fetch(invert(new List<Literal>(impl2 .getNegativeLiterals())))) { // q' <- SUBST(theta, q) Literal qPrime = KB.subst(theta, impl.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(impl, qPrime, theta); // theta <- UNIFY(q', alpha) Dictionary<Variable, Term> theta2 = KB.unify(qPrime.getAtomicSentence(), alpha .getAtomicSentence()); // if theta is not fail then return theta if (null != theta2) { foreach (Literal l in newSentences) { Sentence s = null; if (l.isPositiveLiteral()) { s = l.getAtomicSentence(); } else { s = new NotSentence(l.getAtomicSentence()); } KB.tell(s); } ansHandler.setAnswers(KB.fetch(alpha)); return ansHandler; } } } } // add new to KB foreach (Literal l in newSentences) { Sentence s = null; if (l.isPositiveLiteral()) { s = l.getAtomicSentence(); } else { s = new NotSentence(l.getAtomicSentence()); } KB.tell(s); } } while (newSentences.Count > 0); // return false return ansHandler; }