Рейтинговые книги
Читем онлайн Программирование на языке Пролог для искусственного интеллекта - Иван Братко

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 64 65 66 67 68 69 70 71 72 ... 94

% ограничения Предел и выдает новый список Деревья1

% с "решающим статусом" ЕстьРеш.

расширспис( Деревья, Предел, Деревья1, ЕстьРеш) :-

 выбор( Деревья, Дер, ОстДер, Предел, Предел1),

 расширить( Дер, Предел1, НовДер, ЕстьРеш1),

 собрать( ОстДер, НовДер, ЕстьРеш1, Деревья1, ЕстьРеш).

% "продолжить" решает, что делать после расширения

% списка деревьев

продолжить( да, Верш, С, Поддеревья, _,

 решдер( Верш, F, Поддеревья), да): -

 оценка( Поддеревья, H), F is С + H, !.

продолжить( никогда, _, _, _, _, _, никогда) :- !.

продолжить( нет, Верш, С, Поддеревья, Предел,

 НовДер, ЕстьРеш) :-

 оценка( Поддеревья, H), F is С + H, !,

 расширить( дер( Верш, F, С, Поддеревья), Предел,

  НовДер, ЕстьРеш).

% "собрать" соединяет результат расширения дерева со списком деревьев

собрать( или : _, Дер, да, Дер, да):- !. % Есть решение ИЛИ-списка

собрать( или : ДД, Дер, нет, или : НовДД, нет) :-

 встав( Дер, ДД, НовДД), !.  % Нет решения ИЛИ-списка

собрать( или : [], _, никогда, _, никогда) :- !.

  % Больше нет кандидатов

собрать( или:ДД, _, никогда, или:ДД, нет) :- !.

  % Есть еще кандидаты

собрать( и : ДД, Дер, да, и : [Дер Э ДД], да ) :-

 всереш( ДД), !.             % Есть решение И-списка

собрать( и : _, _, никогда, _, никогда) :- !.

  % Нет решения И-списка

собрать( и : ДД, Дер, ДаНет, и : НовДД, нет) :-

 встав( Дер, ДД, НовДД), !.  % Пока нет решения И-списка

% "расшлист" формирует дерево из вершины и ее преемников

расшлист( Верш, С, дер( Верш, F, С, Оп : Поддеревья)) :-

 Верш---> Оп : Преемники,

 оценить( Преемники, Поддеревья),

 оценка( Оп : Поддеревья, H), F is С + H.

 оценить( [], []).

оценить( [Верш/С | ВершиныСтоим], Деревья) :-

 h( Верш, H), F is С + H,

 оценить( ВершиныСтоим, Деревья1),

 встав( лист( Верш, F, С), Деревья1, Деревья).

% "всереш" проверяет, все ли деревья в списке "решены"

всереш([]).

всереш( [Дер | Деревья] ) :-

 реш( Дер),

 всереш( Деревья).

реш( решдер( _, _, _ ) ).

реш( решлист( _ , _) ).

f( Дер, F) :-              % Извлечь F-оценку дерева

 arg( 2, Дер, F), !.       % F - это 2-й аргумент Дер

% встав( Дер, ДД, НовДД) вставляет Дер в список

% деревьев ДД; результат - НовДД

встав( Д, [], [Д] ) :- !.

встав( Д, [Д1 | ДД], [Д, Д1 | ДД] ) :-

 реш( Д1), !.

встав( Д, [Д1 | ДД], [Д1 | ДД1] ) :-

 реш( Д),

 встав( Д, ДД, ДД1), !.

встав( Д, [Д1 | ДД], [Д, Д1 | ДД] ) :-

 f( Д, F), f( Д1, F1), F=< F1, !.

встав( Д, [Д1 | ДД], [ Д1 | ДД1] ) :-

 встав( Д, ДД, ДД1).

% "оценка" находит "возвращенную" F-оценку И/ИЛИ-списка деревьев

оценка( или :[Дер | _ ], F) :-

 % Первое дерево ИЛИ-списка - наилучшее

 f( Дер, F), !.

оценка( и :[], 0) :- !.

оценка( и : [Дер1 | ДД], F) :-

 f( Дер1, F1),

 оценка( и : ДД, F2),

 F is F1 + F2, !.

оценка( Дер, F) :-

 f( Дер, F).

% Отношение выбор( Деревья, Лучшее, Остальные, Предел, Предел1):

% Остальные - И/ИЛИ-список Деревья без его "лучшего" дерева

% Лучшее; Предел - ограничение для Списка Деревья, Предел1 -

% ограничение для дерева Лучшее

выбор( Оп : [Дер], Дер, Оп : [], Предел, Предел) :- !.

  % Только один кандидат

выбор( Оп : [Дер | ДД], Дер, Оп : ДД, Предел, Предел1) :-

 оценка( Оп : ДД, F),

 ( Оп = или, !, мин( Предел, F, Предел1);

   Оп = и, Предел1 is Предел - F).

