Добавил:
natribu.org Все что нашел в интернете скидываю сюда Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Точно Не проект 2 / Не books / Источник_1

.pdf
Скачиваний:
10
Добавлен:
01.02.2024
Размер:
20.67 Mб
Скачать

360

Глава 6

 

 

ЗКР=[[c,s,10,3],[s,s,14,0]], OTK=[[b,c,8,4],[d,s,11,1],[g1,a,15,15]], ЗКР=[[a,c,6,5],[c,s,10,3],[s,s,14,0]], OTK=[[a,b,6,5],[d,s,11,1],[g1,a,15,15]], ЗКР=[[b,c,8,4],[c,s,10,3],[s,s,14,0]], OTK=[[d,s,11,1],[g1,a,15,15]], ЗКР=[[a,b,6,5],[b,c,8,4],[c,s,10,3],[s,s,14,0]], OTK=[[c,d,9,2],[g1,a,15,15]], ЗКР=[[a,b,6,5],[b,c,8,4],[d,s,11,1],[s,s,14,0]], OTK=[[a,c,5,4],[b,c,7,3],[g1,a,15,15]], ЗКР=[[c,d,9,2],[d,s,11,1],[s,s,14,0]], OTK=[[b,c,7,3],[g1,a,14,14]], ЗКР=[[a,c,5,4],[c,d,9,2],[d,s,11,1],[s,s,14,0]], OTK=[[a,b,5,4],[g1,a,14,14]], ЗКР=[[b,c,7,3],[c,d,9,2],[d,s,11,1],[s,s,14,0]], OTK=[[g1,a,14,14]], ЗКР=[[a,b,5,4],[b,c,7,3],[c,d,9,2],[d,s,11,1],[s,s,14,0]].

Решение=[[g1,a,14,14],[a,b,5,4],[b,c,7,3],[c,d,9,2], [d,s,11,1],[s,s,14,0]].

6.11.3. Поиск решений в И/ИЛИ графах

Поиск решений в И/ИЛИ графах заключается в нахождении подграфа решения (см. § 2.3). В процессе поиска строятся потенциальные подграфы решений, которые определенным образом представляются в памяти ЭВМ. Воспользуемся представлением, предложенным в [7]. Введем в рассмотрение два инфиксных оператора:

:– op(600, xfx, --->).

:– op(500, xfx, : ).

Тогда И/ИЛИ граф, изображенный на рисунке 2.14, можно задать с помощью фактов:

s ---> или : [a, b].

a---> и : [c, d].

c---> или : [f, g].

f---> и : [t1, t2].

g---> или :[t3, h].

b---> и : [d, i].

d ---> или : [g, h]. h ---> или : [ i ]. i ---> или : [ l ].

Здесь первый факт указывает, что задача “s” может быть решена, если решена или подзадача “a”, или подзадача “b” . Второй факт фиксирует,

Язык Пролог

361

 

 

что подзадача “a” разрешима, если решены подзадачи “c” и “d”. Терминальные вершины будем задавать с помощью фактов:

цель(t1). цель(t2). цель(t3).

Рассмотрим программирование процедуры поиска в глубину. При этом воспользуемся следующими фактами:

а) если рассматриваемая вершина является терминальной, то решение соответствующей подзадачи известно;

б) если рассматриваемая вершина – это вершина ИЛИ типа, то необходимо решить одну из подзадач;

в) если рассматриваемая вершина – это вершина И типа, то необходимо решить все подзадачи.

Определим предикат ао_поиск(Верш, РешДер), который аналогичен процедуре Depth_first-AO2, рассмотренной в § 2.3.1. Воспользуемся встроенным механизмом поиска решений пролог-системы. Дерево вывода, формируемое пролог-системой, является И/ИЛИ деревом. Оно строится методом поиска в глубину. Если какая-либо из подзадач не решена, то прологсистема автоматически возвращается к имеющейся альтернативной подзадаче и продолжает ее решение. Это существенно упрощает программирование предиката ао_поиск(Верш, РешДер), где переменная Верш соответствует вершине И/ИЛИ дерева, а переменная РешДер – поддереву решения, расположенному ниже этой вершины. Дерево решений будем представлять следующим образом [7]:

