} //ProcessOr /// <summary> /// Processes an atom. /// </summary> /// <param name="atomToRun"></param> /// <param name="excludedFacts"></param> /// <returns></returns> private IEnumerator <Fact> ProcessAtom(Atom atomToRun, IList <Fact> excludedFacts) { if (atomToRun is AtomFunction) { // an atom function is either positive or negative, it does not return any fact // if this atom function is wrapped in naf, then the base result is negated, // leading to a positive result if the underlying function is negative! if (((AtomFunction)atomToRun).PositiveRelation != atomToRun.Negative) { return(FactEnumeratorFactory.NewSingleFactEnumerator(NAF)); } } else { if (atomToRun.Negative) { // a negative atom, fails if any matching fact is found // and succeed if no data collection (ie returns one dummy fact as a token) // if no facts are actually found // Bug #1332214 pinpointed that excludedFacts should not be applied on Negative atoms IEnumerator matchResult = Select(atomToRun, null); if ((matchResult == null) || (!matchResult.MoveNext())) { return(FactEnumeratorFactory.NewSingleFactEnumerator(NAF)); } } else { return(Select(atomToRun, excludedFacts)); } } return(null); }
/// <summary> /// Gets a list of facts matching a particular atom. /// </summary> /// <param name="filter">The atom to match</param> /// <param name="excludedFacts">A list of facts not to return, or null</param> /// <returns>An IList containing the matching facts (empty if no match, but never null).</returns> public IEnumerator <Fact> Select(Atom filter, IList <Fact> excludedFacts) { if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "FactBase.Select: " + filter + " - Excluding: " + Misc.IListToString((IList)excludedFacts)); } // if the predicate map does not contain an entry for the filter signature or if this entry is empty, return empty result if ((!predicateMap.ContainsKey(filter.Signature)) || (predicateMap[filter.Signature].Count == 0)) { if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "No fact matching signature: " + filter.Signature); } return(EMPTY_SELECT_RESULT.GetEnumerator()); } // if the filter contains only variables, everything should be returned if (filter.OnlyVariables) { if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "Filter with no Ind or Fun -> Return all facts matching signature: " + filter.Signature); } return(FactEnumeratorFactory.NewFactListExcludingEnumerator(signatureMap[filter.Signature], excludedFacts)); } // we build result lists and will reduce the biggest ones from the smallest ones ICollection <Fact> resultList = null; int smallestList = Int32.MaxValue; int positionOfSmallestList = -1; for (int position = 0; position < filter.Members.Length; position++) { if (filter.Members[position] is Individual) { bool matched = false; object predicateValue = filter.Members[position].Value; IDictionary <object, IDictionary <int, ICollection <Fact> > > predicateValueMap; if (predicateMap[filter.Signature].TryGetValue(predicateValue.GetType(), out predicateValueMap)) { IDictionary <int, ICollection <Fact> > predicatePositionMap; if (predicateValueMap.TryGetValue(predicateValue, out predicatePositionMap)) { if ((predicatePositionMap.ContainsKey(position)) && (predicatePositionMap[position].Count > 0)) { if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "Matched predicateValue: " + predicateValue + " [" + predicateValue.GetType() + "]"); } if (predicatePositionMap[position].Count < smallestList) { resultList = predicatePositionMap[position]; smallestList = predicatePositionMap[position].Count; positionOfSmallestList = position; if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "Smallest list of size: " + smallestList + " at position: " + positionOfSmallestList); } } matched = true; } } } // no match found on a particular individual predicate? early return an empty result! if (!matched) { if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "No match -> Return no fact"); } return(EMPTY_SELECT_RESULT.GetEnumerator()); } } } // only one predicate in the filter and we matched it, no need for post matching, return filtered results directly if ((filter.Members.Length == 1) && (resultList != null)) { if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "One member filter and got resultList -> Return facts immediatly"); } return(FactEnumeratorFactory.NewFactListExcludingEnumerator(resultList, excludedFacts)); } // we have not been able to match anything (the filter might contain only variables or functions), // let's load all the facts matching the signature of the filter if (resultList == null) { resultList = signatureMap[filter.Signature]; if (Logger.IsInferenceEngineVerbose) { Logger.InferenceEngineSource.TraceEvent(TraceEventType.Verbose, 0, "No resultList -> Used the list matching the signature, which contains: " + resultList.Count); } } // we append a fact as a result only if it matches the filter predicates // if a predicate has been previously matched, we do not compare it again in the matching process: we add its position // to the ignore list IList <int> ignoredPredicates = null; if (positionOfSmallestList != -1) { ignoredPredicates = new List <int>(); ignoredPredicates.Add(positionOfSmallestList); } return(FactEnumeratorFactory.NewFactListPredicateMatchingEnumerator(resultList, filter, strictTyping, ignoredPredicates, excludedFacts)); }