Главная arrow Робототехника arrow Простая экспертная система
Как начинался компьютер
Компьютерная революция
Двоичный код
Разработки военных лет
Интегральные микросхемы
Микрокомпьютер
Персоны
Сеть
Язык компьютера
Развитие ПО
Гибкие системы
Средства разработки
Информатика
Вычислительная наука
Операционные системы
Искусственный интеллект
Предыстория
Поиск
Знания и рассуждения
Логика
Робототехника
 

 
Простая экспертная система Печать

Пример написания программы Простая Экспертная Система на языке ПроЛог. Начнем с того, что знак равно в ПроЛоге используется не как оператор приравнивания, а как оператор унифицирования. Унификация – это приведение выражений справа и слева от знака унификации к одному значению. При этом несвязанные значения из одного выражения будут заполнены значениями из другого выражения. Таким образом, если в операции унификации участвуют две переменных, и каждая связана со своим значением, то выполняется их сравнение. Если одна переменная не связана, то выполняется приравнивание ей значения. А если в унификации участвуют выражения с наличием несвязанных частей, то эти части принимают значения из таких же частей другого выражения. При этом ПроЛог пытается привести оба выражения к одному значению. Примеры.

Унификация как приравнивание.

Goal
               А = 5,
               А = Б
               write(А, “,”, Б).

Здесь в первой строчке унификация несвязанной переменной со значением 5. Результат – значение переменной А связано с константой 5. Во второй строчке унификация несвязанной переменной В и связанной А приведет к передаче значения переменной А в переменную Б. ПроЛог выдаст на экран:

5,5

Унификация как сравнение

Goal
               А = 5,
               Б = “да”,
               А = Б.

Здесь уже в унификации будут участвовать два полностью связанных значения, значит происходит простое сравнение значений. Результат выполнения ПроЛога:

No

Это говорит что унификация не успешна, то есть значения переменной А и Б неравны.

Унификация как приведение к одному значению

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

domains
Слово = string
Слова = reference Слово*
predicates
унификация(Слова А, Слова Б)
clauses
унификация(Слова,Слова):-!.
 
Goal
               А = [“да”, “нет”, С],
               Б = [“да”,_, “точно”],
               унификация ( А, Б),
               write(А, “,”, Б, “:”, С).

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

[“да”, “нет”, “точно”], [“да”, “нет”, “точно”]: “точно”

Как видно унификация прошла успешно, что привело к одному значению для обоих выражений. Однако, если переменной А будет присвоено другое значение [“да”, “нет”,_,_], унификация будет неуспешна.

Нужно заметить, что для включения механизма унификации неполных значений нужно объявить явно, что значения переменной могут быть частично связаны (быть ссылками, а не значениями) с помощью ключевого слова reference. Это делается при объявлении типа значения в секции domains программы. Еще замечание. При появлении в программе ПроЛога константы “список элементов”, первый элемент должен быть связан со значением. Это нужно для того чтобы ПроЛог мог определить тип остальных элементов списка. В нашем примере в обоих константах “список элементов” первый элемент звязан со значением “да”. Если список передается как параметр вызова предиката, то это условие необязательно ввиду того что параметры предиката уже явно описаны и принадлежат к конкретному типу. Например, можно было бы написать предикат унификация([_, “да”],С) что не вызвало бы ошибку ПроЛога.

Еще интересная особенность ключевого слова reference – это то, что можно унифицировать еще несвязанные переменные. Тогда их ссылки на область значения будут одинаковые. И если в дальнейшем одну переменную связать со значением, то и вторая переменная будет автоматически связана. Пример с использованием предиката “унификация”, описанного выше.

Goal
               Унификация ( А, Б),
               А = [“да”, “нет”],
               write(Б).

Результат ПроЛога :

[“да”, “нет”]

Видно, что явно никакого значения переменной Б не присваивалось. Тем не менее в ней появилось значение.

Простая Экспертная Система на основе унификации значений ПроЛога.

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

Domains
Слово = string
СловоПредл = reference сущ(Слово,СловоПредл); 
               глаг(Слово,СловоПредл); прил(Слово,СловоПредл);
               пред(Слово,СловоПредл); нар(Слово,СловоПредл);
               пусто

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

Теперь опишем базу знаний и вид фактов в ней.

database - знания
знание(СловоПредл)

Используя унификацию значений ПроЛога Мы получаем наипростейший поиск знаний. Предикат поиска будет выглядеть так:

predicates
nondeterm ответ(СловоПредл)
 
clauses
ответ(СловоПредл):-
               знание(СловоПредл).

ВСЁ! Замечу, что можно обойтись и без предиката вовсе, задавая поиск фактов напрямую в базе знаний. Ключевое слово nondeterm указывает на то что в случае отката нужно перебирать все возможные варианты ответов если таковые есть.

Теперь можно создать бузу знаний для экспертной системы и задавать вопросы. Пусть база знаний хранится в файле “знания.txt” и содержит факты:

знание(сущ("лев",глаг("живёт",пред("в",сущ("саванне",пусто))))).
знание(сущ("антилопа",глаг("живёт",пред("в",сущ("саванне",пусто))))).
знание(сущ("зебра",глаг("живёт",пред("в",сущ("саванне",пусто))))).
знание(сущ("лев",глаг("охотится",пред("на",сущ("животных",пусто))))).
знание(сущ("тигр",глаг("охотится",пред("на",сущ("животных",пусто))))).
знание(сущ("тигр",глаг("живёт",пред("в",сущ("лесу",пусто))))).
знание(сущ("заяц",глаг("живёт",пред("в",сущ("лесу",пусто))))).
знание(сущ("заяц",глаг("ест",сущ("траву",пусто)))).
знание(сущ("олень",глаг("ест",сущ("траву",пусто)))).
знание(сущ("заяц",глаг("ест",сущ("кору",пусто)))).

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

 
Goal:-       % вызов решателя ПроЛога
               consult("знания.txt",знания),     % загрузка базы знаний
% определение слов вопроса
               ЧтоДелает="живёт", Где="саванне",
% сборка вопроса
               А=сущ(Кто,глаг(ЧтоДелает,пред(Предл,сущ(Где,Дополнения)))),
% поиск ответов
               ответ(А),
% печать ответов
               nl,write(Кто, " ", ЧтоДелает, " ", Предл, " ", Где, " ", Дополнения),
               fail.

Ответ Пролога:

лев живёт в саванне пусто
антилопа живёт в саванне пусто
зебра живёт в саванне пусто

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

               Кто="лев",
               А=сущ(Кто,глаг(ЧтоДелает,Дополнения),
               nl,write(Кто, " ", ЧтоДелает, " ", Дополнения),
 

ответ ПроЛога будет:

лев живёт пред("в",сущ("саванне",пусто))
лев охотится пред("на",сущ("животных",пусто))

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