а) если Верш – терминальная вершина, то дерево решений тривиально (оно представляется вершиной Верш);

б) если Верш – это вершина ИЛИ типа, то дерево решений будет иметь вид Верш ---> Поддерево, где переменная Поддерево будет представлять одно из возможных поддеревьев решений для задачи, заданной переменной Верш;

в) если Верш – это вершина И типа, то дерево решений будет иметь вид Верш---> и: Поддеревья, где Поддеревья – список поддеревьев решений И-подзадач.

Тогда программа поиска в глубину запишется так [7]:

ао_поиск(Верш, Верш): –

% правило а)

цель(Верш).

 

ао_поиск(Верш, Верш---> Дер): –

% правило б)

Верш---> или : Вершины, элемент(Верш1, Вершины), ао_поиск(Верш1, Дер).

ао_поиск(Верш, Верш---> и: Деревья): – % правило в)

362

Глава 6

 

 

Верш---> и : вершины, ао_поиск_для_всех_вершин(Вершины, Деревья).

ао_поиск_для_всех_вершин([ ], [ ] ). ао_поиск_для_всех_вершин([Верш Вершины], [Дер Деревья] ): –

ао_поиск(Верш, Дер), ао_поиск_для_всех_вершин(Вершины, Деревья).

При запросе

? – ао_поиск(s, РешДер).

получим два решения:

РешДер = s---

> (a---

> и: [c---

> (f---

> и: [t1, t2] ),

 

 

d---

> (g---

> t3)

] );

РешДер = s---

> (a---

> и: [c---

> (g---

> t3),

 

 

d---

> (g---

> t3)

]).

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

6.11.4. Поиск в пространстве версий

Рассмотрим задачу формирования понятий по предъявленным примерам. Одно из решений данной задачи основано на поиске в пространстве версий в соответствии с алгоритмом Митчелла (см §4.3.3). В алгоритме рассматриваются два множества: G – множество наиболее общих понятий; S – множество наименее общих (наиболее специализированных) понятий. В ходе предъявления примеров область действия понятий, входящих в G, сужается, а область действия понятий, входящих в S, расширяется. Иными словами, в процессе поиска понятия из G специализируются, а понятия из S – обобщаются. Поиск заканчивается успешно, когда множества G и S будут содержать одно и то же понятие. Рассмотрим пример из § 4.3.3. Пусть каждый из объектов представляется списком

[Размер, Цвет, Форма].

Например, круг среднего размера красного цвета представляется в виде списка

[средний, красный, круг],

Язык Пролог

363

 

 

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

[средний, красный, Х]

представляет все объекты среднего размера и красного цвета. Этот вектор признаков будет охватывающим для вектора [средний, красный, круг].

Определим отношение охватывает(P,Q), устанавливающее идентичность векторов признаков P и Q или выясняющее, охватывает ли вектор признаков Р вектор Q [77]:

охватывает([ ], [ ]).

% пустые векторы идентичны

охватывает([H1|T1], [H2|T2]): – % переменные Н1 и Н2 var(H1), var(H2), %охватывают друг друга охватывает(Т1, Т2).

охватывает([H1|T1], [H2|T2]): – %переменная охватывает var(H1), atom(H2), % константу охватывает(Т1,Т2).

охватывает([H1|T1], [H2|T2]): – % отношение имеет место, atom(H1), atom(H2), H1=H2, %если константы сопоставимы охватывает(T1, T2).

Алгоритм Митчелла требует выяснения, будет ли некоторое понятие строго более общим, чем другое. Это можно сделать с помощью правила:

более_общее(X, Y): – not охватывает(Y, X), охватывает(X, Y).

В ходе поиска необходимо выполнять операции обобщения и специализации. Определим для этого соответствующие предикаты. Предикат обобщения

обобщить(Гипотеза, Пример, Обобщение),

выполняющий поиск значения переменной Обобщение, которое минимально обобщает понятие-кандидат, представляемое аргументом Гипотеза, и охватывает понятие, заданное аргументом Пример. С этой целью рекурсивно сопоставляются элементы векторов признаков Гипотеза и Пример. Если соответствующие элементы двух векторов признаков сопоставимы, то в результирующий вектор Обобщение помещается элемент вектора Гипотеза. Если соответствующие элементы векторов не сопоставимы, то в соответствующую позицию вектора Обобщение помещается анонимная переменная [77]:

