private List<Predicate> searchRules(Predicate quest) {
        // facts - полученные факты в данной функции
        List<Predicate> facts = new ArrayList<>();
        // tables - список таблиц для исходных предикатов каждого правила
        List<Table> tables = new ArrayList<>();
        for (Rule rule : knowledgeBase.getRules()) {
            // Если имя шаблонного предиката совпадает с именем целевого предиката,
            // то пробуем найти новые факты из этого правила
            if (quest.getName().equals(rule.getInference().getName())) {
                // для каждого исходного предиката формируем таблицу,
                // состоящую из всех возможных для него фактов
                for (Predicate cause : rule.getCauses()) {
                    // формируем промежуточный шаблонный предикат для исходного предиката
                    Predicate tempQuest = new Predicate(cause.getName(), cause.getAttributes().length);
                    // рекурсивно находим факты для исходного предиката и формируем таблицу                    
                    tables.add(new Table(searchPredicate(tempQuest), cause));            
                }
                
                // теперь надо отобрать подходящие по атрибутам факты
                // принимаем за основу самую первую таблицу
                Table resultTable = tables.get(0);
                // если таблиц несколько, то объединяем их (операция "JOIN")
                for (int i = 1; i < tables.size(); i++) {          
                    resultTable = resultTable.join(tables.get(i));
                }
                // находим проекцию объединения таблиц по атрибутам, заданным в целевом предикате
                resultTable = resultTable.projection(Arrays.asList(rule.getInference().getAttributes()));
                // преобразуем полученную таблицу в список предикатов и добавляем их в ответ
                facts.addAll(resultTable.toPredicates(rule.getInference().getName()));
            }
        }
        return facts;
    }