Задача с ханойской башней
Задача с ханойской башней (рис. 13.6) является еще одним классическим примером эффективного применения схемы декомпозиции AND/OR. Для упрощения рассмотрим описанную ниже простую версию этой задачи, содержащую только три диска.
Даны три оси, 1, 2 и 3, и три диска, а, Ь и с (из них а - самый маленький и с -самый большой). Первоначально все диски нанизаны на ось 1. Задача состоит в том, чтобы перенести их все на ось 3. Разрешено переносить одновременно только один диск и нельзя класть диск большего диаметра на диск меньшего диаметра.
Юшшм
1 2 3
Рис. 13.6. Задача с ханойской башней
Такую задачу можно рассматривать как задачу достижения следующего множества целей.
Часть II.Применение языка Prolog в области искусственного интеллекта
1. Диск а на оси 3.
2. Диск Ь на оси 3.
3. Диск с на оси 3.
К сожалению, эти цели не являются независимыми. Например, диск а можно немедленно нанизать на ось 3, достигнув первой цели. Но это помешает достижению двух других целей (если мы не откажемся от непосредственного достижения первой цели). К счастью, имеется удобный способ упорядочения процесса достижения этих целей, такой, что решение можно легко найти на основании этого упорядочения. Требуемую последовательность достижения всех целей можно определить с помощью следующих рассуждений: цели 3 (диск с на оси 3) достичь сложнее всего, поскольку для перемещения диска с необходимо преодолеть больше всего ограничений. Хорошая идея, которая часто оказывается продуктивной в подобных ситуациях, состоит в том, что вначале следует попытаться достичь самой сложной пели. В основе этого принципа лежит наблюдение, что если другие цели не являются такими труднодостижимыми (не связаны с преодолением таких ограничений, как самая трудная), то можно надеяться, что их удастся достичь без необходимости отмены результатов достижения этой самой трудной цели.
Таким образом, стратегия решения задачи, которая вытекает из этого принципа, состоит в следующем:
вначале достичь дели "диск с на оси 3"; затем достичь оставшихся целей.
Но первой из этих целей нельзя достичь немедленно: в начальной ситуации диск с невозможно переместить сразу же, поскольку на нем лежат еще два диска. Поэтому вначале подготовим этот ход и уточним нашу стратегию следующим образом.
1. Обеспечить перемещение с оси 1 на ось 3 диска с.
2. Перенести с оси 1 на ось 3 диск с.
3. Достичь оставшихся целей — диск а на оси 3 и диск Ь на оси 3.
Диск с можно перенести с оси 1 на ось 3, если оба оставшихся диска, а и Ь, нанизаны на ось 2. Поэтому наша первоначальная задача переноса с оси 1 на ось 3 дисков a, b и с сводится к трем перечисленным ниже подзадачам.
Чтобы переместить с оси 1 на ось 3 диски а, Ь и с, необходимо выполнить следующее.
1. Переместить с оси 1 на ось 2 диски а и Ь.
2. Переместить с оси 1 на ось 3 диск с.
3. Переместить с оси 2 на ось 3 диски а и Ь.
Задача 2 является тривиальной (решение состоит из одного хода). Две другие подзадачи можно решить независимо от задачи 2, поскольку диски а и b можно переносить независимо от положения диска с. Чтобы решить задачи 1 и 3, можно применить тот же принцип декомпозиции (на этот раз самой сложной является задача перемещения диска Ь). В соответствии с этим задача 1 сводится к трем перечисленным ниже тривиальным подзадачам.
Чтобы переместить с оси 1 на ось 2 диски а и Ь, необходимо выполнить следующее.
1. Переместить с оси 1 на ось 3 диск а.
2. Переместить с оси 1 на ось 2 диск to.
3. Переместить с оси 3 на ось 2 диск а.
13.2.3. Формулировка процесса игры в виде графа AND/OR
Такие игры, как шахматы и шашки, могут естественным образом рассматриваться как задачи, представленные в виде графов AND/OR. Подобные игры называются играми с двумя участниками, с полной информацией, и здесь предполагается, что в
Глава 13. Декомпозиция задач играфы AND/OR
них могут быть только два возможных исхода — победа и поражение. (Игры с тремя исходами • — победа, поражение или ничья — также могут рассматриваться как имеющие только два исхода: победа и отсутствие победы.) По мере того как два игрока по очереди делают ходы, возникают позиции двух типов, в зависимости от того, кто должен ходить. Назовем двух игроков свой и чужой, поэтому два типа позиций состоят в следующем: позиция сййШ) хода и позиция чужого хода. Предположим, что игра начинается с позиции своего хода ?. Каждый вариант своего хода в этой позиции приводит к созданию одной из позиций чужого хода, Qi, Оз. ... (рис. 13.7). Кроме того, каждый из вариантов чужого хода в позиции Qi приводит к созданию одной из
позиций Rn, Ки............. В дереве AND/OR (рис. 13.7) узлы соответствуют позициям, а
дуги — возможным ходам. Уровни своего хода чередуются с уровнями чужого хода. Чтобы выиграть в начальной позиции, Р, необходимо найти ход, переводящий игру из позиции Р в позицию Qi, для некоторого i, таким образом, чтобы позиция Qi была выигрышной. Поэтому позиция Р является выигрышной, если выигрышной является позиция Qi, или Сь, или ... . Итак, позиция Р представляет собой узел OR. Для всех i позиция Q* является позицией чужого хода, поэтому, если она должна быть выигрышной для своего игрока, то необходимо добиться, чтобы ее можно было выиграть после любого чужого хода. Поэтому позиция Q] является выигрышной, если выигрышными являются все позиции, и J^i, и R;?, и .... В соответствии с этим все позиции чужого хода являются узлами AND. Целевые узлы представляют собой позиции, выигранные согласно правилам данной игры; например, в шахматах •— это позиция с чужим королем, получившим мат. Те позиции, которые проиграны согласно правилам данной игры, соответствуют неразрешимым задачам. Чтобы решить задачу достижения выигрыша в игре, необходимо найти дерево решения, гарантирующее свою победу независимо от ответов противника. Таким образом, подобное дерево решения представляет собой полную стратегию победы в игре: на любое возможное продолжение, которое может быть выбрано противником, в этом дереве стратегии есть такой ход, который приводит к победе.
позиция своего хода позиция чужого хода |
сеой лод
Рис. 13.7. Формулировка игры с двуня участниками о виде графа AND/OR; игроки обозначаются как свой и чужой
13.3. Основные процедуры поиска в графе AND/OR
В данном разделе рассматриваются только процедуры поиска хотя бы одного решения задачи, независимо от его стоимости. Поэтому для целей этого раздела можно проигнорировать стоимости связей или узлов в графе AND/OR.
Часть II. Применение языка Prolog в области искусственного интеллекта
Простейший способ организации поиска в графах AND/OR с помощью программы Prolog состоит в использовании собственного механизма поиска Prolog. Как оказалось, эта задача является тривиальной, поскольку по своему процедурному значению программа Prolog представляет собой ни что иное, как процедуру для поиска в графах AND/OR. Например, граф AND/OR, приведенный на рис. 13.4 (если не рассматривать стоимости дуг) может быть представлен с помощью следующих предложений: а :- Ь. % Узел а - это узел OR с двумя преемниками, b и с а :- с. b :- d, e. % Узел b - это узел AN D с двумя преемниками, d и е
с :- 1, д. f :- h, i.
d. д. h, i d, д и h • целевые узлы
Чтобы узнать, можно ли решить задачу а, достаточно просто задать системе следующий вопрос: ?- а.
После этого система Prolog фактически выполнит поиск в графе, приведенном на рис. 13.4,по методу поиска в глубину и ответит "yes", посетив ту часть графа поиска, которая соотаетствует дереву решения на рис. 13.4, б.
Преимуществом такого подхода к программированию поиска в графе AND/ORявляется его простота. Но этот подход имеет также перечисленные ниже недостатки.
• Он позволяет получить лишь ответ "yes" или "по", который не сопровождается также деревом решения. Дерево решения можно восстановить из трассировки программы, но такой подход становится громоздким и неэффективным, если необходимо, чтобы дерево решения было явно доступным в качестве одного из объектов в программе.
• Такую программу трудно дополнить, чтобы она позволяла также учитывать стоимости.
• Если граф AND/OR представляет собой граф общего типа, содержащий циклы, то система Prolog с ее стратегией поиска в глубину может войти в бесконечный рекурсивный цикл.
Эти недостатки будем исправлять постепенно. Вначале определим собственную процедуру поиска в глубину для графов AND/OR.
Прежде всего необходимо изменить представление графов AND/OR в программе.
Для этого введем бинарное отношение, представленное в инфиксной системе обозна
чений с помощью оператора "----- >". Например, информация о том, что узел а связан
с его двумя преемниками типа OR, будет представлена с помощью следующего пред
ложения:
а----- > or:[b,c].
Оба символа, "------ >" и ":", являются инфиксными операторами, которые можно
определить следующим образом:
:- ор[ 600, :■-■■■,-------->) .
:- ор[ 500, xfx, :) .
Поэтому полный граф AMD/OR, показанный на рис. 13.4, можно представить с помощью таких предложений:
а------ > or: [b,с] .
b> and: [d,e] .
с---- > and: !t, g] .
G---- > or:[h].
t —> or:[h,i].
goalt d). goal( g> . goal! h).
Процедуру поиска в глубину в графе AND/OR можно сформировать на основе приведенных ниже принципов.
Глава 13. Декомпозиция задач играфы AND/OR
Для поиска решения, представленного с помощью некоторого узла N, используются следующие правила.
1. Если N— целевой узел,то решение является тривиальным.
2. Если К имеет преемников OR,то найти решение с помощью одного из них (попытаться использовать их одного за другим до тех пор, пока не будет найден тот, который приведет к решению).
3. Если узел N имеет преемников AND, то найти решение для всех них (попытаться найти решения, перебирая преемников одного за другим, таким образом, чтобы решение было найдено для всех этих преемников).
Если приведенные выше правила не позволяют найти решение, то следует полагать, что задача не может быть решена.
Соответствующая программа может быть представлена следующим образом:
solvet Mode) :-goal! Node) .
solvet Bode) :-
Node--- > or:Nodes, % Узел Node - узел OR
member( Nodel, Nodes) , % Выбрать преемника Model узла Node solve ( Nodel) .
Solvef Node) :-
Node------ ? and:Modes, % Узел Mode - узел AND
SOlvealK Nodes) . % Найти решения для всех преемников узла Node soivealKM ) .
SOlvealK [Node 1 Nodes]) :-
solvet Node) , solvealK Nodes) .
где member — обычное отношение проверки принадлежности к списку. Тем не менее эта программа все еще имеет следующие недостатки.
• Не формирует дерево решения;
• Восприимчива к бесконечным циклам, в зависимости от свойств графа
AND/OR (наличия в нем циклов).
Данную программу можно легко модифицировать таким образом, чтобы она формировала дерево решения. Для этого необходимо откорректировать отношение solve, предусмотрев в нем следующие два параметра: solve(Node, Solutio.nTree)
Представим дерево решения следующим образом. Для этого могут рассматриваться три перечисленных ниже случая.
1. Если Mode — целевой узел, то соответствующим деревом решения является сам узел Node.
2. Если Node — узел OR, то дерево решения имеет следующую форму: Node>Subtree
где Subtree — дерево решения для одного из преемников узла Node.
3. Если Node — узел AND, то его дерево решения имеет форму
Node------ > and:Subtrees
где Subtrees — список деревьев решения всех преемников узла Node.
Например, в графе AND/OR (см. рис. 13.4) первое решение для верхнего узла а
может быть представлено таким образом:
а-----> b------> and:[d, е----> h]
286 Часть II. Применение языка Prolog в области искусственного интеллекта
Эти три формы дерева решения соответствуют первым трем предложениям, касающимся рассматриваемого отношения solve. Поэтому первоначальную процедуру solve можно усовершенствовать, откорректировав каждое из трех предложений; это означает, что достаточно просто ввести в предложение solve дерево решения в качестве второго параметра. Результирующая программа показана в листинге 13.1. В этой программе имеется дополнительная процедура show для отображения деревьев решения. Например, дерево решения задачи (см. рис. 13.4) отображается процедурой show в следующей форме: а —> b — > d
е—>h
Программа в листинге 13.1 все еще способна переходить в бесконечные циклы. Один из простых способов предотвращения бесконечных циклов состоит в том, что необходимо следить за текущей глубиной поиска и запрещать программе поиск сверх некоторой указанной глубины. Это можно сделать, введя еще один параметр в отношение solve: solve! Node, SolutionTree, MaxDepth)
Здесь, как и прежде, узел Mode представляет задачу, которая должна быть решена, a SolutionTree— это решение, не превышающее по глубине MaxDepth. С другой стороны, MaxDepth — это допустимая глубина поиска в графе. В том случае, если MaxDepth = 0, дальнейшее развертывание дерева не допускается; в противном случае, если MaxDepth > 0, то можно развернуть узел Kode и попытаться достичь решения с помощью его преемников, с меньшим пределом глубины MaxDepth - 1. Такое условие можно легко включить в программу, приведенную в листинге 13.1. Например, второе предложение, касающееся процедуры solve, принимает следующий вид.
solve: Mode, Node---- > Tree, MaxDepth! :-
HassDepth > 0,
Node------ > or:Modes, Ъ Узел Node - Это узел OR
raembec( Model, Nodes), % Выбрать преемника Model узла Node
Depthi is MaxDepth - 1, % Новый предел глубины
solver wodei, Tree, Depthl). i Найти решение для преемника,
<t установив меньший предел глубины
Эту процедуру поиска в глубину с ограничением по глубине можно также использовать в режиме итеративного углубления, моделируя тем самым поиск в ширину. Идея состоит в том, чтобы поиск в глубину выполнялся повторно, с увеличением каждый раз предела глубины до тех пор, пока не будет найдено решение. Это означает, что нужно попытаться решить проблему с использованием предела глубины 0, затем 1, 2 и т.д. Такая программа имеет следующий вид.
Листинг 13.1, Программа поиска в глубину для графов AND/OR.Эта программа не предотвращает возникновения бесконечных циклов. Процедура solve находит дерево решения, а процедура show отображает такое дерево. При использовании процедуры show подразумевается, что для вывода имени каждого узла достаточно одного символа
'*..... Поиск в глубину длягзафсв AND/OR
% solve ( Node, SolutionTree):
% найти дерево решения для узла Hode з графе AND/OR
:- ор( 500, xfx, : ) .
:- ор{ 600, xfx,-- > ! .
solve( Mode, Node) :- S Деревом решения для целевого узла является
i сам узел Node goal(Node) .
solve ( Mode, Node--------- > Tree) :-
Mode------ > or:Nodes, % Узел Node - это узел OR
Глава 13. Декомпозиция задам играфы AND/OR
member; Nodel, Nodes), solvet Nodel, Tree).
* Выбрать преемника Nodel узла Node
solve< Mode, Node- > and:Trees> :-
Node-- > and:Nodes, % Узел Node - это узел AMD
SOlvealM Nodes, Trees) . * Найти решения для всех преемников узла Node
% solveall{ (Model,Node2, . . . ] , [SolutionTreel,SolutionTree2, ...])
solvealK [] , [) ) .
SOlvealK [Node! Modes] , [Tree| Trees] ] :-
solve( Node, Tree),
solvealK Modes, Trees).
% Отображение дерева решения
show(Tree) :- % Отобразить дерево решения
show(Tree,0), !. % с отступом 0
% show( Tree, H): отобразить дерево решения с отступом 3
show! Node-- > Tree, H) :- !,
write(Mode), write('- > '),
HI Is H + 7, showf Tree, HI) . show( and: IT], B) :- ], % Отобразить одно дерево AMD show [T, К) .
show ( and:[TITS], H) :- !, % Отобразить список AND деревьев решения
show!T, В), tab(H) , show{ and;Ts, H! .
show( Node, H) :-write (Node) , jil.
Как и при итеративном углублении в пространстве состояний (см. главу 11), недостаток такого моделирования поиска в ширину состоит в том, что программа повторно исследует верхнюю часть пространства состояний при каждом увеличении предела глубины. С другой стороны, важным преимуществом по сравнению с оригинальной процедурой поиска в ширину является экономия пространства.
Упражнения
13.1. Доработайте программу поиска в графе AND/OR по принципу поиска Б глубину с ограничением по глубине в соответствии с процедурой, описанной в данном разделе.
13.2. Определите на языке Prolog пространство состояний AND/OR для задачи с ханойской башней и используйте это определение с процедурами поиска, представленными в данном разделе.
13.3. Рассмотрите какую-либо простую игру с двумя участниками и с полной информацией, в которой не применяется жребий, и определите ее представление а виде графа AND/OR Воспользуйтесь программой поиска в глубину в графах AND/OR чтобы найти стратегии выигрыша в форме деревьев AND/OR.
Часть II. Применение языка Prolog в области искусственного интеллекта
13.4. Поиск в графе AND/OR по заданному критерию