- •Аннотация
- •Лабораторная работа № 1 «Логическое программирование задачи поиска пути на конечных графах пространства состояний»
- •1.1.1. Прямой поиск (от исходной вершины до целевой вершины).
- •Самостоятельная часть работы
- •1.1.2. Обратный поиск (от целевой вершины к исходной).
- •Самостоятельная часть работы.
- •Самостоятельная часть работы
- •Задание №1.3. Поиск пути в неориентированном графе.
- •Самостоятельная часть работы
- •Задание №1.4. Поиск в псевдо бинарном дереве.
- •Самостоятельная часть работы
- •Самостоятельная часть работы
- •Задание 1.6. Поиск пути в ориентированном ациклическом графе с обходом вершин «в ширину».
- •I j k
- •Самостоятельная часть работы.
- •Задание № 1.7. Программирование поиска в глубину на конечном графе пространства состояний на языке clips
- •Самостоятельная часть работы
Самостоятельная часть работы
Объясните на примере протокол работы программы.
Задайте цель в виде запроса tree(X,9,_,_). Запустите программу в режиме трассировки, чтобы посчитать число последовательных сопоставлений со списком фактов, которое потребовалось программе для ответа.
Задание 1.6. Поиск пути в ориентированном ациклическом графе с обходом вершин «в ширину».
Применяемый метод поиска является прямым, но перебор вершин происходит в ширину. Особенность рассматриваемой ниже программы SEARCH состоит в том, что при поиске заданной конечной вершины среди вершин текущего уровня графа одновременно формируются и сохраняются в стеке списки путей откаждой из нихкобщей начальной. Эти списки представлены в инверсном виде: в голове каждого списка пути стоит одна из вершин текущего уровня графа, а в конце общая начальная. Поэтому при совпадении головы одного из списков с целевой вершиной не требуется дополнительной процедуры поиска пути, он будет содержаться в головном элементе списка списков всех путей. Но для хранения всех списков путей требуется большая память стека.
Рассмотрим пока без программы, как происходит процесс генерации новых путей и поиск заданной конечной вершины (см. рис.ниже).
Вначале рассматривается единственная вершина 1-го уровня - исходная. Это вершина «а». С помощью фактов edge(x,y) определяются все вершины, связанные с «a», в данном случае это «b», «c» и «d», и формируются инверсные списки пути от этих вершинв «a»: [b,a], [c,a], [d,a]. Все пути собираются в общий список списков: [[b,a], [c,a], [d,a]]. Далее идет поиск целевой вершины в головном списке списков. При этом отделяется головной список [b,a],
a









b
d
c
e
f
g
h







I j k










l
n
r
m o p q











s
t
u
v


