Beispiel #1
0
 public QueryResult(bool result, Query theQuery, List<Dictionary<string, string>> solutions)
 {
     Result = result;
     TheQuery = theQuery;
     Solutions = solutions;
 }
Beispiel #2
0
 public QueryResult(bool result, Query theQuery)
 {
     Result = result;
     TheQuery = theQuery;
 }
Beispiel #3
0
        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));
        }
Beispiel #4
0
 protected bool Equals(Query other)
 {
     return Name == other.Name
            &&
            Arguments.SequenceEqual(other.Arguments);
 }
Beispiel #5
0
 private static QueryResult AddToCacheAndReturn(Query query, QueryResult result)
 {
     _cache[query] = result;
     return result;
 }