364

Глава 6

 

 

% обобщение понятия-кандидата

 

обобщить([ ], [ ]).

% Выход из рекурсии

обобщить([H1|T1], [H2|T2], [H1|T3]): –

 

not(H1\=H2),

% Сопоставить без присвоения

обобщить(Т1, Т2, Т3).

 

обобщить([H1|T1], [H2|T2], [_|T3]): –

 

H1\=H2,

 

обобщить(Т1, Т2, Т3).

 

Минимальную специализацию понятий-кандидатов будем выполнять с помощью предиката

специализировать(Гипотеза, Пример, Подстановки),

где Гипотеза и Пример – это векторы признаков соответственно специализируемого понятия и примера. Подстановки – список признаков понятий, в котором возможные значения того или иного признака представляются в виде подсписка констант. Например,

[[маленький, средний, большой], [желтый, зеленый, красный], [круг, квадрат, треугольник]].

В ходе специализации переменные вектора признаков понятия-кандидата заменяются соответствующей константой из списка Подстановки [77]:

специализировать([H1|_], [H2|_], [L|_]): – var(H1),

элемент(H1, L), H1\=H2. специализировать([_|T1], [_|T2], [_|T3]): –

специализировать(Т1, Т2, Т3).

Отметим два обстоятельства. Во-первых, данный предикат специализирует понятие-кандидат таким образом, чтобы оно не охватывало Пример. Это обеспечивается проверкой условия H1\=H2. Во-вторых, если вызвать данный предикат, то будет выполнена подстановка константы только вместо первой переменной. Для того, чтобы обеспечить выполнение всех возможных специализаций, вызов рассмотренного предиката будет выполняться внутри цели bagof.

В алгоритме Митчелла необходимо специализировать понятиякандидаты множества G. Определим для этого предикат

специализировать_мн-во(G, Нов_G, Пример, Подстановки).

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

Язык Пролог

365

 

 

вое множество понятий-кандидатов Нов_G. Предикат определяется рекурсивно [77]:

специализировать_мн-во([ ], [ ], _, _).

специализировать_мн-во([HG|TG],Нов_G,Пример,Подстановки): – охватывает(HG, Пример), (bagof(HG,специализировать(HG,Пример,Подстановки),

Нов_G_Голова); Нов_G_Голова=[ ]),

специализировать_мн-во(TG, Нов_G_Хвост, Пример, Подстановки), соединить(Нов_G_Голова, Нов_G_Хвост, Нов_G).

специализировать_мн-во([HG|TG], [HG|Нов_G_Хвост], Пример,Подстановки): –

not охватывает(HG, Пример),

специализировать_мн-во(TG, Нов_G_Хвост, Пример,Подстановки).

Аналогично определим предикат, обобщающий понятия-кандидаты из множества S:

обобщить_мн-во(S, Нов_S, Пример).

Данный предикат рекурсивно просматривает понятия из множества S и выполняет их минимальное обобщение по сравнению с понятиемпримером:

обобщить_мн-во([ ], [ ], _, _).

обобщить_мн-во([HS|TS], Нов_S, Пример): – not охватывает(HS, Пример),

(bagof(X, обобщить(HS, Пример, X), Нов_S_Голова); Нов_S_Голова=[ ]),

обобщить_мн-во(TS, Нов_S_Хвост, Пример), соединить(Нов_S_Голова, Нов_S_Хвост, Нов_S).

обобщить_мн-во([HS|TS], [HS|Нов_S_Хвост], Пример): – охватывает(HS, Пример),

обобщить_мн-во(TS, Нов_S_Хвост, Пример).

Для реализации алгоритма Митчелла также определим предикат удаления

удалить(X, L, C, Нов_L),

который выполняет удаление элемента Х из списка условие С. В результате формируется список Нов_L ко определяется с помощью встроенного предиката

L, если не выполняется

. Данный предикат лег- bagof:

366

Глава 6

 

 

удалить(X, L, C, Нов_L): –

