private void PrintQueryResult(QueryResult queryResult) { var args = queryResult.TheQuery.Arguments.Select(arg => arg.Name).ToArray(); view.PrintOutput(Colors.DimGray, "> "); view.PrintOutput(Colors.LightGray, string.Format("{0}({1})?\n", queryResult.TheQuery.Name, string.Join(", ", args))); if (queryResult.Solutions != null && (queryResult.Solutions.Any() == queryResult.Result)) { if (queryResult.Solutions.Any()) { var c = queryResult.Solutions.Count; view.PrintOutput(Colors.DimGray, string.Format(" {0} решени{1}\n", c, c == 1 ? "е" : (c < 5 ? "я" : "й"))); foreach (var solution in queryResult.Solutions) { view.PrintOutput(SyntaxColors.Atom, " "); foreach (var atom in solution.Keys) { var value = solution[atom]; view.PrintOutput(SyntaxColors.Atom, string.Format("{0}", atom)); view.PrintOutput(Colors.White, string.Format(" = {0}{1}", value, atom == solution.Keys.Last() ? "" : ", ")); } view.PrintOutput(Colors.White, "\n"); } } else { view.PrintOutput(Colors.LightCoral, " Решений нет\n"); } } else { if (queryResult.Result) { view.PrintOutput(Colors.LightGreen, " Истина\n"); } else { view.PrintOutput(Colors.LightCoral, " Ложь\n"); } } }
private static QueryResult ApplyLogicalOperator(QueryResult v1, ConditionOperator? @operator, QueryResult v2) { if (v1 == null) { return v2; } if (@operator == ConditionOperator.And) { IEnumerable<Dictionary<string, string>> solutions; bool includeSolutions = true; if (v1.Solutions != null) { if (v2.Solutions != null) { var v2Solutions = new List<string>(); v2.Solutions.ForEach(solution => v2Solutions.Add(Stringify(solution))); solutions = v1.Solutions.Where(s => v2Solutions.Contains(Stringify(s))); } else { solutions = v1.Solutions; } } else { if (v2.Solutions != null) { solutions = v2.Solutions; } else { includeSolutions = false; solutions = new List<Dictionary<string, string>>(); } } if (includeSolutions) { var solutionList = solutions.ToList(); return new QueryResult(solutionList.Any(), v2.TheQuery, solutionList); } return new QueryResult(v1.Result & v2.Result, v2.TheQuery); } if (v1.Result) return v1; if (v2.Result) return v2; return new QueryResult(false, v2.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)); }
private static QueryResult AddToCacheAndReturn(Query query, QueryResult result) { _cache[query] = result; return result; }