- •Таганрог 2001
- •Содержание
- •Введение
- •1. Принципы логического программирования
- •1.1. Базовые понятия
- •1.2. Терминология
- •1.3. Сложные термы, или структуры
- •1.4. Синтаксис строк
- •1.5. Утверждения
- •1.6. Запросы
- •1.7. Ввод программ
- •1.8. Унификация
- •1.9. Арифметические выражения
- •1.10. Вычисление арифметических выражений
- •1.11. Сравнение результатов арифметических выражений
- •Контрольные вопросы и упражнения
- •2. Структуры данных на языке пролог
- •2.1. Списки
- •2.2. Бинарные деревья
- •2.3. Механизм возврата и процедурная семантика
- •3. Представление моделей знаний
- •3.1. Процесс представления знаний
- •3.2. Семантические сети
- •3.3. Фреймы
- •3.4. Механизм наследования в Прологе
- •3.5. Создание динамических баз данных
- •3.6. Представление задач в виде и/или – графов
- •4. Экспертные системы
- •4.1. Системы экспертных консультаций
- •Этап идентификации
- •Этап концептуализации
- •Этап формализации
- •Этап выполнения
- •Этап тестирования
- •Этап опытной эксплуатации
- •Экспертные системы, параллельные и последовательные решения
- •Пример эс, основанной на правилах логического вывода и действующую в обратном порядке
- •Часть 1.
- •Часть 2.
- •Часть 3.
- •Часть 4.
- •Часть 5.
- •4.2. Запоминание пути вывода
- •5. Пример задачи на представление знаний
- •6. Заключение
- •Литература
- •Представление знаний и логическое программирование в системах искусственного интеллекта Учебное пособие
1. Принципы логического программирования
1.1. Базовые понятия
Развитие систем баз данных первоначально было мотивировано потребностью в эффективных средствах хранения, манипуляции и извлечения большого количества разнообразных данных. По мере того, как в достижении этих целей наблюдался прогресс, возникла дополнительная заинтересованность в возможности задавать информационным системам правила, применяемые к хранимым фактам (данным), с тем, чтобы появилась возможность вывода фактов, т.е. получения новых знаний.
Включение знаний в системы баз данных было подсказано исследованиями в области искусственного интеллекта (ИИ), который занимается вопросами программирования разумного поведения. Разработки в области ИИ включали исследования представлений логических правил, применяемых к данным. Экспертные системы (ЭС) — это особый раздел ИИ, посвященный представлению правил и процедур, которым следует специалист, решая задачи в конкретной предметной области. К таким областям относятся медицина, планирование налогов, проектирование компьютеров и т.д. Таким образом, экспертные системы (ЭС) можно определить как системы, моделирующие процесс принятия решений специалистами в разных предметных областях методами искусственного интеллекта [2] [3].
Хотя исследования в области экспертных систем значительно повлияли на методы представления знаний, основанные на логических правилах, экспертные системы не являются базами знаний, поскольку они не обеспечивают полные возможности управления данными, присущие системам управления базами данных (СУБД). Язык Пролог, наиболее популярный язык экспертных систем, является естественным мостом между базами данных и базами знаний. Этот язык основан на исчислении предикатов, а его предикаты могут рассматриваться как реляционные таблицы. Кроме того, в нем имеется возможность выражения той логики, которой пользуется человек, преобразуя факты из базы данных в информацию, помогающую принимать решения [4].
В средние века знание латинского и греческого языков являлось существенной частью образования любого ученого. Ученый, владеющий только одним языком, неизбежно чувствовал себя неполноценным, поскольку он был лишен той полноты восприятия, которая возникает благодаря возможности посмотреть на мир сразу с двух точек зрения. Таким же неполноценным ощущает себя сегодняшний исследователь в области искусственного интеллекта, если он не обладает основательным знакомством с Лиспом и Прологом - основными языками искусственного интеллекта. Без знания этих языков невозможен более широкий взгляд на предмет исследования.
В самом широком смысле, эволюция языков программирования - это движение от языков низкого уровня, при использовании которых, программист описывает то, как что-либо следует делать, к языкам высокого уровня, на которых просто указывается, что необходимо сделать. Так, например, появление Фортрана освободило программистов от необходимости разговаривать с машиной на языке адресов и регистров.
Однако Фортран, Си и большинство других языков программирования все еще остаются языками типа «как». Чемпионом среди этих языков является, пожалуй, современный модернизированный язык Лисп. Например, Common Lisp, имея богатейшие выразительные возможности, позволяет программисту описывать наиболее «выразительно» именно то, как что-либо следует делать. В то же время Пролог порывает с традициями языков типа «как», поскольку он определенным образом направляет программистское мышление, заставляя программиста давать определения ситуаций и формулировать задачи вместо того, чтобы во всех деталях описывать способ их решения. Программист только сообщает системе то, что ему известно, и задает вопросы. Его в большей степени интересуют знания и в меньшей - алгоритмы, при помощи которых из этих знаний извлекается нужная информация.
Пролог - это язык программирования, предназначенный для обработки символьной нечисловой информации [2]. Особенно хорошо он приспособлен для решения задач, в которых фигурируют объекты и отношения между ними.
Для иллюстрации особенностей представления знаний на языке Пролог (не вдаваясь в тонкости, которые будут рассмотрены далее в соответствующих разделах), рассмотрим на примере описания родословной Иисуса из Евангелия от Матфея. Как известно, эта родословная в Евангелии представлена в следующем виде.
1 Родословие Иисуса Христа, Сына Давидова, Сына Авраамова.
2 Авраам родил Исаака; Исаак родил Иакова; Иаков родил Иуду и братьев его;
3 Иуда родил Фареса и Зару от Фамари; Фарес родил Есрома; Есром родил Арама;
4 Арам родил Аминадава; Аминадав родил Наассона; Наассон родил Салмона;
5 Салмон родил Вооза от Рахавы; Вооз родил Овида от Руфи; Овид родил Иессея;
6 Иессей родил Давида царя; Давид царь родил Соломона от бывшей за Уриею;
7 Соломон родил Ровоама; Ровоам родил Авию; Авия родил Асу;
8 Аса родил Иосафата; Иосафат родил Иорама; Иорам родил Озию;
9 Озия родил Иоафама; Иоафам родил Ахаза; Ахаз родил Езекию;
10 Езекия родил Манассию; Манассия родил Амона; Амон родил Иосию;
11 Иосия родил Иоакима; Иоаким родил Иехонию и братьев его, перед переселением в Вавилон.
12 По переселении же в Вавилон, Иехония родил Салафииля; Салафииль родил Зоровавеля;
13 Зоровавель родил Авиуда; Авиуд родил Елиакима; Елиаким родил Азора;
14 Азор родил Садока; Садок родил Ахима; Ахим родил Елиуда;
15 Елиуд родил Елеазара; Елеазар родил Матфана; Матфан родил Иакова;
16 Иаков родил Иосифа, мужа Марии, от Которой родился Иисус, называемый Христос.
17 Итак всех родов от Авраама до Давида четырнадцать родов; и от Давида до переселения в Вавилон четырнадцать родов; и от переселения в Вавилон до Христа четырнадцать родов.
Суть задачи состоит в получении ответов на вопросы о типе родства тех или иных имен, содержащихся в приведенной родословной. Для получения ответов от системы, данную родословную необходимо представить в более формализованном виде. Тот факт, что Авраам является родителем Исаака, можно записать на Прологе так:
родитель( авраам, исаак).
Здесь мы выбрали родитель в качестве имени отношения, а авраам и исаак - в качестве его аргументов. По причинам, которые станут понятны позднее, мы записываем имена начиная со строчной буквы. В результате поддерево дерева родственных отношений может быть описано следующей пролог-программой:
родитель(авраам, исаак).
родитель(исаак, иаков).
родитель(иаков, иуда).
родитель(иуда, фарес).
родитель(иуда, зара)
родитель(фамарь, фарес).
родитель(фамарь, зара)
родитель(фарес, есром).
родитель(есром, арам).
родитель(арам, аминадав).
родитель(аминадав, наассон).
родитель(наассон, салмон).
родитель(салмон, вооз).
родитель(рахава, вооз).
родитель(вооз, овид).
родитель(руфь, овид).
родитель(овид, иессей).
Эта программа содержит 17 предложений. Каждое предложение объявляет об одном факте наличия отношения родитель.
После ввода такой программы в пролог-систему последней можно будет задавать вопросы, касающиеся отношения родитель. Например, является ли Овид родителем Иессея? Этот вопрос можно передать пролог-системе, набрав на клавиатуре терминала:
?- родитель(овид, иессей).
Найдя этот факт в программе, система ответит
yes (да) Другим вопросом мог бы быть такой:
?- родитель(руфь, иессей).
Система ответит
nо (нет),
поскольку в программе ничего не говорится о том, является ли Руфь родителем Иессея. Программа ответит «нет» и на вопрос
?- родитель( соломон, вооз).
потому, что имя Соломон (в отличие от Салмон) в программе даже не упоминается.
Можно задавать и более интересные вопросы. Например: "Кто является родителем Аминадава?"
?- родитель( X, аминадав).
На этот раз система ответит не просто «да» или «нет». Она скажет нам, каким должно быть значение X (ранее неизвестное), чтобы вышеприведенное утверждение было истинным. Поэтому мы получим ответ:
X = арам
Вопрос «Кто дети Иуды?» можно передать пролог-системе в такой форме:
?- родитель( иуда, X).
В этом случае возможно несколько ответов. Сначала система сообщит первое решение:
X = фарес
Возможно, мы захотим увидеть и другие решения. О нашем желании мы можем сообщить системе (во многих реализациях для этого надо набрать точку с запятой), и она найдет другой ответ:
X = зара
Если мы потребуем дальнейших решений, система ответит «нет», поскольку все решения исчерпаны.
Нашей программе можно задавать и более общие вопросы: «Кто чей родитель?» Приведем другую формулировку этого вопроса:
Найти X и Y такие, что X - родитель Y. На Прологе это записывается так:
?- родитель( X, Y).
Система будет по очереди находить все пары вида «родитель-ребенок». По мере того, как мы будем требовать от системы новых решений, они будут выводиться на экран одно за другим до тех пор, пока все они не будут найдены. Ответы выводятся следующим образом:
X = авраам
Y = исаак;
X = исаак
Y = иаков;
X = иаков Y = иуда; . . .
Мы можем остановить поток решений, набрав, например, точку вместо точки с запятой (выбор конкретного символа зависит от реализации).
Пролог-системе можно задавать и еще более сложные вопросы, скажем, кто является родителем родителя Иакова? Поскольку в нашей программе прямо не сказано, что представляет собой отношение родитель родителя, такой вопрос следует задавать в два этапа.
Кто родитель Иакова?
Предположим, что это некоторый Y.
Кто родитель Y?
Предположим, что это некоторый X.
Такой составной вопрос на Прологе записывается в виде последовательности двух простых вопросов:
?- родитель (Y, иаков), родитель( X, Y).
Ответ будет:
X = авраам
Y = исаак
Наш составной вопрос можно интерпретировать и так: «Найти X и Y, удовлетворяющие следующим двум требованиям»:
родитель( Y, иаков) и родитель( X, Y)
Если мы поменяем порядок этих двух требований, то логический смысл останется прежним:
родитель( X, Y) и родитель( Y, иаков)
Этот вопрос можно задать нашей пролог-системе и в такой форме:
?- родитель( X, Y), родитель( Y, иаков).
При этом результат будет тем же. Таким же образом можно спросить: «Кто внуки Авраама?»
?- родитель (авраам, X), родитель( Х, Y).
Система ответит так:
X = авраам
Y = иаков
Следующим вопросом мог бы быть такой: «Есть ли у Фареса и Зары общий родитель?» Его тоже можно выразить в два этапа:
(1) Какой X является родителем Фареса?
(2) Является ли (тот же) X родителем Зары?
Соответствующий запрос к пролог-системе будет тогда выглядеть так:
?- родитель( X, фарес), родитель( X, зара).
Ответ:
X = иуда;
Х = фамарь
Теперь добавим к нашей программе о родственных связях еще одно отношение - предок. Определим его через отношение родитель. Ключевая идея здесь - определить отношение предок через него самого.
Для всех X и Z,
X - предок Z, если
существует Y, такой, что
(1) X - родитель Y и
(2) Y - предок Z.
Предложение Пролога, имеющее тот же смысл, записывается так:
предок( X, Z) :-
родитель( X, Y),
предок( Y, Z).
Теперь мы построили полную программу для отношения предок, содержащую два правила: одно для ближайших предков и другое для отдаленных предков. Здесь приводятся они оба вместе:
предок( X, Z) :-
родитель( X, Z).
предок( X, Z) :-
родитель( X, Y),
предок( Y, Z).
Ключевым моментом в данной формулировке было использование самого отношения предок в его определении. Такое определение может озадачить - допустимо ли при определении какого-либо понятия использовать его же, ведь оно определено еще не полностью. Такие определения называются рекурсивными. Логически они совершенно корректны и понятны. Но будет ли в состоянии пролог-система использовать рекурсивные правила? Оказывается, что пролог-система довольно легко может обрабатывать рекурсивные определения. На самом деле, рекурсия - один из фундаментальных приемов программирования на Прологе. Без рекурсии с его помощью невозможно решать задачи сколько-нибудь ощутимой сложности.
Возвращаясь к нашей программе, можно задать системе такой вопрос: «Кто потомки Авраама?» То есть: «Кто тот человек, чьим предком является Авраам?»
?- предок( авраам, X).
X = исаак;
X = иаков;
X = иуда;
X = фарес
…
Наша программа-пример помогла проиллюстрировать некоторые важные моменты, а именно:
На Прологе легко определить отношение, подобное отношению родитель, указав объекты, для которых это отношение выполняется.
Пользователь может легко задавать пролог-системе вопросы, касающиеся отношений, определенных в программе.
Пролог-программа состоит из предложений. Каждое предложение заканчивается точкой.
Аргументы отношения могут быть (среди прочего): конкретными объектами, или константами (такими, как авраам и иаков), или абстрактными объектами, такими, как X и Y. Объекты первого типа называются атомами. Объекты второго типа - переменными.
Вопросы к системе состоят из одного или более целевых утверждений (или кратко – целей). Последовательность целей, такая как
родитель( X, фарес), родитель( X, зара)
означает конъюнкцию этих целевых утверждений:
X - родитель Фареса и
X - родитель Зары.
Пролог-система рассматривает вопросы как цели, к достижению которых нужно стремиться.
Ответ на вопрос может оказаться или положительным или отрицательным в зависимости от того, может ли быть соответствующая цель достигнута или нет. В случае положительного ответа мы говорим, что соответствующая цель достижима и успешна. В противном случае цель недостижима, имеет неуспех или терпит неудачу.
Если на вопрос существует несколько ответов, пролог-система найдет столько из них, сколько пожелает пользователь.
Предложения могут быть заданы рекурсивно.
