KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Иван Братко - Программирование на языке Пролог для искусственного интеллекта

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

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Иван Братко, "Программирование на языке Пролог для искусственного интеллекта" бесплатно, без регистрации.
Перейти на страницу:

% ограничения Предел и выдает новый список Деревья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 будет использоваться как величина отступа для поддеревьев.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*