а в нем в свою очередь отделяется головной элемент, в данном случае «b», и сравнивается с заданной целевой вершиной:
[[b|a]|[c,a],[d,a]]
Если совпадение произошло, то выводится искомый путь: [b,a]. Если же совпадения не произошло, то по фактам edge определяются продолжения путей от «b» на следующий уровень графа. Это вершина «e». Она добавляется в голову неуспешного списка [b,a] и получаем новый инверсный путь от вершины «e» к «a», т.е. список [e,b,a], который заменяет собой предыдущий [b,a], так как вершина «b» не целевая, и ставится в конец обновленного списка списков путей, который образуется путем объединения хвоста 1-го списка списков, т.е. [[c,a],[d,a]], с новым путем [e,b,a], который ставится в конец. Получается новый список путей:
[[c,a],[d,a],[e,b,a]]
На первое место в этом списке вышла следующая вершина рассматриваемого уровня графа «c». Применим то же правило, отделив головной список, а в нем головной элемент:
[[c|a]|[d,a],[e,b,a]]
Допустим, головной элемент «c» опять не совпадает с заданной целевой вершиной. Тогда от «c» следует образовать продолжения путей на следующий уровень графа. По фактам edge вершина «c» связана с «f» и «g». В этом случае порождаются два новых инверсных пути [f,c,a] и [g,c,a]. Они заменяют собой путь [c,a] и ставятся в конец нового списка списков, который образуется путем объединения хвоста предыдущего списка, т.е. [[d,a][e,b,a]], с новыми путями [f,c,a] и [g,c,a]. Получим список списков:
[[d,a],[e,b,a],[f,c,a],[g,c,a]]
Теперь, как видим, на первое место выходит элемент «d» - последний в списке вершин 2-го уровня, образованном от «a». Следующими будут рассмотрены вершины «e», «f», «g» , т.е. вершины 3-го уровня. Такой процесс продолжится, пока в голове одного из списков не обнаружится конечная вершина пути. Этот список и будет искомым путём. В противном случае появится сообщение, что пути нет.
Рассмотрим программную реализацию изложенного алгоритма. Правило верхнего уровня:
search(BN, EN, Result): - widesearch ([[BN]], EN, Result).
Первые два аргумента целевого предиката search являются задаваемыми начальной (BN) и конечной (EN) вершинами искомого пути. Третий аргумент Result - возвращаемый список вершин искомого пути (если, конечно, таковой имеется).
Первый аргумент предиката widesearch - список инверсных путей от всех текущих, еще не рассмотренных на предмет совпадения с целью, вершин данного уровня графа к исходной вершине. Этот аргумент описан как список списков. Остальные аргументы имеют тот же смысл что и в search. При первом вызове widesearch рассмотренного правила первый аргумент состоит только из исходной вершины BN.
Основное правило поиска состоит из 2-х предложений:
widesearch([[Node|Path]|_], EN, [Node|Path]: - Node = EN,!.
widesearch([[Node|Path]|Paths], EN, Result):-findall(X,nextpath(Node, Path, X),NextPaths),
append(Paths, NextPaths, NewPaths),!, widesearch(NewPaths, EN, Result).
Первое предложение служит для опознавания одного из путей [Node|Path], стоящего в голове списка списков, как искомого, если голова Node этого пути совпадет с заданной конечной вершиной EN. В этом случае он как третий аргумент предиката widesearchбудет передан переменнойResaultзапроса. Поиск успешен.
Если совпадения Node и EN не произошло, подключается 2-ое предложение widesearch, которое выполняет всю основную работу по формированию новых путей от вершины “а” на следующий уровень. Вначале предикат findall вызывает правило nextpath:
nextpath(Node, Path, [NextNode, Node|Path]): - edge(Node, NextNode).
Это правило добавляет в голову списка Node|Path = [а] одну вершину следующего уровня [NextNode,Node|Path], определяя ее с помощью факта edge. В вызывающий предикат nextpath правила findall этот новый путь [NextNode,Node|Path] возвращается на место свободной переменной X. В рассмотренном выше примере это будет список [b,a]. Затем предикат findall повторяет вызов правила nextpath для поиска других возможных продолжений отNodeвниз на следующий уровень, т.е. с иd, и собирает полученные списки в своем третьем аргументе NextPaths. В нашем примере переменнаяNextPathsполучит значение [[b,a], [c,a], [d,a]]. Следующий предикат append вызывает правило объединения двух списков в третий, выходной список. Аргументы append должны быть описаны как списки списков. Первый аргумент — хвост предыдущего списка путейPaths, в нашем случае он пока пустой, второй — новые пути NextPaths, третий — результат их объединения в список NewPaths, т.е. вNewPathsполучим список [[b,a], [c,a], [d,a]]. Этот список списков передается последнему предикату widesearch в качестве 1-го аргумента и происходит рекурсивный вызов правила widrsearch. Первое предложение этого правила опять проверит выполнимость условия окончания поиска по совпадениюголовного элемента головного списка, в данном случае, bс заданной конечной EN. Если совпадения не произошло, то второе предложение widesearch будет искать продолжения пути от неуспешной вершиныbна следующий уровень в том же порядке, какой был описан выше.
