/// <summary> /// A helper method for easily creating an array of Individual predicates. /// </summary> /// <param name="predicates">The array of predicate values.</param> /// <returns>The array of Individual built on the predicate values.</returns> public static Individual[] NewArray(params object[] predicates) { Individual[] individuals = new Individual[predicates.Length]; for (int i=0; i<predicates.Length; i++) individuals[i] = new Individual(predicates[i]); return individuals; }
/// <summary> /// Checks if an Individual matches the current Function by either calling a NxBRE helper method /// or using a binder. /// </summary> /// <param name="individual">The Individual to check.</param> /// <returns>True if the Individual matches the Function.</returns> public bool Evaluate(Individual individual) { if (resolutionType == FunctionResolutionType.NxBRE) return EvaluateNxBREOperator(individual.Value, name, arguments); else if (resolutionType == FunctionResolutionType.Binder) return bob.Evaluate(individual.Value, functionSignature, arguments); else throw new BREException("Function evaluation mode not supported: " + resolutionType); }
/// <summary> /// Called by the Inference Engine whenever an Individual predicate is found in the /// rule base and must be evaluated to determine if it is a function. /// </summary> /// <param name="individual">The Individual found in the rule base.</param> /// <returns>The unchanged Individual if it is not a function, else a Function predicate.</returns> public IPredicate AnalyzeIndividualPredicate(Individual individual) { if (individual.Value is string) { // Match the regular expression pattern against a text string. Match m = RegexFunction.Match((string)individual.Value); if (m.Success) { // Create a function predicate with ArrayList arguments = new ArrayList(); foreach (Capture c2 in m.Groups[2].Captures) arguments.Add(c2.ToString().Trim()); return new Function(Function.FunctionResolutionType.Binder, (string)individual.Value, this, m.Groups[1].Captures[0].ToString(), (string[])arguments.ToArray(typeof(string))); } } return individual; }
// ----------------- Static methods ---------------- /// <summary> /// Resolves all Function predicates by replacing them by their String representations. /// </summary> /// <param name="atom">The Atom to resolve.</param> /// <returns>A new Atom where all Function predicates have been resolved. If no /// Function predicate exists, it returns a clone of the current Atom.</returns> public static Atom ResolveFunctions(Atom atom) { if (atom.HasFunction) { IPredicate[] predicates = new IPredicate[atom.predicates.Length]; for(int i=0; i<atom.predicates.Length; i++) if (atom.predicates[i] is Function) predicates[i] = new Individual(atom.predicates[i].ToString()); else predicates[i] = atom.predicates[i]; return new Atom(atom.Negative, atom.Type, predicates); } else return (Atom)atom.Clone(); }
/// <summary> /// Prepare the atom to be pattern matched by replacing in a fact: /// - all the predicates that match function predicates in the passed atom with /// the string reprentation of these function predicates, /// - all the predicates that match individual predicates in the passed atom with /// the string reprentation of these individual predicates. /// </summary> /// <remarks> /// This operation must be done *if and only if* the fact matches the atom. /// </remarks> /// <param name="factToResolve">The fact that must be resolved.</param> /// <param name="atom">The atom with which the current fact matches.</param> /// <returns>A new fact with only String individuals.</returns> public static Fact Resolve(Fact factToResolve, Atom atom) { IPredicate[] predicates = new IPredicate[factToResolve.Members.Length]; for(int i=0; i<factToResolve.Members.Length; i++) if ((atom.Members[i] is Function) || ((atom.Members[i] is Individual) && (!(factToResolve.Members[i].Value is System.String)))) predicates[i] = new Individual(atom.Members[i].ToString()); else predicates[i] = factToResolve.Members[i]; return new Fact(factToResolve.Type, predicates); }
private int RunImplication(Implication implication) { int implicationResultsCount = 0; FactBase.ProcessResultSet processResults = WM.FB.ProcessAtomGroup(implication.AtomGroup); if (implication.Action == ImplicationAction.Count) { if (HasLogListener) ForceDispatchLog("Counting Implication '" + implication.Label + "' counted: " + processResults.Count, LogEventImpl.DEBUG); bool variableFound = false; IPredicate[] members = (IPredicate[])implication.Deduction.Members.Clone(); for(int i=0; !variableFound && i<members.Length; i++) { if (members[i] is Variable) { members[i] = new Individual(processResults.Count); variableFound = true; break; } } if ((IEImpl.StrictImplication) && (!variableFound)) throw new BREException("Strict counting implication rejected the assertion due to lack of variable predicate: " + implication.Deduction); Fact deductedFact = new Fact(implication.Deduction.Type, members); implicationResultsCount++; // counting implication factbase action bool result = WM.FB.Assert(deductedFact); if ((result) && (NewFactHandler != null)) NewFactHandler(new NewFactEventArgs(deductedFact)); if (HasLogListener) ForceDispatchLog((result?"Asserted":"Ignored Assertion of ") + " Fact: " + deductedFact.ToString(), LogEventImpl.DEBUG); } else if ((implication.Action == ImplicationAction.Assert) || (implication.Action == ImplicationAction.Retract)) { // loop on each result and try to build a new fact out of the predicates coming for each result foreach(ArrayList processResult in processResults) { Fact deductedFact = BuildFact(implication.Deduction, processResult); if (deductedFact != null) { implicationResultsCount++; if (implication.Action == ImplicationAction.Retract) { // retracting implication factbase action bool result = WM.FB.Retract(deductedFact); if ((result) && (DeleteFactHandler != null)) DeleteFactHandler(new NewFactEventArgs(deductedFact)); if (HasLogListener) ForceDispatchLog((result?"Retracted":"Ignored Retraction of ") + " Fact: " + deductedFact.ToString(), LogEventImpl.DEBUG); } else { // asserting implication factbase action bool result = WM.FB.Assert(deductedFact); if ((result) && (NewFactHandler != null)) NewFactHandler(new NewFactEventArgs(deductedFact)); if (HasLogListener) ForceDispatchLog((result?"Asserted":"Ignored Assertion of ") + " Fact: " + deductedFact.ToString(), LogEventImpl.DEBUG); } } } } else if (implication.Action == ImplicationAction.Modify) { foreach(ArrayList processResult in processResults) { // look for facts to modify by: // - resolving variable predicates of the deduction // - replacing formulas with variables // and performing a search in the fact base Atom modificationTargetLookup = FactBase.BuildQueryFromDeduction(implication.Deduction, processResult); if (HasLogListener) ForceDispatchLog("Modifying Implication '" + implication.Label + "' will target matches of: " + modificationTargetLookup, LogEventImpl.DEBUG); foreach(Fact factToModify in FactBase.ExtractFacts(WM.FB.ProcessAtomGroup(new AtomGroup(AtomGroup.LogicalOperator.And, modificationTargetLookup)))) { if (HasLogListener) ForceDispatchLog("-> found target: " + factToModify, LogEventImpl.DEBUG); // for each fact, perform the modification Fact deductedFact = BuildFact(implication.Deduction, FactBase.EnrichResults(processResult, modificationTargetLookup, factToModify)); if (HasLogListener) ForceDispatchLog("-> modified target: " + deductedFact, LogEventImpl.DEBUG); if ((deductedFact != null) && (!factToModify.Equals(deductedFact))) { implicationResultsCount++; bool result = WM.FB.Modify(factToModify, deductedFact); if ((result) && (ModifyFactHandler != null))ModifyFactHandler(new NewFactEventArgs(factToModify, deductedFact)); if (HasLogListener) ForceDispatchLog((result?"Modified":"Ignored Modification of ") + " Fact: " + factToModify.ToString(), LogEventImpl.DEBUG); } } } } else throw new BREException("Implication action not supported: " + implication.Action); return implicationResultsCount; }
/// <summary> /// Prepare the atom to be pattern matched by replacing in a fact: /// - all the predicates that match function predicates in the passed atom with /// the string representation of these function predicates, /// - in fully mode, all the predicates that match individual predicates in the passed atom with /// the string representation of these individual predicates. /// </summary> /// <remarks> /// This operation must be done *if and only if* the fact matches the atom. /// </remarks> /// <param name="fully">Forces resolution of non-string individual to String.</param> /// <param name="factToResolve">The fact that must be resolved.</param> /// <param name="atom">The atom with which the current fact matches.</param> /// <returns>A new fact with only String individuals.</returns> public static Fact Resolve(bool fully, Fact factToResolve, Atom atom) { IPredicate[] predicates = new IPredicate[factToResolve.Members.Length]; for(int i=0; i<factToResolve.Members.Length; i++) { if ((atom.Members[i] is Function) || ((fully) && (atom.Members[i] is Individual) && (!(factToResolve.Members[i].Value is System.String)))) { predicates[i] = new Individual(atom.Members[i].ToString()); } else { predicates[i] = factToResolve.Members[i]; } } return (Fact)factToResolve.CloneWithNewMembers(predicates); }
protected override IPredicate BuildPredicate(XPathNavigator predicateElement, bool inHead, bool resolveImmediatly) { IPredicate predicate; string predicateName = predicateElement.Name; string predicateValue = predicateElement.Value; switch(predicateName) { // --------- IND predicates -------- case "Ind": string predicateURI = predicateElement.GetAttribute("uri", String.Empty).ToLower(); switch(predicateURI) { case "nxbre://expression": if (inHead) { if (resolveImmediatly) predicate = new Individual(Compilation.Evaluate(predicateValue)); else predicate = new Formula(Formula.FormulaResolutionType.NxBRE, Binder, predicateValue); } else { predicate = new Function(Function.FunctionResolutionType.Binder, predicateValue, new ExpressionEvaluator(predicateValue), String.Empty, String.Empty); } break; case "nxbre://operator": // NxBRE operators must follow this pattern: operator(uniqueargument) string[] split = predicateValue.Split(Parameter.PARENTHESIS); predicate = new Function(Function.FunctionResolutionType.NxBRE, predicateValue, null, split[0], split[1]); break; case "nxbre://binder": if (Binder == null) throw new BREException("No binder available for Individual: " + predicateValue); if (inHead) predicate = new Formula(Formula.FormulaResolutionType.Binder, Binder, predicateValue); else predicate = Binder.AnalyzeIndividualPredicate(new Individual(predicateValue)); break; case "": predicate = new Individual(predicateValue); break; default: // there is a predicateURI but it is not recognized by the engine so we assimilate it as // a web reference predicate = new Individual(new HyperLink(predicateValue, predicateURI)); break; } break; // --------- VAR predicates -------- case "Var": predicate = new Variable(predicateValue); break; // --------- DATA predicates -------- case "Data": string schemaType = predicateElement.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance"); if (schemaType != String.Empty) { // remove any preceding namespace, like in "xs:string" if (schemaType.IndexOf(':')>=0) schemaType = schemaType.Split(':')[1]; // this is a strongly typed individual predicate = new Individual(Schema.ToClr(predicateValue, schemaType), schemaType); } else { // this is just a string based predicate, using Data was not so wise... predicate = new Individual(predicateValue); } break; // --------- SLOT predicates -------- case "slot": // the first child must be an Ind, we do not support other slot name holders if (predicateElement.MoveToFirstChild()) { if (predicateElement.Name != "Ind") throw new BREException("Only Ind is accepted as a slot name holder"); string slotName = predicateElement.Value; if (!predicateElement.MoveToNext()) throw new BREException("A slot should contain two children"); predicate = new Slot(slotName, BuildPredicate(predicateElement, inHead, resolveImmediatly)); } else { throw new BREException("A slot can not be empty"); } break; // --------- UNKNOWN predicates -------- default: throw new BREException("Unsupported predicate type: " + predicateName); } return predicate; }
public void Gedcom() { deductionsToCheck = new string[]{ "sibling{Girl,Boy}", "sibling{Boy,Girl}", "parent{Girl,Daddy}", "parent{Girl,Mummy}", "parent{Boy,Daddy}", "parent{Boy,Mummy}", "ancestor{Girl,Daddy}", "ancestor{Girl,Mummy}", "ancestor{Boy,Daddy}", "ancestor{Boy,Mummy}", "descendent{Daddy,Girl}", "descendent{Mummy,Girl}", "descendent{Daddy,Boy}", "descendent{Mummy,Boy}", "child{Daddy,Girl}", "child{Mummy,Girl}", "child{Daddy,Boy}", "child{Mummy,Boy}", "spouse{Daddy,Mummy}", "spouse{Mummy,Daddy}", "wife{Daddy,Mummy}", "daughter{Daddy,Girl}", "daughter{Mummy,Girl}", "mother{Girl,Mummy}", "mother{Boy,Mummy}", "sister{Boy,Girl}", "son{Daddy,Boy}", "son{Mummy,Boy}", "father{Girl,Daddy}", "father{Boy,Daddy}", "brother{Girl,Boy}", "husband{Mummy,Daddy}", "ancestor{Daddy,Old'Pa}", "descendent{Old'Pa,Daddy}", "ancestor{Girl,Old'Pa}", "ancestor{Boy,Old'Pa}", "descendent{Old'Pa,Girl}", "descendent{Old'Pa,Boy}", "grandparent{Girl,Old'Pa}", "grandparent{Boy,Old'Pa}", "granddaughter{Girl,Old'Pa}", "grandchild{Old'Pa,Girl}", "grandchild{Old'Pa,Boy}", "child{Old'Pa,Daddy}", "grandson{Old'Pa,Boy}", "son{Old'Pa,Daddy}", "grandfather{Girl,Old'Pa}", "grandfather{Boy,Old'Pa}", "father{Daddy,Old'Pa}", "ancestor{Uncle,Old'Pa}", "sibling{Daddy,Uncle}", "father{Uncle,Old'Pa}", "child{Old'Pa,Uncle}", "brother{Uncle,Daddy}", "brother{Daddy,Uncle}", "descendent{Old'Pa,Uncle}", "niece{Uncle,Girl}", "nephew{Uncle,Boy}", "son{Old'Pa,Uncle}", "uncle{Girl,Uncle}", "uncle{Boy,Uncle}", "firstCousin{Girl,Cousin}", "firstCousin{Boy,Cousin}", "firstCousin{Cousin,Girl}", "firstCousin{Cousin,Boy}", "ancestor{Cousin,Uncle}", "ancestor{Cousin,Old'Pa}", "father{Cousin,Uncle}", "child{Uncle,Cousin}", "grandparent{Cousin,Old'Pa}", "uncle{Cousin,Daddy}", "descendent{Uncle,Cousin}", "descendent{Old'Pa,Cousin}", "aunt{Cousin,Mummy}", "grandchild{Old'Pa,Cousin}", "cousin{Cousin,Girl}", "cousin{Cousin,Boy}", "cousin{Girl,Cousin}", "cousin{Boy,Cousin}", "grandfather{Cousin,Old'Pa}", "daughter{Uncle,Cousin}", "granddaughter{Cousin,Old'Pa}", "niece{Daddy,Cousin}" }; NewFactEvent henf = new NewFactEvent(HandleExpectedNewFact); ie.NewFactHandler += henf; ie.LoadRuleBase(NewGedcomAdapter()); Individual male = new Individual("M"); Individual female = new Individual("F"); Individual happyFamily = new Individual("Happy"); Individual daddy = new Individual("Daddy"); Individual mummy = new Individual("Mummy"); Individual girl = new Individual("Girl"); Individual boy = new Individual("Boy"); ie.Assert(new Fact("sex", daddy, male)); ie.Assert(new Fact("sex", mummy, female)); ie.Assert(new Fact("sex", girl, female)); ie.Assert(new Fact("sex", boy, male)); ie.Assert(new Fact("spouseIn", daddy, happyFamily)); ie.Assert(new Fact("spouseIn", mummy, happyFamily)); ie.Assert(new Fact("childIn", girl, happyFamily)); ie.Assert(new Fact("childIn", boy, happyFamily)); Process(); Assert.AreEqual(32, deducted, "(1) Deducted"); Assert.IsFalse(wrongDeduction, "(1) Deductions OK"); Individual oldpa = new Individual("Old'Pa"); ie.Assert(new Fact("sex", oldpa, male)); ie.Assert(new Fact("parent", daddy, oldpa)); Process(); Assert.AreEqual(17, deducted, "(2) Deducted"); Assert.IsFalse(wrongDeduction, "(2) Deductions OK"); Individual uncle = new Individual("Uncle"); ie.Assert(new Fact("sex", uncle, male)); ie.Assert(new Fact("parent", uncle, oldpa)); ie.Assert(new Fact("sibling", uncle, daddy)); Process(); Assert.AreEqual(12, deducted, "(3) Deducted"); Assert.IsFalse(wrongDeduction, "(3) Deductions OK"); Individual cousin = new Individual("Cousin"); ie.Assert(new Fact("sex", cousin, female)); ie.Assert(new Fact("parent", cousin, uncle)); Process(); Assert.AreEqual(22, deducted, "(4) Deducted"); Assert.IsFalse(wrongDeduction, "(4) Deductions OK"); ie.NewFactHandler -= henf; deductionsToCheck = null; }
/// <summary> /// Creates a new Fact. /// </summary> /// <remarks> /// This method is an helper of the regular Fact instantiation. /// </remarks> /// <param name="type">The Type of the new Fact to assert.</param> /// <param name="individuals">The Array of Individual predicates or the Individual predicate that the Fact will contain.</param> /// <returns>A new Fact of desired Type and individuals.</returns> public Fact NewFact(string type, object individuals) { Fact newFact; if (individuals.GetType().IsArray) { Array individualsArray = (Array) individuals; Individual[] members = new Individual[individualsArray.Length]; for (int i=0; i<individualsArray.Length; i++) members[i] = new Individual(individualsArray.GetValue(i)); newFact = new Fact(type, members); } else newFact = new Fact(type, new Individual(individuals)); return newFact; }
protected override IPredicate BuildPredicate(XPathNavigator predicateElement, bool inHead, bool resolveImmediatly) { IPredicate predicate; string predicateName = predicateElement.Name; string predicateValue = predicateElement.Value; switch(predicateName) { // --------- IND predicates -------- case "ind": if (predicateValue.ToLower().StartsWith("expr:")) { if (inHead) { if (resolveImmediatly) predicate = new Individual(Compilation.Evaluate(predicateValue)); else predicate = new Formula(Formula.FormulaResolutionType.NxBRE, Binder, predicateValue); } else { predicate = new Function(Function.FunctionResolutionType.Binder, predicateValue, new ExpressionEvaluator(predicateValue), String.Empty, String.Empty); } } else if (predicateValue.ToLower().StartsWith("nxbre:")) { // NxBRE functions must follow this pattern: NxBRE:Function(uniqueargument) string[] split = predicateValue.Split(Parameter.PARENTHESIS); predicate = new Function(Function.FunctionResolutionType.NxBRE, predicateValue, null, split[0], split[1]); } else if (Binder == null) { predicate = new Individual(predicateValue); } else if ((inHead) && (predicateValue.ToLower().StartsWith("binder:"))) { predicate = new Formula(Formula.FormulaResolutionType.Binder, Binder, predicateValue); } else if ((inHead) && (predicateValue.EndsWith("()"))) { predicate = new Formula(Formula.FormulaResolutionType.Binder, Binder, predicateValue); } else { predicate = Binder.AnalyzeIndividualPredicate(new Individual(predicateValue)); } break; // --------- VAR predicates -------- case "var": predicate = new Variable(predicateValue); break; // --------- UNKNOWN predicates -------- default: throw new BREException("Unsupported predicate type: " + predicateName); } return predicate; }
public static Atom Populate(Atom targetAtom, ArrayList resultStack, bool evaluateFormulas) { IPredicate[] members = (IPredicate[])targetAtom.Members.Clone(); // populate the variable elements with predicate values coming // from the query part of the implication foreach(ResultPocket rp in resultStack) if (!(rp.fact is FactBase.NegativeFact)) Fact.Populate(rp.fact, rp.source, members); // if there are formulas in the atom, resolve these expressions, passing // the variable values as arguments if (targetAtom.HasFormula) { if (evaluateFormulas) { // formulas must be evaluated and the results placed in individual predicates IDictionary arguments = new Hashtable(); foreach(ResultPocket rp in resultStack) { if (!(rp.fact is FactBase.NegativeFact)) { for(int i=0; i<rp.source.Members.Length; i++) { object sourcePredicateKey = null; if (rp.source.Members[i] is Variable) { sourcePredicateKey = rp.source.Members[i].Value; } else if (rp.source.SlotNames[i] != String.Empty) { sourcePredicateKey = rp.source.SlotNames[i]; } if ((sourcePredicateKey != null) && (!arguments.Contains(sourcePredicateKey))) arguments.Add(sourcePredicateKey, rp.fact.Members[i].Value); } } } for(int i=0; i<members.Length; i++) if (members[i] is Formula) members[i] = new Individual(((Formula) members[i]).Evaluate(arguments)); } else { // formulas must be replaced by variables named after the position of the predicate for(int i=0; i<members.Length; i++) if (members[i] is Formula) members[i] = new Variable(i.ToString()); } } // clone the target with new members, because atom is immutable return targetAtom.CloneWithNewMembers(members); }
public void Predicates() { IPredicate v1 = new Variable("one"); IPredicate v2 = new Variable("two"); IPredicate i1 = new Individual("one"); IPredicate i2 = new Individual("two"); Assert.AreEqual(v1, new Variable("one"), "Similar Variables"); Assert.IsFalse(v1.Equals(v2), "Different Variables"); Assert.IsFalse(v1.Equals(i2), "Variable differs from Individual"); Assert.AreEqual(i1, new Individual("one"), "Similar Individuals"); Assert.IsFalse(i1.Equals(i2), "Different Variables"); Assert.IsFalse(i2.Equals(v1), "Individual differs from Variable"); }
private Atom GetAtom(XPathNavigator atom, bool negative, bool inHead, bool resolveImmediatly) { ArrayList relationPredicates; XPathNodeIterator rel; XPathNodeIterator predicates; relationPredicates = new ArrayList(); rel = atom.Select(GetXPathExpression("dl:_opr/dl:rel")); rel.MoveNext(); String atomRelation = rel.Current.Value; predicates = atom.Select(GetXPathExpression("dl:ind | dl:var")); while(predicates.MoveNext()) { IPredicate predicate; string predicateValue = predicates.Current.Value; if (predicates.Current.Name == "ind") { if (predicateValue.ToLower().StartsWith("expr:")) { if (inHead) { if (resolveImmediatly) predicate = new Individual(Compilation.Evaluate(predicateValue)); else predicate = new Formula(Formula.FormulaResolutionType.NxBRE, Binder, predicateValue); } else { predicate = new Function(Function.FunctionResolutionType.Binder, predicateValue, new ExpressionEvaluator(predicateValue), String.Empty, String.Empty); } } else if (predicateValue.ToLower().StartsWith("nxbre:")) { // NxBRE functions must follow this pattern: NxBRE:Function(uniqueargument) string[] split = predicateValue.Split(Parameter.PARENTHESIS); predicate = new Function(Function.FunctionResolutionType.NxBRE, predicateValue, null, split[0], split[1]); } else if (Binder == null) predicate = new Individual(predicateValue); else if ((inHead) && ((predicateValue.ToLower().StartsWith("binder:")) || (predicateValue.EndsWith("()")))) predicate = new Formula(Formula.FormulaResolutionType.Binder, Binder, predicateValue); else predicate = Binder.AnalyzeIndividualPredicate(new Individual(predicateValue)); } else if (predicates.Current.Name == "var") { predicate = new Variable(predicateValue); } else throw new BREException("Unsupported predicate type: " + predicates.Current.Name); relationPredicates.Add(predicate); } // build the array of predicates IPredicate[] predicatesArray = (IPredicate[])relationPredicates.ToArray(typeof(IPredicate)); // identify function based atom relations AtomFunction.RelationResolutionType resolutionType = AtomFunction.RelationResolutionType.None; if (atomRelation.ToLower().StartsWith("nxbre:")) resolutionType = AtomFunction.RelationResolutionType.NxBRE; else if ((atomRelation.ToLower().StartsWith("binder:")) || (atomRelation.EndsWith("()"))) resolutionType = AtomFunction.RelationResolutionType.Binder; else if (atomRelation.ToLower().StartsWith("expr:")) resolutionType = AtomFunction.RelationResolutionType.Expression; if ((resolutionType == AtomFunction.RelationResolutionType.NxBRE) || (resolutionType == AtomFunction.RelationResolutionType.Binder)) return new AtomFunction(resolutionType, negative, Binder, atomRelation, predicatesArray); else if (resolutionType == AtomFunction.RelationResolutionType.Expression) return new AtomFunction(resolutionType, negative, new ExpressionRelater(atomRelation, predicatesArray), atomRelation, predicatesArray); else return new Atom(negative, atomRelation, predicatesArray); }