Усовершенствование процедуры useranswer

Один из недостатков первой версии процедуры useranswer, который проявился в приведенном выше диалоге, состоит в том, что сформированные системой Prolog имена переменных в выводе этой системы кажутся невыразительными. При отобра­жении диалога для пользователя символы типа 7 необходимо заменять некоторы­ми осмысленными словами.

Еще один, более серьезный недостаток этой версии процедуры useranswer состо­ит в следующем. Если в дальнейшем процедура useranswer будет применена для достижения аналогичной цели, то пользователю придется повторно вводить все те же сведения, что и раньше. Если этой экспертной системе в процессе формирования в ней рассуждений придется дважды проверить одну и ту же запрашиваемую цель, она будет раздражать пользователя, снова повторяя один и тот же диалог, а не используя информацию, предоставленную пользователем ранее.

Устраним эти два недостатка. Прежде всего, для усовершенствования внешнего вида запросов к пользователю можно предусмотреть некоторый стандартный формат для каждой запрашиваемой цели. Для этого достаточно добавить в отношение askable второй параметр, обозначающий этот формат, как показано в следующем примере: askable X eats Y, ' ' eats 'Something').

Затем при выдаче пользователю запроса каждую переменную в этом запросе необ­ходимо заменить ключевыми словами в указанном формате, например, следующим образом:

?- useranswer ( X eats Y, [], Answer). Is it true: Animal eats Something? yes.

Animal = peter. Something = meat. Answer = true X = peter Y = meat

В усовершенствованной версии процедуры useranswer, приведенной в листин­ге 16.4, такое форматирование запросов осуществляется с помощью процедуры format; Goal, ExternFormat, Question, VarsO, Variables)

где Goal - форматируемая цель, a ExternFormat задает внешний формат для Goal, который определен следующим образом: askable ( Goal, ExternFormat)

Далее, Question - это цель Goal, отформатированная в соответствии с форматом ExternFormat. Параметр Variables представляет собой список переменных, кото­рые появляются в цели Goal в сопровождении соответствующих им ключевых слов (как указано в формате ExternFormat), введенных в список VarsO, например, как показано ниже.


Глава 16.Командный интерпретатор экспертной системы



■1,,^ yives 1What' to '«horn',

Question, [], Variables!.

Question - 'Who' gives documents to "Whom1,

Variables = [X/'Who1, Y/'Whom'].

Листинг 16.4. Командный интерпретатор экспертной системы: процедура, которая запрашивает у пользователя необходимую информацию и отвечает на вопросы "why"

% Процедура

!

I useranswer! Goal, Trace, Answer)

%

% формирует с помощью перебора с возвратами решения, связанные с достижением % цели Goal, запрашивая у пользователя информацию.

s Trace - это цепочка родительски:- целей и правил, применяемая для формирования Ч объяснения необходимости затребованной информации

useranswert Goal, Trace, Answer) :-

askable; Goal, _ ) , % Цель, информацию о которой можно запросить

$ у пользователя freshcopy( Goal, Copy!, Переменные в цели Goal переименованы useranswer; Goal, Copy, Trace, Answer, 1) .

% He следует повторно задавать вопрос, касающийся уже конкретизированной цели

useranswer( Goal, _, _, _, N) :-

N > 1, * Вопрос должен Быть задан повторно?

instantiate( Goal),! , % В цели Goal переменные отсутствуют

fail.% Вопрос не следует задавать. повторно

* Можно ли предположить, что цель Goal является истинной или ложной 4 при всех конкреткзациях?

useranswer! Goal, Copy, _, Answer, _) :-wastold ' Copy, Answer, _) , instance_of( Copy, Goal) , !. Предполагаемый ответ Answer для цели Goal

i Выполнить выборку известных решений цели Goal, проиндексированных числами % от N и выше

useranswer,. Goal, _, _, true, H) :-wastcld; Goal, truerM),

:- Есть ли уже вся необходимая информация о цели Goal?

useranswerf Goal, Copy, _, Answer, _) :-end_answers : Copy} , ins-ance_c£ { Copy, Goal}, !, ;- Вся необходимая информация

ч о цели Goal уже имеется fail.

% Запросить у пользователя (дополнительные) решения

useranswerf Goal, _, Trace, Answer, к} :-

askuserf Goal, Trace, Answer, N) . askusert Goal, Trace, Answer, K) :-

askable( Goal, ExternFormat),

format ( Goal, ExternFormat, Question, Variables), .. Определить формат

% вопроса
ask I Goal, Question, Variables, Trace, Answer, H) .
ask( Goal, Question, Variables, Trace, Answer, H) :-
nl,
(Variables - [] , !,
wll'.<- ' 'Is it truer1) % Вывести запрос с приглашением



Часть II. Применение языка Prolog в области искусственного интеллекта


write( 'Any (more) solution to:') % Вывести запрос с приглашением

) ,

