Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программы классификации 49 9 Программа классифи...doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
944.13 Кб
Скачать

2.4.3. Секция Database

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

2.4.4. Секция Clauses

Здесь записываются все дизъюнкты всех предикатов. Другое название дизъюнктов – статьи, предложения или клозы. Это факты и правила, соответствующие каждому из объявленных предикатов. Примеры записи дизъюнктов-фактов:

child( “Иван” ).

mother( “Анна”, “Иван” ).

mother( “Анна”, “Петр” ).

Каждый из дизъюнктов одного предиката секции Clauses соответствует альтернативам этого предиката (т.е. реализация ИЛИ).

Главное синтаксическое требование при записи дизъюнктов – одноименные предикаты должны быть сгруппированы, т.е. записаны последовательно один за другим.

2.4.5. Секция Goal

Здесь указывается вопрос (цель), на который должен ответить Пролог. Записывается он как дизъюнкт без головы и знака ":–" , т.е. это конъюнкция подцелей. Например:

Goal

mother( “Анна”, X ), mother( X, Y ).

При запуске программы цель выполняется автоматически. Если все подцели в разделе Goal истинны, программа завершается успешно. Если же какая-то подцель из раздела Goal ложна, выполнение программы на этом заканчивается и она завершатся неуспешно.

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

3. Язык Пролог в задачах и примерах

3.1. Программирование с помощью фактов и правил

Рассмотрим следующую вводную Пролог-программу. На этом примере мы покажем, как создать, отредактировать и выполнить Пролог-программу в интегрированной среде PDC Prolog.

predicates

hello

clauses

hello :-

makewindow(1,7,7,"My first program",4,36,10,22), % Создание окна

nl, % Перевод строки

write(" Please type your name "), % Вывод текстовой строки

cursor(4, 5), % Позиционирование курсора

readnl( Name ), % Ввод строки в переменную Name

nl,

write(" Wellcome ", Name). % Вывод текстовой строки и переменной

goal

hello.

После исправления ошибок в программе выберите опцию RUN в меню PDC Prolog. Введите свое имя (например, Аня) в окне ввода и нажмите ENTER. Программа напечатает

Welcome Аня

и будет ждать нажатия клавиши пробела (SPACE BAR).

Работа программы всегда начинается с выполнения раздела Goal. Цель пытается удовлетворить предикат hello. Этот предикат не имеет аргументов, его описание есть в разделе Predicates. Имеется единственная статья Clauses для этого предиката. Поэтому для проверки истинности цели начинают последовательно выполняться предикаты, записанные в правой части предиката hello. Все эти предикаты являются встроенными (стандартными), поэтому в программе не требуется их описания.

Эту небольшую программу привели только для демонстрации запуска полностью готовой программы в среде PDC Prolog. Она похожа на процедурный стиль программирования и напоминает, скажем так, реализацию некоторой логической функции (поскольку предикат, как логическая функция, может принимать только одно из двух значений – истина или ложь). Данный пример приведен, чтобы искушенный в программировании пользователь смог провести аналогию между процедурным стилем программирования и возможностью его реализации на Прологе.

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

Оформим факты и правила примера из раздела 1.2 в виде работающей Пролог-программы, добавив секцию описания предикатов Predicates и название секции их реализации Clauses:

Predicates

likes( string, string )

clever ( string )

Clauses

likes( ellen, reading ).

likes( john, football ).

likes( tom, baseball ).

likes( eric, reading ).

likes( mark, tennis ).

clever ( X ) :- likes ( X, reading ).

Эта программа может выполняться в интерактивном режиме (режиме диалога), поскольку цель явно не записана в программе (отсутствует секция Goal).

Запустите среду PDC PROLOG и наберите в окне редактора текст этой программы. После исправления синтаксических ошибок в программе в процессе компиляции выберите опцию RUN в меню Пролога. В этой программе цель не указана (которая, вообще говоря, в отладочном режиме не обязательна), поэтому, когда система в отдельном диалоговом окне после приглашения «Goal:» запросит цель, сразу после двоеточия введите запрос:

