public QueryResult(bool result, Query theQuery, List<Dictionary<string, string>> solutions) { Result = result; TheQuery = theQuery; Solutions = solutions; }
public QueryResult(bool result, Query theQuery) { Result = result; TheQuery = theQuery; }
private static QueryResult ResolveQuery(Query query) { if (_cache.ContainsKey(query)) { if (_cache[query] == null) { if (query.HasAtoms) { _cache[query] = new QueryResult(false, query, new List<Dictionary<string, string>>()); } else { _cache[query] = new QueryResult(false, query); } } return _cache[query]; } _cache.Add(query, null); if (!query.HasAtoms) // Если нет атомов, то запрос простой (возвращает true или false) { // Попытка 1: // Ищем факт с именем запроса // И таким же набором аргументов (порядок важен) if (_facts.Any(fact => fact.Name == query.Name && fact.Arguments.SequenceEqual(query.Arguments))) { return AddToCacheAndReturn(query, new QueryResult(true, query)); } // Попытка 2: // Найти все правила с именем запроса // И аналогичным количеством аргументов var matchingRules = _rules.FindAll(rule => rule.Name == query.Name && rule.Arguments.Count == query.Arguments.Count); // Если есть такие правила, то играем в дедукцию // Подставляем каждому правилу вместо атомов аргументы запроса // И рекурсивно вычисляем каждое условие if (matchingRules.Any()) { foreach (var rule in matchingRules) { QueryResult finalResult = null; foreach (var condition in rule.Conditions) { // Подставляем вместо атомов аргументы запроса var conditionArgs = ReplaceAtomsWithNames(rule.Arguments, query.Arguments, condition.Condition.Arguments); // Вычисляем значение запроса var conditionQuery = new Query(condition.Condition.Name, conditionArgs); QueryResult queryResult; if (_cache.ContainsKey(conditionQuery)) { if (_cache[query] == null) { return AddToCacheAndReturn(query, new QueryResult(false, query)); } queryResult = _cache[query]; } else { queryResult = ResolveQuery(conditionQuery); } if (condition.Condition.IsNegated) { if (queryResult.Solutions != null) { queryResult = new QueryResult(!queryResult.Result, queryResult.TheQuery, queryResult.Solutions); } else { queryResult = new QueryResult(!queryResult.Result, queryResult.TheQuery); } } // Применяем логический оператор finalResult = ApplyLogicalOperator(finalResult, condition.Operator, queryResult); } if (finalResult != null && finalResult.Result) { return AddToCacheAndReturn(query, new QueryResult(finalResult.Result, query)); } } } // Попытка 3: // Не помогла дедукция -- не беда, пробуем индукцию // Ищем все правила, в которых наш запрос содержится в качестве условия var containingRules = _rules.Where(rule => rule.Conditions.Any(cnd => cnd.Condition.Name == query.Name && cnd.Condition.Arguments.Count == query.Arguments.Count)) // Отсеиваем правила, которые содержат условия с оператором ИЛИ .Where(rule => rule.Conditions.All(cnd => cnd.Operator != ConditionOperator.Or)); foreach (var rule in containingRules) { foreach (var condition in rule.Conditions) { if (condition.Condition.Name == query.Name && condition.Condition.Arguments.Count == query.Arguments.Count) { if (CompareArgumentsIgnoringAtoms(condition.Condition.Arguments, query.Arguments)) { var nextQuery = new Query(rule.Name, ReplaceAtomsWithNames(condition.Condition.Arguments, query.Arguments, rule.Arguments)); QueryResult result; if (_cache.ContainsKey(nextQuery)) { if (_cache[nextQuery] == null) { return AddToCacheAndReturn(query, new QueryResult(false, query)); } result = _cache[nextQuery]; } else { result = ResolveQuery(nextQuery); } if (result.Result != condition.Condition.IsNegated) { return AddToCacheAndReturn(query, new QueryResult(true, query)); } } } } } } else // Атомы есть { var solutions = new List<Dictionary<string, string>>(); // Шаг 1: // Найти все факты с именем запроса и нужным количеством аргументов var matchingFacts = _facts.FindAll(fact => fact.Name == query.Name && fact.Arguments.Count == query.Arguments.Count) // И взять только те, у которых идентичны аргументы, не являющиеся атомами .Where(fact => CompareArgumentsIgnoringAtoms(query.Arguments, fact.Arguments)); foreach (var fact in matchingFacts) { solutions.Add(new Dictionary<string, string>()); for (var i = 0; i < query.Arguments.Count; i++) { var arg = query.Arguments.ElementAt(i); if (arg.IsAtom) { var solution = fact.Arguments.ElementAt(i); solutions.Last().Add(arg.Name, solution.Name); } } } /* Friends(X, Y) : Likes(X, Y) AND Knows(X, Y); Likes(Max, Jane); Knows(Max, Jane); Friends(X, Y)? */ // Шаг 2: // Пытаемся вычислить все правила с именем запроса var matchingRules = _rules.Where(rule => rule.Name == query.Name && rule.Arguments.Count == query.Arguments.Count); foreach (var rule in matchingRules) { var ruleQuery = new Query(rule.Name, ReplaceAtomsWithNames(rule.Arguments, query.Arguments, rule.Arguments)); var queryResult = ResolveQuery(ruleQuery); if (queryResult.Result) { solutions.Add(new Dictionary<string, string>()); for (var i = 0; i < query.Arguments.Count; i++) { var arg = query.Arguments.ElementAt(i); if (arg.IsAtom) { var solution = ruleQuery.Arguments.ElementAt(i); solutions.Last().Add(arg.Name, solution.Name); } } } } return AddToCacheAndReturn(query, new QueryResult(solutions.Any(), query, solutions)); } return AddToCacheAndReturn(query, new QueryResult(false, query)); }
protected bool Equals(Query other) { return Name == other.Name && Arguments.SequenceEqual(other.Arguments); }
private static QueryResult AddToCacheAndReturn(Query query, QueryResult result) { _cache[query] = result; return result; }