мин( А, В, А) :- А < В, !.

мин( А, В, В).

Рис. 13.12. Программа поиска с предпочтением в И/ИЛИ-графе.

Еще одна процедура

собрать( ОстДер, НовДер, ЕстьРеш1, НовДеревья, ЕстьРеш)

связывает между собой несколько объектов, с которыми работает расширспис. НовДер — это расширенное дерево, взятое из списка деревьев процедуры расширспис, ОстДер — остальные, не измененные деревья из этого списка, а ЕстьРеш1 указывает на "решающий статус" дерева НовДер. Процедура собрать имеет дело с несколькими случаями в зависимости от значения ЕстьРеш1, а также от того, является ли список деревьев И-списком или ИЛИ-списком. Например, предложение

собрать( или : _, Дер, да, Дер, да).

означает: в случае, когда список деревьев — это ИЛИ-список и при только что проведенном расширении получено решающее дерево, считать, что задача, соответствующая всему списку деревьев, также решена, а ее решающее дерево и есть само дерево Дер. Остальные случаи легко понять из текста процедуры собрать.

Для отображения решающего дерева можно определить процедуру, аналогичную процедуре отобр (рис. 13.8). Оставляем это читателю в качестве упражнения.

13.4.3. Пример отношений, определяющих конкретную задачу: поиск маршрута

Давайте теперь сформулируем задачу нахождения маршрута как задачу поиска в И/ИЛИ-графе, причем сделаем это таким образом, чтобы наша формулировка могла бы быть непосредственно использована процедурой и_или рис. 13.12. Мы условимся, что карта дорог будет представлена при помощи отношения

связь( Гор1, Гор2, P)

означающего, что между городами Гор1 и Гор2 существует непосредственная связь, а соответствующее расстояние равно P. Далее, мы допустим, что существует отношение

клпункт( Гор1-Гор2, Гор3)

имеющее следующий смысл: для того, чтобы найти маршрут из Гор1 в Гор2, следует рассмотреть пути, проходящие через Гор3 (Гор3 — это "ключевой пункт" между Гор1 и Гор2). Например, на карте рис. 13.1 f и g — это ключевые пункты между а и z:

клпункт( a-z, f).  клпункт( a-z, g).

Мы реализуем следующий принцип построения маршрута:

 Для того, чтобы найти маршрут между городами X и Z, необходимо:

  (1) если между X и Z имеются ключевые пункты Y1, Y2, …, то найти один из путей:

   путь из X в Z через Y1, или

   путь из X в Z через Y2, или

   …

  (2) если между X и Z нет ключевых пунктов, то найти такой соседний с X город Y, что существует маршрут из Y в Z.

Таким образом, мы имеем два вида задач, которые мы будем представлять как

(1) X-Z         найти маршрут из X в Z

(2) X-Z через Y найти маршрут из X в Z, проходящий через Y

Здесь 'через' — это инфиксный оператор более высокого приоритета, чем '-', и более низкого, чем '--->'. Теперь можно определить соответствующий И/ИЛИ-граф явным образом при помощи следующего фрагмента программы:

:- op( 560, xfx, через)

% Правила задачи X-Z, когда между  X  и  Z

% имеются ключевые пункты,

% стоимости всех дуг равны 0

X-Z ---> или : СписокЗадач

 :- bagof( ( X-Z через Y)/0, клпункт( X-Z, Y),

 СписокЗадач), !.

% Правила для задачи X-Z без ключевых пунктов

X-Z ---> или : СписокЗадач

 :- bagof( ( Y-Z)/P, связь( X, Y, P), СписокЗадач).

% Сведение задачи типа "через" к подзадачам,

% связанным отношением И

X-Z через Y---> и : [( X-Y)/0, ( Y-Z)/0].

 цель( X-X) % Тривиальная задача: попасть из X в X

Функцию h можно определить, например, как расстояние, которое нужно преодолеть при воздушном сообщении между городами.

Упражнение

13.4. Напишите процедуру

отобр2( РешДер)

для отображения решающего дерева, найденного программой и_или рис. 13.12. Формат отображения пусть будет аналогичен тому, что применялся в процедуре отобр (рис. 13.8), так что процедуру отобр2 можно получить, внеся в отобр изменения, связанные с другим представлением деревьев. Другая полезная модификация — заменить в отобр цель write( Верш) на процедуру, определяемую пользователем

печверш( Верш, H)

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

1 ... 64 65 66 67 68 69 70 71 72 ... 94
На этой странице вы можете бесплатно читать книгу Программирование на языке Пролог для искусственного интеллекта - Иван Братко бесплатно.
Похожие на Программирование на языке Пролог для искусственного интеллекта - Иван Братко книги

Оставить комментарий