Goal: likes( john, football ).

Пролог ответит

Yes ,

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

Заметим, что хотя программа и в таком виде будет работать, более грамотным является запись программы с указанием областей определения переменных:

domains

name, hobby = string

Predicates

likes( name, hobby )

clever ( name )

Clauses

likes( ellen, tennis ).

likes( john, football ).

likes( tom, baseball ).

likes( eric, swimming ).

likes( mark, tennis ).

clever ( X ) :- likes ( X, reading ).

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

Predicates

car( string, integer, string, integer )

Clauses

car( volvo, 1990, red, 1800 ).

car( toyota, 1988, black, 2000 ).

car( ford, 1994, white, 3000 ).

Наберите эту программу согласно правилам оформления Пролог-программы и исполните команду RUN. Когда система запросит цель, введите запрос:

Goal: car( toyota, _ , _ , _ ).

Пролог ответит

1 solution

Yes

в диалоговом окне и будет ждать, когда вы введете другую цель.

В этом запросе использовались анонимные переменные, обозначенные символом подчеркивания. Анонимная переменная используется для обозначения аргументов, значения которых в данный момент могут быть произвольны. Если анонимная переменная встречается в запросе, то ее значение не выводится при ответе системы на этот запрос. Анонимная переменная может также использоваться в записи предикатов, если в предложении она встречается один раз. Примеры записи таких предикатов встретим дальше.

Если зададите в качестве цели

Goal: car( mersedes, 1990, _ , _ ) ,

система ответит

No solution,

поскольку наша база данных не содержит такого утверждения.

Теперь предположим, что мы хотим узнать все марки машин, имеющиеся в базе данных, т.е. задать вопрос: "Каковы те объекты Х, которые являются марками машины?". Тогда наш вопрос запишется так:

Goal: car( X, _ , _ , _ ).

Пролог ответит:

X = “volvo”

X = "toyota"

X = "ford"

3 solutions.

Можно также задавать вопросы более общего характера. К примеру, если требуется найти все машины, выпущенные до 1992 года, то следует задать запрос, который представляет конъюнкцию целей:

Goal car( X, Y, _ , _ ), Y < 1992.

X = “volvo” Y = 1990

X = "toyota" Y = 1988

2 solutions.

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

year( volvo, 1990 ).

year( toyota, 1988 ).

year( ford, 1994 ).

color( volvo, red ).

color( toyota, black ).

color( ford, white ).

cost( volvo, 2000 ).

cost( toyota, 2500 ).

cosr( ford, 3000 ).

В случае необходимости атрибуты можно собрать в единое целое с использованием переменных при помощи правила:

car( M, Y, C, P ) :– year( M, Y ), color( M, C ), cost( M, P ).

Правило в данном случае является обобщением всех фактов.

Определим теперь запрос, выполняющий поиск старых автомобилей, в виде правила «старый автомобиль»:

old_car( M, Y ) :- car( M , Y, _ , _ ), Y < 1992.

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

Goal: old_car( X, Y ).

Даже уже в этой простой программе мы вплотную подошли к одному из определений базы знаний. База знаний – это набор фактов и правил. Пока у нас было описание машин в виде фактов, это была база данных. Как только программу дополнили правилами, т.е. указали способ использования данных, мы перешли уже к базе знаний.

4. Любитель проводить аналогию между различными языками программирования уже догадался, что Пролог-программа ведет себя так, как если бы каждая строка программы начиналась с ключевого слова IF (ЕСЛИ). Поэтому разветвляющиеся алгоритмы реализуются в Прологе достаточно прямолинейно.

Программа решение квадратного уравнения – типичный пример реализации на Прологе разветвляющегося алгоритма. В комментариях приведена интерпретация предикатов.

predicates

solve( 0real, real, real ) % Запуск программы

reply( real, real, real ) % Ветви вычислений

clauses

solve( A, B, C ) :–