write ( Question) , write('? ' ) ,

getreply( Reply), !, % Ответ равен yes/no/why

process! Reply, Goal, Question, Variables, Trace, Answer, N) .

process( why, Goal, Question, Variables, Trace, Answer, N) :-showtrace ( Trace) , ask( Goal, Question, Variables, Trace, Answer, N) .

process) yes, Goal, _, Variables, Trace, true, N) :-

nextindex ( Next) , % Получить новый незанятый индекс для факта wastold
Nextl is Next + 1,
(askvars '.Variables) ,
assertz( wastold( Goal, true. Next)) % Внести решение в базу данных

freshcopyf Goal, Copy) , % Копия цели Goal

useranswer ( Goal, Copy, Trace, Answer, Nextl) % Есть еще ответы? ) .

process! no, Goal, _, _, _, false, N) :-freshcopy( Goal, Copy) ,

wastold ( Copy, true, _) , ! , % 'no' означает, что решений больше нет

assertzf end answers( Goal)), % Отметить конец списка решений

fail

nextindex ( Next) , % Следующий незанятый индекс для факта wastold

assertz { wastold( Goal, false, Next)) . % 'no' означает, что решений больше нет

format' Var, Name, Name, Vars, [Var/Name | Vars]) :-var ( Var) , ! .

format(Atom, Name, Atom, Vars, Vars) :-atomic( Atom) , !, atomic(Name).

format( Goal, Form, Question, VarsO, Vars) :-Goal =.. [Functor | Argsl], Form =.. [Functor | Forms],

formatall ( Argsl, Forms, Args2 , VarsO, Vars), Question =.. [Functor | Args2] .

formatall ( [] , [] , [] , Vars, Vars) .

formatall ( [X | XL], [F | FL], [Q | QL], VarsO, Vars) :-formatall( XL, FL, QL, VarsO, Varsl), formatt X, F, Q, Varsl, Vars).

askvars( [ ] ) .

askvars( [Variable/Name | Variables]) :-

nl, write ( Name) , write(' = '),

read( Variable) ,

askvars Variables) . showtrace( [ ] ) : -

nl, write ( 'This was your question'), nl. showtrace( [Goal by Rule | Trace]) :-

nl, write ( 'To investigate, by ' ) ,

write ( Rule) , write ( ' , ' ) ,

write ( Goal) ,

showtrace( Trace) . instantiate) Term) :-

nurabervars ( Term, 0, 0). % В терме Term переменные отсутствуют

Глава 16.Командный интерпретатор экспертной системы 373


instance of( Tl, T2>: T2 - экземпляр Tl; это означает, что терм Т1 является более обиим или столь же общим, как и Т2

instance of[ Terra, Terml) :- i Экземпляром терма Term является lentil

freshcopyt Terml, Term2), l Копия терка Terml с обновленным множеством

% переменных numbervars! Term2, 0, _), !,

Term = Term2. % Эта цель достигается успешно, если

I Terml - экземпляр терма Term freshcopyt Term, FreshTerm) :- % Создать копию терма Term с пе

% Создать копию терма Term с переименованными переменными

asserts copyt Term)),

retract ( copy! FreshTerm)}, !.

nextindext Next) :- Следующий незанятый индекс тя факта wastold

retract! lastindex( Last)), !, Next is Last + 1,

assert; lastindexf Next)),

% Инициализировать динамические процедуры lastindex/l, wastold/3, end_answers/i

:- assertz { lastindex(O)},

assertz! wastold ( dummy, false, 0)), assertz( end answers! dummy)).

Еще одно усовершенствование, которое позволило бы избежать повторных вопро­сов к пользователю, реализовать немного труднее. Прежде всего, для этого необходи­мо запоминать все ответы пользователя, чтобы можно было осуществить их выборку в некоторый последующий момент.Это можно обеспечить, внося в базу данных ответы пользователя как элементы некоторого отношения, например, следующим образом: assert( wastold! шагу gives documents to friends, true) ).

Но в той ситуации, когда пользователь предоставил несколько решений, относя­
щихся к одной и той же цели, в базу данных будет внесено несколько фактов, ка­
сающихся этой цели. В этом и состоит сложность. Предположим, что в разных мес­
тах в базе данных присутствует несколько вариантов одной и той же цели (причем
цель одна, а переменные в ней разные), например, как показано ниже.
(X has у} and % Первый экземпляр факта - Goall

Ш has У1) and % Второй экземпляр факта - Goal2

