Оболочка экспертной системы Geni

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

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

Знания в этой системе представляют собой правила, имеющие вид:

rule(N,CAT1,CAT2,COND).

Здесь N -порядковый номер правила,

CAT1 - выражение, стоящее в левой части правила и характеризующее признак класса (подкласса и т.д.), к которому относится данное правило;

CAT2 - содержание правила в правой части, содержащее вывод из этого правила;

COND - список номеров условий, определяющих правило.

Условие имеет вид:

cond( N, CONDTEXT),

где N - номер условия,

CONDTEXT - текст условия.

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

rule(1,"хищник","гепард",[1,2])

rule(2,"хищник","тигр",[1,3])

rule(3,"копытное","жираф",[5,4,2])

rule(4,"копытное","зебра",[3])

rule(5,"птица","страус",[5,7])

rule(6,"птица","пингвин",[9,7])

rule(7,"птица","альбатрос",[10])

rule(8,"животное","млекопитающее",[11,12])

rule(9,"животное","птица",[8,13])

rule(10,"млекопитающее","хищник",[14])

rule(11,"ìëåêîïèòàþùåå","êîïûòíîå",[15])

cond(1,"оно имеет рыжий цвет")

cond(2,"оно имеет темные пятна")

cond(3,"оно имеет черные полосы")

cond(4,"оно имеет длинную шею")

cond(5,"оно имеет длинные ноги")

cond(6,"оно летает")

cond(7,"оно имеет черный и белый цвет")

cond(8,"оно имеет перья")

cond(9,"оно плавает")

cond(10,"оно летает хорошо")

cond(11,"оно имеет шерсть")

cond(12,"оно кормит детенышей молоком")

cond(13,"оно откладывает яйца")

cond(14,"оно ест мясо")

cond(15,"оно имеет копыта")

Легко видеть, что такой способ представления знаний реализует конструкцию вида ЕСЛИ ТО:

ЕСЛИ САТ1 отвечает условиям СOND, ТО САТ1 есть САТ2.

В целом все описание соответствует древовидной структуре представления информации, в которую хорошо вписываются различные классификационные системы. Разделение базы данных и программы позволяет реализовать оболочку экспертной системы. Такая программа организует диалог с пользователем в процессе консультаций, модификацию базы знаний, а также имеет систему объяснений.

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

yes(N) или no(N),

где N - номер условия cond.

Основным рабочим предикатом ЭС является рекурсивный предикат go. Этот предикат организует просмотр дерева базы знаний, выделение очередного правила и выдачу рекомендаций в случае достижения вершины древовидной структуры базы знаний. Он также позволяет хранить предысторию процесса консультации (т.е. набор использованных правил) для реализации системы объяснений.

go( _, Mygoal ):- /*Цель достигнута */

not(rule(_,Mygoal,_,_)),!,nl,

write("I think it is a(n): ",Mygoal),nl,nl,

write("I was right, wasn't I? (enter y or n)"),

readchar(Ans),

evalans(Ans).

go( HISTORY, Mygoal ):-

rule(RNO,Mygoal,NY,COND),

check(RNO,HISTORY, COND),

go([RNO|HISTORY],NY).

Первое правило предиката go является базовым для рекурсии, оно соответствует достижению конечной вершины классификационного дерева (в базе данных нет правила rule, где конечная вершина стоит вторым аргументом). В этом случае система просит подтвердить правильность ее решения (предикат evalans). Если конечная вершина не достигнута, работает второе правило предиката go. Выбирается очередное правило rule из базы данных.

Предикат check, входящий во второе правило предиката go, производит проверку списка условий COND на достоверность, т.е. поиск уже имеющихся фактов, относящихся к данным условиям. Если ответ на эти условия имеется в базе данных в виде фактов yes(BNO) или no(BNO), проверка на этом заканчивается. В случае, если требуемые факты не обнаружены, определяется запрос пользователю с помощью предиката inpq. Если проверка check заканчивается ложно, то выбирается следующее правило из базы знаний. Если же проверка успешна, номер правила присоединяется к списку успешных правил HISTORY, по которому можно восстановить историю поиска, а текущей целью становится третий аргумент правила rule, что означает переход к следующему уровню дерева:

check( RNO, HISTORY, [BNO|REST] ):- yes(BNO), !,

check(RNO, HISTORY, REST).

check( _, _, [BNO|_] ):- no(BNO), !,fail.

check( RNO, HISTORY, [BNO|REST] ):-

cond(BNO,TEXT),

