Выбрать главу

class PatternMatchingKnowledgeSource : public WordKnowledgeSource { public: ... protected:

static BoundedCollection<Word*> words; REPatternMatching patternMatcher;

};

Все экземпляры этого класса разделяют общий словарь, но каждый из них может иметь собственного агента для сравнения с шаблонами.

На данном этапе проектирования подробности реализации этого класса для нас не существенны, поэтому мы не будем на них подробно останавливаться.

Определим теперь подклассы класса StringKnowledgeSource следующим образом:

class CommonPrefixKnowledgeSource : public StringKnowledgeSource ... class CommonSuffixKnowledgeSource : public StringKnowledgeSource ... class DoubleLetterKnowledgeSource : public StringKnowledgeSource ... class LegalStringKnowledgeSource : public StringKnowledgeSource ...

Наконец, определим подклассы класса LetterKnowledgeSource:

class DirectSubstitutionKnowledgeSource : public LetterKnowledgeSource ... class VowelKnowledgeSource : public LetterKnowledgeSource ... class ConsonantKnowledgeSource : public LetterKnowledgeSource ... class LetterFrequencyKnowledgeSource : public LetterKnowledgeSource ...

Общее в источниках знаний. Анализ показал, что только две операции определены для всех упомянутых специализированных классов:

Reset - Перезапуск источника знаний.

evaluate - Определение состояния информационной доски.

Причина упрощения интерфейса - в относительной автономности знаний: мы указываем на интересующий объект информационной доски и даем источнику команду применить его правила, учитывая глобальное состояние доски. При выполнении правил каждый из источников знаний может осуществлять следующие действия:

• Высказать предположение о подстановке.

• Найти противоречие в ранее предложенных подстановках и откатить их.

• Высказать утверждение о подстановке.

• Сообщить контроллеру о своем желании записать на доску что-то интересное.

Все эти действия являются общими для всех источников знаний. Перечисленные операции образуют механизм вывода заключений. Определим механизм вывода (InferenceEngine) как объект, который выполняет известные правила для того, чтобы либо найти новые правила (прямая последовательность рассуждений), либо доказать некоторую гипотезу (обратная последовательность рассуждений). На основании сказанного введем следующий класс:

class InferenceEngine { public:

InferenceEngine(<DynamicSet<Rules*>);

... };

Конструктор класса создает экземпляр объекта и населяет его правилами. Лишь одна операция сделана в этом классе видимой для источников знании:

evaluate - Выполнить правило механизма вывода.

Теперь о том, как сотрудничают источники знаний: каждый специализированный источник определяет свои собственные правила и возлагает ответственность за их выполнение на класс InferenceEngine. Точнее, операция KnowledgeSource::evaluate вызывает метод InferenceEngine::evaluate, что приводит к выполнению одной из четырех упомянутых выше операций. На рис. 11-4 показан сценарий такого взаимодействия:  

Рис. 11-4. Взаимодействия с источником знаний.

Что такое правило? Для иллюстрации приведем (в формате Lisp) правило, касающееся знаний об общеупотребительных суффиксах:

((* I ? ?) (* I N G) (* I E S) (* I E D))

Это правило означает, что заданному шаблону *I?? (условие - antecedent) могут соответствовать суффиксы ING, IES и IED (заключение - consequent). В C++ можно определить следующий класс для представления правил:

class Rule { public: ...

int bind(String<char>& antecedent, String<char>& consequent); int remove(Strlng<char>& antecedent); int remove(String<char>t antecedent, String<char>& conseiruent); int hasConflict(const String<char>& antecedent) const;

protected:

String<char> antecedent; List<String<char>> consequents;

};

Смысл приведенных операций полностью понятен из их наименований. Мы здесь повторно использовали некоторые классы из главы 9.

С точки зрения строения данного класса можно утверждать, что источники знаний являются разновидностью механизма вывода. Кроме того, они ассоциированы с объектами доски, поскольку находят там приложение своим усилиям. Наконец, каждый источник знаний связан с контроллером и посылает ему свои соображения. Контроллер, в свою очередь, может активизировать источники знаний.

Выразим все сказанное следующим образом:

class KnowledgeSource : public InferenceEngine, public Dependent  { public:

KnowledgeSource(Blackboard*, Controller*); void reset(); void evaluate();

protected:

Blackboard* blackboard; Controller* controller; UnboundedOrderedCollection<Assumption*> pastAssumptions;