(bagof(X, (элемент(X, L), not C), Нов_L); Нов_L=[ ]).

Напишем программу, использующую введенные выше предикаты и выполняющую поиск в пространстве понятий в полном соответствии с алгоритмом Митчелла, рассмотренном в § 4.3.3. Для этого введем предикат

v_поиск(Пример, G, S, Нов_G, Нов_S, Подстановки).

Здесь все переменные имеют введенную ранее интерпретацию. В случае положительного примера происходит исключение всех понятий Х из G, которые не охватывают пример. Затем обобщаются те понятия, входящие в S, которые не сопоставимы с предъявляемым примером. В заключение из S сначала удаляются те понятия, которые являются более общими, чем любое другое понятие, входящее в S, а затем – понятия, которые охватывают некоторые понятия, входящие в G. В случае предъявления отрицательного понятия, из множества S исключаются все понятия, которые охватывают пример. После этого выполняется специализация понятий, входящих в G. Затем из G исключаются все понятия менее общие, чем любое другое понятие, входящее в G. И наконец, из G исключаются понятия, не охватывающие соответствующих понятий, входящих в S. Предикат v_поиск определится следующим образом [77]:

v_поиск(отрицат(Пример), G, S, Нов_G, Нов_S, Подстановки): – удалить(X, S, охватывает(Х, Пример), Нов_S), специализировать_мн-во(G,Конкр_G, Пример, Подстановки), удалить(X, Конкр_G, (элемент(Y, Конкр_G),

более_общее(Y, X)),Сокращенное_G), удалить(X, Сокращенное_G, (элемент(Y, Нов_S),

not охватывает(X, Y)), Нов_G).

v_поиск(положит(Пример), G, [ ], Нов_G, [Пример], _ ): – удалить(X, G, not охватывает(X, Пример), Нов_G).

v_поиск(положит(Пример), G, S, Нов_G, Нов_S, _ ): – удалить(X, G, not охватывает(X, Пример), Нов_G), обобщить_мн-во(S, Обобщ_S, Пример), удалить(Х,обобщ_S,(элемент(Y,обобщ_S),

более_общее(Y, X)),Сокращенное_S), удалить(X, Сокращенное_S, not(элемент(Y, Нов_G),

охватывает(Y, X)),Нов_S).

В соответствии с алгоритмом Митчелла (алгоритмом исключения по- нятий-кандидатов), вызов предиката v_поиск выполняется до тех пор, пока множества G и S не совпадут:

Язык Пролог

367

 

 

исключ_понятий_кандидатов([G], [S], _ ): – охватывает(G, S), охватывает(S, G), write('искомое понятие – '), write(G), nl.

исключ_понятий_кандидатов(G, S, Подстановки): – write('G='), write(G), nl, write('S='), write(S), nl, write('Введите пример:'), read(Пример), v_поиск(Пример, G, S, Нов_G, Нов_S, Подстановки),

иключ_понятий_кандидатов(Нов_G,Нов_S,Подстановки).

Проиллюстрируем работу программы с помощью следующего вызова

? – исключ_понятий_кандидатов([[ _, _, _]], [ ], [[маленький, средний, большой], [желтый, зеленый, красный],.

[круг, квадрат, треугольник]]).

G=[[ _0048, _0050, _0058]] S=[ ]

Введите пример: положит([средний, круг, красный]). G=[[ _0048, _0050, _0058]]