inpq(HISTORY,RNO,BNO,TEXT),

check(RNO, HISTORY, REST).

check( _, _, [ ] ).

Предикат inpq запускает диалоговый механизм, посредством которого система получает недостающую информацию. Система задает пользователю вопросы, представляющие собой условия истинности конкретного правила, при этом пользователь может ответить “yes”, “no” или “why”. Третий ответ означает, что пользователю нужно знать, почему система задала такой вопрос. В этом случае намерения системы демонстрируются в виде цепочки правил и целей, соединяющих эту информацию с исходным вопросом.

inpq(HISTORY,RNO,BNO,TEXT):-

write("Is it true that ",TEXT,": "),

ROW = 14,

COL = 60,

menu(ROW,COL,7,7,[yes,no,why],"",1,CHOICE),

do_answer(HISTORY,RNO,TEXT,BNO,CHOICE).

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

do_answer(_,_,_,BNO,1):-assert(yes(BNO)), write(yes),nl. % Ответ yes

do_answer(_,_,_,BNO,2):-assert(no(BNO)), write(no),nl,fail. % Ответ no

do_answer(HISTORY,RNO,TEXT,BNO,3):- !, % Ответ why

rule( RNO, Mygoal1, Mygoal2, _ ),

sub_cat(Mygoal1,Mygoal2,Lstr),

concat("I try to show that: ",Lstr,Lstr1),

concat(Lstr1,"\nBy using rule number ",Ls1),

str_int(Str_num,RNO),

concat(Ls1,Str_num,Ans),

show_rule(RNO,Lls1),

concat(Ans,Lls1,Ans1),

report(HISTORY,Sng),

concat(Ans1,Sng,Answ),

display(Answ),

write(" Use Arrow Keys To Select Option "),

shiftwindow(1),

ROW = 14,COL = 60,

menu(ROW,COL,7,7,[yes,no,why],"",1,CHOICE),

do_answer(HISTORY,RNO,TEXT,BNO,CHOICE).

Объяснению придается удобная для восприятия форма с помощью стандартных предикатов concat, str_int, display и рекурсивного предиката report:

report([],"").

report([RNO|REST],Strg) :-

rule( RNO, Mygoal1, Mygoal2, _), % Выбирается правило с номером RNO

sub_cat(Mygoal1,Mygoal2,Lstr),

concat("I have shown that: ",Lstr,L1),

concat(L1,"By using rule number ",L2),

str_int(Str_RNO,RNO),

concat(L2,Str_RNO,L3),

concat(L3, L4),

show_rule(RNO,Str), % Показ правила

concat(L4,Str,L5),

report(REST,Next_strg),

concat(L5,Next_strg,Strg).

Модификацию бзы данных выполняет предикат update:

update:-

write("Name of category: "),

readln(KAT), % Ввод категории

KAT><"", % Окончание работы предиката

write("Name of subcategory: "),

readln(SUB), SUB><"", % Ввод подкатегории

readcondl(CONDL), % Ввод списка условий

getrnr(1,RNO), % Получение номера правила

assert( rule(RNO,KAT,SUB,CONDL) ), % Добавление правила к БД

update.

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

rule(RNO,"хищник","пантера", [BNO] ) и условие

cond(BNO,"оно имеет черный цвет") , где RNO и BNO - соответственно номер правила и номер условия, еще не конкретизированные переменные. Предикат readcondl позволяет ввести список условий:

readcondl( [BNO|R] ):-

readln(COND), % Вод текста условия

COND><"",!, % Окончание ввода списка условий

getcond(BNO,COND), % Получение номера условия

readcondl( R ).

readcondl( [ ] ).

Предикат getcondl находит номер условия в базе данных, если такое условие там уже есть, или получает следующий по порядку свободный номер условия с помощью предиката getbnr:

getcond(BNO,COND):-cond(BNO,COND),!. % Условие есть в базе данных

getcond(BNO,COND):-getbnr(1,BNO),

assert( cond(BNO,COND) ). % Óñëîâèå äîáàâëÿåòñÿ ê áàçå äàííûõ

getbnr(N,N):-not(cond(N,_)),!.

getbnr(N,N1):-H=N+1,getbnr(H,N1).

Сходным образом определяется номер правила, которого еще нет в базе данных:

getrnr(N,N):-not(rule(N,_,_,_)),!.

getrnr(N,N1):-H=N+1,getrnr(H,N1).

Файлы оболочки программы и примеров баз знаний расположены в каталоге Programs.