/// <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> /// 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 Individual predicatesthat the Fact will contain.</param> /// <returns>A new Fact of desired Type and individuals.</returns> public Fact NewFact(string type, params object[] individuals) { Fact newFact; if (individuals.Length == 0) { newFact = new Fact(type); } else if (individuals.Length == 1) { newFact = new Fact(type, new Individual(individuals[0])); } else { Individual[] members = new Individual[individuals.Length]; for (int i=0; i<individuals.Length; i++) members[i] = new Individual(individuals[i]); newFact = new Fact(type, members); } 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) ObjectPair operatorCall = Parameter.ParseOperatorCall(predicateValue); predicate = new Function(Function.FunctionResolutionType.NxBRE, predicateValue, null, (string)operatorCall.First, (string)operatorCall.Second); } 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; }
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) ObjectPair operatorCall = Parameter.ParseOperatorCall(predicateValue); predicate = new Function(Function.FunctionResolutionType.NxBRE, predicateValue, null, (string)operatorCall.First, (string)operatorCall.Second); 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(Xml.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; }
private int RunImplication(Implication implication) { int implicationResultsCount = 0; IList<IList<FactBase.PositiveMatchResult>> processResults = WM.FB.ProcessAtomGroup(implication.AtomGroup); if (implication.Action == ImplicationAction.Count) { if (Logger.IsInferenceEngineVerbose) Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "Counting Implication '" + implication.Label + "' counted: " + processResults.Count); 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 ((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)) { if (exposeEventContext) { NewFactHandler(new NewFactEventArgs(deductedFact, EventContextFactory.NewEventContext(processResults, implication))); } else { NewFactHandler(new NewFactEventArgs(deductedFact)); } } if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, (result?"Asserted":"Ignored Assertion of ") + " Fact: " + deductedFact.ToString()); } } 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(IList<FactBase.PositiveMatchResult> 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)) { if (exposeEventContext) { DeleteFactHandler(new NewFactEventArgs(deductedFact, EventContextFactory.NewEventContext(processResult, implication))); } else { DeleteFactHandler(new NewFactEventArgs(deductedFact)); } } if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, (result?"Retracted":"Ignored Retraction of ") + " Fact: " + deductedFact.ToString()); } } else { // asserting implication factbase action bool result = WM.FB.Assert(deductedFact); if ((result) && (NewFactHandler != null)) { if (exposeEventContext) { NewFactHandler(new NewFactEventArgs(deductedFact, EventContextFactory.NewEventContext(processResult, implication))); } else { NewFactHandler(new NewFactEventArgs(deductedFact)); } } if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, (result?"Asserted":"Ignored Assertion of ") + " Fact: " + deductedFact.ToString()); } } } } } else if (implication.Action == ImplicationAction.Modify) { foreach(IList<FactBase.PositiveMatchResult> 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 (Logger.IsInferenceEngineVerbose) Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "Modifying Implication '" + implication.Label + "' will target matches of: " + modificationTargetLookup); foreach(Fact factToModify in FactBase.ExtractAllFacts(WM.FB.ProcessAtomGroup(new AtomGroup(AtomGroup.LogicalOperator.And, modificationTargetLookup)))) { if (Logger.IsInferenceEngineVerbose) Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "-> found target: " + factToModify); // for each fact, perform the modification Fact deductedFact = BuildFact(implication.Deduction, FactBase.EnrichResults(processResult, modificationTargetLookup, factToModify)); if (Logger.IsInferenceEngineVerbose) Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "-> modified target: " + deductedFact); if ((deductedFact != null) && (!factToModify.Equals(deductedFact))) { implicationResultsCount++; bool result = WM.FB.Modify(factToModify, deductedFact); if ((result) && (ModifyFactHandler != null)) { if (exposeEventContext) { ModifyFactHandler(new NewFactEventArgs(factToModify, deductedFact, EventContextFactory.NewEventContext(processResult, implication))); } else { ModifyFactHandler(new NewFactEventArgs(factToModify, deductedFact)); } } if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, (result?"Modified":"Ignored Modification of ") + " Fact: " + factToModify.ToString()); } } } } } else { throw new BREException("Implication action not supported: " + implication.Action); } return implicationResultsCount; }
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> /// 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> internal 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); }
/* Atom Utils */ /// <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> internal static Atom ResolveFunctions(Atom atom) { if (atom.HasFunction) { IPredicate[] predicates = new IPredicate[atom.Members.Length]; for(int i=0; i<atom.Members.Length; i++) if (atom.Members[i] is Function) predicates[i] = new Individual(atom.Members[i].ToString()); else predicates[i] = atom.Members[i]; return new Atom(atom.Negative, atom.Type, predicates); } else return (Atom)atom.Clone(); }
/// <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) { try { 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); } catch (Exception ex) { // Chuck Cross added try/catch block with addtional info in new thrown exception StringBuilder sb = new StringBuilder("Error evaluating formula ") .Append(this) .Append(".\r\n Arguments:"); foreach(string argument in arguments) sb.Append(" ").Append(argument==null?"Null":argument).Append("\r\n"); throw new BREException(sb.ToString(), ex); } }
/// <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; }
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"); }