S=[[средний, круг, красный]

Введите пример: отрицат([средний, квадрат, зеленый]). G=[[ _07С0, круг, _07D0], [ _ 0748, 0750, красный]] S=[[средний, круг, красный]

Введите пример: положит([большой, круг, красный]). G=[[ _07С0, круг, _07D0], [ _ 0748, 0750, красный]] S=[[ _13F8, круг, красный]]

Введите пример: отрицат([средний, треугольник, красный]). G=[[ _07С0, круг, _07D0]]

S=[[ _13F8, круг, красный]]

Введите пример: отрицат([средний, круг, зеленый]). Искомое понятие – [ _231C, круг, красный]

Yes.

Здесь числовые кодовые комбинации, начинающиеся с символа подчеркивания, – переменные. Поэтому сформированный программой вектор признаков [ _231C, круг, красный] соответствует понятию “красный круг”.

6.11.5. Поиск в сети фреймов

Рассмотрим сеть иерархически упорядоченных фреймов, представляющих графические объекты (рисунок 6.12).

Фрейм на языке Пролог можно представить совокупностью предикатов

фрейм(Имя-фрейма,Имя-слота,Фацет,Значение), каждый из которых опре-

деляет значение соответствующего фацета (аспект) слота. Например, корневой графический объект можно описать предикатом

368

Глава 6

 

 

фрейм(граф-объект, позиция, значение, [0, 0]).

Рисунок 6.12 – Иерархия графических объектов

Фрейм прямоугольника отличается от обобщенного графического объекта наличием дополнительных слотов:

фрейм(прямоугольник, is_a, значение, граф-объект). фрейм(прямоугольник, сторона-х, значение, 1). фрейм(прямоугольник, сторона-х, диапазон, [ 1, 511]). фрейм(прямоугольник, сторона -y, значение, 2). фрейм(прямоугольник, сторона -y, диапазон, [ 1, 311]).

фрейм(прямоугольник, площадь, если-нужно, площадь-прямоугольника).

Поиск значений по иерархии фреймов можно выполнить с помощью предиката:

поиск(Фрейм, Слот, Фацет, Значение):- фрейм(Фрейм, Слот, Фацет, Значение).

поиск(Фрейм, Слот, Фацет, Значение):- фрейм(Фрейм, is_a, значение, Род-фрейм), поиск(Род-фрейм, Слот, Фацет, Значение).

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

определить-значение(Фрейм, Слот, Значение):- поиск(Фрейм, Слот, Фацет, 3), (Фацет = значение, !, Значение = 3; Фацет = если-нужно,

Демон = .. [ 3, Фрейм, Слот, Значение ], call(Демон)), ! .

Язык Пролог

369

 

 

В этом случае процедуры-демоны должны представляться в виде предикатов:

имя_процедуры_демона(Фрейм, Слот, Значение):- . . .

Например:

площадь-прямоугольника(Фрейм. Слот, Значение):- определить-значение(Фрейм, сторона-х, Х), определить-значение(Фрейм, сторона-y, Y), Значение is X * Y, !.

Вопросы для самопроверки

1.Приведите примеры следующих основных понятий языка Пролог: константа, переменная, список, факт, правило, терм.

2.Сформулируйте правила сопоставления термов, используемые в Прологе.

3.Объясните на примере декларативный и процедурный смысл прологпрограммы.

4.Постройте дерево вывода для целевого утверждения member(c,[a, d, c]).

5.Как в пролог-программе объявить оператор? Как специфицируются типы операторов?

6.Объясните на примере порядок вычисления арифметического выражения, представив его в виде древовидной структуры.

7.Каким образом выполняется оператор is?

8.Какие формы записи списков используются в Прологе?

9.Приведите общую схему предиката, выполняющего обработку каждого элемента списка.

10.Определите на языке Пролог предикаты удалить и реверс, обрабатывающие списки рекурсивно.

11.Объясните на примере назначение предиката отсечения.

12.Что в языке Пролог называют группой?

13.Как в Прологе реализуется отрицание? Приведите примеры.

14.Что называют метапеременными (метаусловиями)?

15.Определите с помощью метапеременных конструкцию “если-то-иначе”. Приведите пример её использования.

16.Как в Прологе организовать итерационный цикл? Определите предикат все_решения(Условие,X), обеспечивающий поиск всех значений X, при которых выполняется метаусловие Условие(X).

17.Перечислите и объясните процедурный смысл встроенных предикатов, осуществляющих ввод-вывод.

18.Определите на Прологе предикат, осуществляющий ввод арифметического выражения с клавиатуры (из файла) и вывод его значения на экран (в файл).

19.Объясните следующие встроенные предикаты: var, nonvar, atom, atomic, integer.

20.Объясните предикаты: name(A,L), functor(T,F,A), arg(N,T,A), T=..L.

21.Объясните предикаты: assert(X), asserz(X), retract(X), consult(F), save(F), restore(F).

Соседние файлы в папке Не books