Кроме того, предположим, что пользователь запросил (с помощью перебора с воз­вратами) несколько решений для цели Goall. После этого процесс формирования рассуждений перешел к цели С-оа12. А поскольку уже имеются некоторые решения для Goall, то хотелось бы, чтобы система применяла их автоматически также и к цели Goai2 (поскольку они, безусловно, позволяют достичь и Goal2). Теперь предпо­ложим, что система пытается применить эти решения для Goal2, ко ни одно из них не позволяет больше достичь какой-либо иной цели. Поэтому система должна возвра­титься к GoaI2 и потребовать от пользователя дополнительные решения. Если поль­зователь предоставит дополнительные решения, их также нужно запомнить. В том случае, если система в дальнейшем вернется к цели Goall, то эти новые решения необходимо также автоматически применить к цели Goall.

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

wastold! Goal, Truthvalue, Index)

где Index — счетчик ответов, предоставленных пользователем. Процедура useranswer! Goal/ Trace, Answer)

374 Часть II.Применение языка Prolog в области искусственного интеллекта


должна следить за количеством решений, которые уже были выработаны с помощью перебора с возвратами. Такую задачу можно решить с использованием еще одной процедуры, useranswer, с четырьмя параметрами: useranswer( Goal, Trace, Answer, N)

где N - целое число. В вызове этой процедуры необходимо вырабатывать решения для цели Goal, проиндексированные целым числом N или большим числом. А вызов useranswer ( Goal, Trace, Answer)

предназначен для выработки всех решений для цели Goal. Решения индексируются целыми числами, начиная с 1, поэтому имеет место следующее отношение: useranswer ( Goal, Trace, Answer) :-useranswer ( Goal, Trace, Answer, 1).

Общая схема функционирования процедуры useranswer ( Goal, Trace, Answer, N)

состоит в том, что необходимо формировать решения для цели Goal, вначале осуще­ствляя выборку известных решений, проиндексированных числами от N и больше. После того как известные решения будут исчерпаны, нужно начать выдавать пользо­вателю запросы, касающиеся цели Goal, и вносить в базу данных полученные таким образом новые решения, проиндексированные должным образом последовательно возрастающими числами. После того как пользователь сообщит, что решений больше нет, внести в базу данных следующий факт: end_answers( Goal)

А если пользователь сразу же сообщит, что решений вообще не существует, то не­посредственно внести в базу данных такой факт: wastoldf Goal, false, Index)

При выборке решений процедура useranswer должна правильно интерпретиро­вать такую информацию.

Но есть еще одна сложность. Пользователь имеет также право задавать общие решения, оставляя некоторые переменные неконкретизированными. А если есть воз­можность осуществить выборку положительного решения, более общего или столь же общего, как Goal, то, безусловно, нет смысла продолжать задавать вопросы, касаю­щиеся Goal, если уже известно самое общее решение. Если же является истинным следующее высказывание: wastold( Goal, false, _) то должно быть принято аналогичное решение.

Все эти требования учтены в программе useranswer, приведенной в листин­ге 16.4. Введен еще один параметр, Сору (копия цели Goal), который используется в некоторых согласованиях вместо Goal, чтобы нельзя было уничтожить переменные в цели Goal. В этой программе применяются также два вспомогательных отношения. Одним из них является следующее: instantiated ( Term)

Это отношение принимает истинное значение, если терм Term не содержит пере­менных. Другим из них является instance_of( Term, Terml)

где Terml — экземпляр терма Term; это означает, что Term является, по меньшей мере, таким же общим, как Terml, например, как показано ниже. instance^of ( X gives information to Y, тагу gives information to Z) В этих двух процедурах используется еще одна процедура:

numbervars( Term, N, м)

Эта процедура "нумерует" переменные в терме Term, заменяя каждую перемен­ную в этом терме некоторым вновь сформированным термом таким образом, чтобы


Глава 16.Командный интерпретатор экспертной системы



эти "пронумерованные" термы соответствовали целым числам между от N до М-1. Например, предположим, что эти термы представлены в следующей форме: var/0, var/l, var/2, . .. В таком случае вопрос

?- Term = f( X, t( a, Y, X) ), numbervars ( Term, 5, Ml.

приведет к получению такого результата: Term = f( var/5, t( a, var/6, var/5)) X = var/5 Y = var/6

M = 7

Подобная процедура numbervars часто предоставляется в системе Prolog в виде встроенного предиката. В противном случае ее можно ввести в программу, как пока­зано ниже.

numbervars ( Term, N, Nplusl) :-

var ( Term), ! , % Переменная?

Term = var/N,

Nplusl is N + 1. numbervars( Term, N, Mi :-

Term =.. [Functor I Args] , % Структура или атом

numberargs { Args, Ы, M) . % Количество переменных в параметрах

numberargs ( [ ] , N, Ы) :- ! . numberargs ( [X I L] , N, M) :-

numbervars( X, Ы, N1),

numberargs( L, N1, M).