Реализация экспертной системы на языке
Рефераты >> Программирование и компьютеры >> Реализация экспертной системы на языке

not сообщено(Н, _), % вопроса не было

спроси(Н).

запрашиваемая(Н): - Факт : признак(Н).

спроси(Н): - nl, write(Н), write ('?'), % вопрос

read(О), ответ(Н, О).

ответ(Н, да): - assert(сообщено(Н, да)),! % добавить в БД

ответ(Н, по): - assert(сообщено(Н, нет)),!, fail. ответ

ответ(Н, _): - write ('правильный ответ: да, нет'), спроси(Н). % повторить вопрос

Вызов метаинтерпретатора с целью проверки всех гипотез выполняется следующим образом:

/* ЭС для решения задами диагностики */

инициализация: - retractall(сообщено( _,_)).

диагностика(Н):- инициализация, Факт: причина(Н), найти(Н).

Дальнейшее совершенствование разработанной программы связано с включением возможности ответов на вопросы типа "почему?" и "как?". Возможный сценарий диалога с ЗС при ответе на вопрос "почему?" приведен в таблице 7.1.

Таблица 7.1 - Ответы на вопросы "почему?"

Вопрос или ответ системы

Ответ или вопрос пользователя

лампа(светится)?

плита(холодная)?

пытаюсь доказать тока(нет) с помощью правила: правило 4

плита(холодная)?

питаюсь доказать выключатель(не_включен) с помощью правила: правило 2

плита(холодная)?

Моя гипотеза: выключатель(не_включен)

плита(холодная)?

Вы задаете слишком много вопросов

Плита(холодная)?

нет

почему

почему

почему

почему

да

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

найти(Н, [Н]).

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

/* вариант2*/

найти(Н, Стек)-Факт: Н.

найти(Н, Стек): - Правило: если Н1 то Н, найти(Н1, [Правило | Стек]). Стек)

найти(Н1 и Н2, Стек): - найти(Н1, Стек), найти(Н2, Стек).

найти(Н, Стек): запрашиваемая(Н), сообщено(Н, да).

найти(Н, Стек): запрашиваемая(Н), not сообщено(Н, _ ), спроси(Н, Стек)

В связи с необходимостью ввода вопроса "почему?" в предикаты спроси и ответ добавляется дополнительный аргумент:

спроси(Н, Стек): - nl, write (Н), write ('?'), read (О), ответ(Н, О, Стек).

ответ(Н, да, Стек): - assert (сообщено(Н, да)), !.

ответ(Н, нет, Стек): - assert (сообщено(Н, нет)), !.

ответ(Н, почему, [ ]): - !, nl, write ('Вы задаете слишком много вопросов'), спроси(Н, []).

ответ(Н, почему, [Н]): - !, nl, write ('моя гипотеза :'), write (Н), спроси(Н, [ ]).

ответ(Н, почему, [Правило | Стек]): - !, Правило : если Н1 то Н, nl, write('пытаюсь доказать'), write (Н), nl, write('с помощью правила : '), write (Правило), спроси(Н, Стек).

ответ(Н, _ , Стек): - write('правильный ответ : да, нет, почему'), спроси(Н, Стек).

Формирование ответа на вопрос "как?" требует дополнительных изменений предиката найти. При ответе на вопрос "как?" система должна, по сути, построить дерево вывода. Например, если пользователя интересует, как была подтверждена гипотеза выключатель(не_включен), то система должна обеспечить отображение дерева вывода, изображенного на рисунке 3.

Такое дерево можно представить в форме вложенных правил, условия и заключения которых конкретизированы:

правило 2 : если правило 4 : если сообщено(плита(холодная)) и сообщено (лампа(не_светится)) то тока(нет) то выключатель(не_включен).

Рисунок 3 - Дерево вывода

Пусть Д обозначает дерево вывода целевого утверждения Н. Тогда построение дерева вывода выполним на основе следующих правил:

  1. если сообщено(Н), то Д = сообщено(Н);
  2. если имеется Факт : Н, то Д = Факт : Н;
  3. если имеется правило Правило : если Н1 то Н, и если Д1 - дерево вывода для Н1, то Д = Правило : если Д1 то Н;
  4. если доказывается гипотеза Н = Н1 и Н2, то дерево вывода Д = Дерево1 и Дерево2, где Дерево1 - дерево вывода гипотезы Н1, а Дерево2 - гипотезы Н2.

Переопределим предикат найти, добавив третий аргумент, представляющий дерево вывода:

найти(Н, Стек, Дерево).

Воспользовавшись введенными выше правилами построения дерева вывода, получим:

/* правило 1 */

найти(Н, Стек, сообщено(Н)):- сообщено(Н, да).

найти(Н, Стек, сообщено(Н)):- запрашиваемая(Н), not сообщено(Н, _), спроси(Н, Стек).

/* правило 2 */ найти(Н, Стек, Факт : Н):- Факт : Н.

/* правило З */ найти(Н, Стек, Правило : если Д1 то Н):- Правило : если Н1 то Н, найти [Правило\Стек,], Д1

/* правило4 */

найти (Н1 й Н2, Стек, Дерево 1 и Дерево 2):-

найти (Н1, Стек, Дерево 1), найти(Н2, Стек, Дерево2).

Теперь можно будет выяснять у системы, как было получено то или иное заключение. Чтобы реализовать эту возможность, введем предикат как(Н, Дерево), где Н - интересующее пользователя заключение, а Дерево - дерево вывода заключения, формируемое предикатом найти. Определяя предикат как(Н, Дерево), учтем два случая:

% Дерево можно построить как(Н, Дерево):- как1(Н, Дерево),!.

% Дерево нельзя построить как(Н, _}:- nl, write(Н), write ( 'не доказано').

Здесь предикат как1(Н, Дерево) определяется с помощью правил, аналогичных правилам, используемых в определении предиката найти:

как1(Н, сообщено(Н)):-!, nl, write (Н), write ('было введено'). /* правило1 */

как1(Н, Факт : Н):-!, nl, write (Н), write ( 'является фактом'), write (Факт). /* правило2 */

как1(Н, Правило : если _ то Н):- !, nl, write (Н), write ( 'было доказано с помощью'),

Правило : если Н1 то Н, отобрази_правило(Правило : если Н1 то Н). /*правилоЗ */


Страница: