Создание экспертных систем средствами ПРОЛОГа
Экспертные системы (ЭС) - это сложные программные комплексы, аккумулирующие знания специалистов в конкретных предметных областях и тиражирующие этот эмпирический опыт для консультаций менее квалифицированных пользователей.
Построим небольшую экспертную систему, которая будет определять одну из нескольких рыб по признакам, указанным пользователем. Система будет задавать вопросы и строить логические выводы на основе полученных ответов.
Типичный диалог экспертной системы с пользователем может выглядеть следующим образом (рис.27):
рис.27. Диалог экспертной системы с пользователем
Первым шагом построения такой системы является обеспечение ее знаниями, необходимыми для выполнения рассуждений. Программа должна во время консультаций выводить заключения из информации, имеющейся в базе знаний, а также использовать новую информацию, полученную от пользователя. Поэтому минимальная ЭС должна включать:
- базу знаний;
- механизм вывода;
- пользовательский интерфейс.
Разработку любой ЭС следует начать с исследования предметной области. Пусть на основе бесед с экспертом были получены следующие эмпирические правила:
1) ЕСЛИ
это отряд карпообразные и
И
у рыбы желто-золотистый окрас
И
губы с 4 усиками
ТО
это сазан
2) ЕСЛИ
это отряд карпообразные
И
у рыбы плавники с розовыми перьями
TО
это плотва
3) ЕСЛИ
спинной плавник узкий
И
у рыбы желто-золотистый окрас
И
это отряд карпообразные
TО
это лещ
4) ЕСЛИ
у рыбы нет зубов
И
одиночный спинной лучевой плавник
И
это костная рыба
И
это пресноводная рыба
TО
это отряд карпообразные
5) ЕСЛИ
у рыбы есть костный скелет
ИЛИ
у рыбы есть жаберные крышки
TО
это костная рыба
6) ЕСЛИ
рыба плавает в озерах
ИЛИ
рыба плавает в реках
ТО
это пресноводная рыба
Для создания базы знаний используем предикаты:
fish(symbol)
otrajd(symbol)
vid(symbol)
priznak(symbol)
Базу знаний будут составлять следующие правила:
fish("это сазан"):-
otrajd("отряд карпообразные"),
priznak("губы с 4 усиками").
fish("это плотва"):-
otrajd("отряд карпообразные"),
priznak("плавники с розовыми перьями").
fish("это лещ"):-
otrajd("отряд карпообразные"),
priznak("у рыбы желто-золотистый окрас"),
priznak("у рыбы спинной плавник узкий").
Необходимо предусмотреть, что искомой рыбы в базе знаний нет:
fish("Данной рыбы в базе знаний не обнаружено").
otrajd("отряд карпообразные"):-
vid("пресноводная рыба"),
vid("костная рыба"),
priznak("одиночный спинной лучевой плавник"),
priznak("у рыбы нет зубов").
vid("костная рыба"):-
priznak("у рыбы есть жаберные крышки");
priznak("у рыбы есть костный скелет").
vid("пресноводная рыба"):-
priznak("рыба плавает в реках или озерах").
Для хранения информации, полученной от пользователя, используются предикаты yes и no, составляющие внутреннюю базу фактов. Предикат yes служит для хранения фактов, соответствующих положительному ответу, а предикат no – для хранения отрицательных ответов. Т.е. предикат yes утверждает наличие какого-либо признака у рыбы, а no – отсутствие указанного признака. Эти предикаты объявляются в разделе внутренней базы фактов:
global facts
yes (symbol)
no (symbol)
Добавить новые факты во внутреннюю базу можно с помощью правила add_to_database, состоящего из двух частей. Первая часть добавляет факты, соответствующие положительному ответу (с клавиатуры вводится ‘y’). Вторая часть правила добавляет факты, указывающие на отсутствие данного признака у рыбы.
add_to_database (Y,'y') :- assertz (yes (Y)).
add_to_database (Y,'n') :- assertz (no (Y)),fail.
Необходимо предусмотреть очистку внутренней базы фактов. Для этого создадим правило:
clear_from_database :- retract(yes(_)),fail.
clear_from_database :- retract(no(_)),fail.
Для проверки наличия у рыбы определенного признака создадим правило priznak (Y):
priznak (Y) :- yes (Y),!.
priznak (Y) :- not(no (Y)),
question (Y).
Формулировка вопроса, ввод ответа и сохранение соответствующего правила осуществляется с помощью правил:
answer :- fish(X),!,nl,
save("BF1.dbf"),
write (" Ответ: ",X,"."),nl.
question(Y) :-
write ("Вoпрос: ",Y,"?(y/n) "),
otvet(X),
write(X),nl,
add_to_database (Y,X).
otvet(C):-readchar(C).
И, наконец, правило begin, запускающее сеанс консультации:
begin :- write ("Ответьте на вопросы :"),nl,nl,
answer,
clear_from_database,
nl,nl,nl,nl,
exit.
Полный листинг программы выглядит следующим образом:
GLOBAL FACTS
yes (symbol)
no (symbol)
PREDICATES
fish(symbol)
otrajd(symbol)
vid(symbol)
begin
answer
question(symbol)
add_to_database(symbol,char)
otvet(char)
clear_from_database
priznak(symbol)
GOAL
begin.
CLAUSES
begin :-
write ("Ответьте на вопросы :"),nl,nl,
answer,
clear_from_database,
nl,nl,nl,nl,
exit.
answer :-
fish(X),!,nl,
save("BF1.dbf"),
write (" Ответ: ",X,"."),nl.
question(Y) :-
write ("Вoпрос: ",Y,"? "),
otvet(X),
write(X),nl,
add_to_database (Y,X).
otvet(C):-
readchar(C).
priznak (Y) :-
yes (Y),!.
priznak (Y) :-
not( no (Y)),
question (Y).
add_to_database (Y,'y') :-
assertz (yes (Y)).
add_to_database (Y,'n') :-
assertz (no (Y)),fail.
clear_from_database :- retract (yes(_)),fail.
clear_from_database :- retract (no(_)),fail.
fish("это сазан"):-
otrajd("отряд карпообразные"),
priznak("губы с 4 усиками").
fish("это плотва"):-
otrajd("отряд карпообразные"),
priznak("плавники с розовыми перьями").
fish("это лещ"):-
otrajd("отряд карпообразные"),
priznak("у рыбы желто-золотистый окрас"),
priznak("у рыбы спинной плавник узкий").
fish("Данной рыбы в базе знаний не обнаружено").
otrajd("отряд карпообразные"):-
vid("пресноводная рыба"),
vid("костная рыба"),
priznak("одиночный спинной лучевой плавник"),
priznak("у рыбы нет зубов").
vid("костная рыба"):-
priznak("у рыбы есть жаберные крышки");
priznak("у рыбы есть костный скелет").
vid("пресноводная рыба"):-
priznak(«рыба плавает в реках или озерах»).