D = B * B – 4 * A * C, % Вычисление дискриминанта

reply( A, B, D ), nl. % Здесь запускаются разветвления вычислительного процесса

reply( _ , _ , D) :– D < 0,

write( "No solution" ).

reply( A, B, D ) :– D = 0,

X = - B / ( 2 * A ), write( "x1,2=", X ).

reply( A, B, D ) :– D > 0,

SqrtD = sqrt( D ),

X1 = ( - B + SqrtD) / ( 2 * A ),

X2 = ( - B – SqrtD) / ( 2 * A ),

write( "x1 = ", X1," and x2 = ", X2 ).

Goal solve( 3, 4, 5 ).

На этом примере видно, что главный способ реализации разветвлений в Пролог-программе – обращение к некоторому предикату, который реализуется с проверкой заданных условий (в нашем случае – предикат reply).

В этом примере также видим использование анонимной переменой в первом предложении предиката reply:

reply( _ , _ , D) :– D < 0, write( "No solution" ).

Оно говорит, что если дискриминант D меньше нуля, неважно, какие значения имеют коэффициенты A и B.

Рассмотрим другой пример в качестве упражнения по автоматизации логического вывода. Имеется следующая задача из психологического практикума.

Бутси – коричневая кошка. Корни – черная кошка. Мак – рыжая кошка. Флэш, Ровер, Спот – собаки, Ровер – рыжая, а Спот – белая. Все животные, которыми владеют Том и Кейт, имеют родословные. Том владеет всеми черными и коричневыми животными, а Кейт владеет всеми собаками небелого цвета, которые не являются собственностью Тома. Алан владеет Мак, если Кейт не владеет Бутси и если Спот не имеет родословной. Флэш – пятнистая собака. Определить, какие животные не имеют хозяев. (Ответ: Спот).

Для интерпретации формул исчисления предикатов требуется задать области интерпретации предметных переменных, что делается в разделе Domains

Domains

animal_name, color, name = string

Описание предикатов включает имена предикатов и перечисление имен предметных переменных:

Predicates

cat( animal_name )

dog( animal_name )

color( animal_name, color )

have( name, animal_name )

rodosloмnaya(animal_name )

animal( animal_name)

Факты и правила следующие:

Clauses

/* Факты, перечисляющие клички и расцветки животных */

cat( butsi ). cat( korni ). cat( mac ).

dog( rover ). dog( fles ). dog( spot ).

color( butsi, brown ).

color( korni, black ).

color( mac, yellow ).

color( rover, yellow ).

color( spot, white ).

color( fles, black_and_white ).

/* Животное – это кошка или собака*/

animal( X ) :– cat( X ); dog( X ).

/* Животные, имеющие родословные */

rodoslovnaya( X ) :– animal( X ), have( tom, X ).

rodoslovnaya( X ) :– animal( X ), have( keit, X ).

/* Том владеет всеми черными или коричневыми животными */

have( tom, X ) :– color( X, black ); color( X, brown ).

/* Кейт владеет собаками */

have( keit, X ):–dog( X ),

not( color( X, white )),

not( have( tom, X )).

/* Алан владеет Мак */

have( alan, mac ) :– not( have( keit, butsi )),

not( rodoslovnaya( spot )).

/* Цель – найти животное Х, не имеющее владельца */

goal

animal( X ), not( have( _ , X )),write( X ).

Цель организует запрос к программе и выводит результат. Процесс доказательства включает в себя как поиск нужных подстановок, которые делают истинными утверждения, так и выполнение встроенных предикатов. Например, not – встроенный предикат отрицания, write( ) – вывод значения переменной.

Каждое предложение раздела Clauses представляет собой формулу вида:

D <– A & B & … & C.

Например, предложение

rodoslovnaya(X):–animal(X), have(tom,X).

представляет собой формулу

animal(X) & have(tom,X) –> rodoslovnaya(X),

причем порядок следования элементов конъюнкции определяет последовательность процесса доказательства по методу резолюций и может имеет важное значение.