1 / 35

Логическое программирование

Логическое программирование. Факультет Прикладной математики и физики Кафедра Вычислительной математики и программирования Московский авиационный институт (государственный технический университет). Игра в 8. :- pred final(probstate::out) is det. final([[1,2,3],[4,0,5],[6,7,8]]).

akamu
Download Presentation

Логическое программирование

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Логическое программирование Факультет Прикладной математики и физики Кафедра Вычислительной математики и программирования Московский авиационный институт (государственный технический университет)

  2. Игра в 8 :- pred final(probstate::out) is det.final([[1,2,3],[4,0,5],[6,7,8]]). :- pred init(probstate::out) is det.init([[1,3,5],[4,2,8],[6,7,0]]). :- type row == list(int). :- type probstate == list(row).

  3. Игра в 8 - 2 :- pred move(probstate::in, probstate::out) is nondet. move(A,B) :- move_lr(A,B). move(A,B) :- move_ud(A,B). :- pred move_z(row::in, row::out) is nondet. move_z([0,X|T],[X,0|T]). move_z([X,0|T],[0,X|T]). move_z([X|T],[X|R]):-move_z(T,R). :- pred move_lr(probstate::in, probstate::out) is nondet. move_lr([A|T],[B|T]) :- move_z(A,B). move_lr([A|T],[A|R]) :- move_lr(T,R). :- pred move_h(row::in, row::in, row::out, row::out) is nondet. move_h([0|T],[A|R],[A|T],[0|R]). move_h([A|T],[0|R],[0|T],[A|R]). move_h([X|T],[Y|R],[X|T1],[Y|R1]) :- move_h(T,R,T1,R1).:- pred move_ud(probstate::in, probstate::out) is nondet. move_ud([A,B,C],[A1,B1,C]) :- move_h(A,B,A1,B1). move_ud([A,B,C],[A,B1,C1]) :- move_h(B,C,B1,C1).

  4. Мораль • Алгоритмы поиска (в особенности поиск в глубину) эффективно реализуются на языках логического программирования • Базовые алгоритмы поиска обладают взаимоисключающими достоинствами и недостатками • Алгоритм поиска с заглублением сочетает в себе достоинства обоих методов, хотя и производит исключительно много ненужных вычислений • Чтобы решать реальные задачи, нужно иметь методы поиска, использующие знания о направлении поиска.

  5. Алгоритмы поиска в нагруженных графах Алгоритмы поиска в нагруженных графах Алгоритмы поиска в нагруженных графах Алгоритмы поиска в нагруженных графах

  6. Граф дорог между городами road(a,d,4).road(a,f,2). road(b,c,4).road(b,d,4). road(c,i,4). road(d,e,3). road(e,i,3). road(f,g,2). road(g,h,2).road(h,i,3). move(A,B,N) :- road(A,B,N); road(B,A,N).

  7. Нагруженные графы • Нагруженным графом (направленным) называется пара <U,V>, где U — множество вершин, VU×U×R — множество дуг. • Длиной пути {xi}i=0n в нагруженном графе G=<U,V> называется величина L= li, где <xi-1,xi,li> V. Задача поиска в нагруженном графе ставится следующим образом: Пусть имеется нагруженный граф G, заданный предикатом move/3. Необходимо по двум заданным вершинам a и b найти кратчайший путь (или пути в порядке возрастания длины) из a в b в графе G.

  8. Представление пути в нагруженном графе prolong(C:[X|T],C1:[Y,X|T]):- move(X,Y,A), not(member(Y,[X|T])), C1 is C+A. ln([_],0). ln([A,B|T],C) :- move(A,B,C1), ln([B|T],C2), C is C1+C2. ln(C:_,C). • Для поиска кратчайшего пути надо уметь сравнивать пути по длине • 2 способа: • Хранить длину пути вместе с путём L=3:[a,b,c] • Каждый раз вычислятьдлину предикатом ln(L)

  9. Поиск с весовой функцией (Unified Cost Search, UCS) path(X,Y,P):- bdth([[X]],Y,P). bdth([[X|T]|_],X,[X|T]). bdth([P|QI],X,R) :- findall(Z,prolong(P,Z),T), append(QI,T,QO),!, bdth(QO,X,R). bdth([_|T],Y,L) :- bdth(T,Y,L). • Наиболее очевидное решение – в «стандартном» алгоритме поиска (в ширину) продлевать в первую очередь кратчайшие в смысле весовой функции пути. • Эквивалентный подход – поддерживать очередь путей в отсортированном состоянии (очередь с приоритетами).

  10. Поиск с весовой функцией - реализация path_bst(Start,Finish,Res):- bst([0:[Start]],Finish,_:Res). bst([C:[Finish|T]|_],Finish,C:[Finish|T]). bst([Path|Rest],Finish,R) :- findall(Z,prolong(Path,Z),NewPathes), place(NewPathes,Rest,NewQueue), !, bst(NewQueue,Finish,R). bst([P|T],F,R) :- bst(T,F,R).

  11. Вставка в очередь place([],L,L). place([X|T],L,R) :- insert(X,L,L1), place(T,L1,R). insert(C:P,[C1:P1|R],[C:P,C1:P1|R]) :- C<C1, !. insert(C:P,[X|T],[X|R]) :- insert (C:P,T,R). insert(C:P,[],[C:P]).

  12. Порядок просмотра путей | ?- search_bst(a,i,R). 2-->[2:[f,a],4:[d,a]] 2-->[4:[d,a],4:[g,f,a]] 3-->[4:[g,f,a],7:[e,d,a],8:[b,d,a]] 3-->[6:[h,g,f,a],7:[e,d,a],8:[b,d,a]] 3-->[7:[e,d,a],8:[b,d,a],9:[i,h,g,f,a]] 3-->[8:[b,d,a],9:[i,h,g,f,a],10:[i,e,d,a]] 3-->[9:[i,h,g,f,a],10:[i,e,d,a],12:[c,b,d,a]] R = [i,h,g,f,a] ? ; 4-->[10:[i,e,d,a],12:[c,b,d,a],12:[e,i,h,g,f,a],13:[c,i,h,g,f,a]] R = [i,e,d,a] ? ; 5-->[12:[c,b,d,a],12:[e,i,h,g,f,a],13:[c,i,h,g,f,a],13:[h,i,e,d,a],14:[c,i,e,d,a]] 5-->[12:[e,i,h,g,f,a],13:[c,i,h,g,f,a],13:[h,i,e,d,a],14:[c,i,e,d,a],16:[i,c,b,d,a]] 5-->[13:[c,i,h,g,f,a],13:[h,i,e,d,a],14:[c,i,e,d,a],15:[d,e,i,h,g,f,a],16:[i,c,b,d,a]] 5-->[13:[h,i,e,d,a],14:[c,i,e,d,a],15:[d,e,i,h,g,f,a],16:[i,c,b,d,a],17:[b,c,i,h,g,f,a]] 5-->[14:[c,i,e,d,a],15:[d,e,i,h,g,f,a],15:[g,h,i,e,d,a],16:[i,c,b,d,a],17:[b,c,i,h,g,f,a]] 5-->[15:[d,e,i,h,g,f,a],15:[g,h,i,e,d,a],16:[i,c,b,d,a],17:[b,c,i,h,g,f,a],18:[b,c,i,e,d,a]] 5-->[15:[g,h,i,e,d,a],16:[i,c,b,d,a],17:[b,c,i,h,g,f,a],18:[b,c,i,e,d,a],19:[b,d,e,i,h,g,f,a]] 5-->[16:[i,c,b,d,a],17:[b,c,i,h,g,f,a],17:[f,g,h,i,e,d,a],18:[b,c,i,e,d,a],19:[b,d,e,i,h,g,f,a]] R = [i,c,b,d,a] ? ; 6-->[17:[b,c,i,h,g,f,a],17:[f,g,h,i,e,d,a],18:[b,c,i,e,d,a],19:[b,d,e,i,h,g,f,a],19:[e,i,c,b,d,a],19:[h,i,c,b,d,a]] …. 2-->[23:[f,g,h,i,c,b,d,a],24:[e,d,b,c,i,h,g,f,a]] 1-->[24:[e,d,b,c,i,h,g,f,a]] 0-->[]

  13. Проблема • В рассмотренных алгоритмах поиска движение происходит в направлении кратчайшего пути, но не по направлению к цели • Аналогично поиску пути в городе без компаса • Для повышения эффективности поиска надо иметь возможность как-то задать направление поиска • Такие методы поиска называются информированными

  14. Граф дорог с заданным направлением h(a,10). h(b,7). h(c,4). h(d,5). h(e,3). h(f,8). h(g,6). h(h,3). h(i,0). В данном примере функция h/2 задается для фиксированной конечной вершины. Для универсального алгоритма поиска надо задавать функцию h как функцию текущей и конечной вершин.

  15. Жадный алгоритм поиска wt([P|_],C) :- h(P,C). place([],L,L). place([X|T],L,R) :- insert(X,L,L1), place(T,L1,R). insert(P,[P1|R],[P,P1|R]) :- wt(P,C), wt(P1,C1), C<C1,!. insert(P,[X|T],[X|R]) :-insert(P,T,R). insert(P,[],[P]). search_grd(Start,Finish,Res):- greedy([[Start]],Finish,Res). greedy([[Finish|T]|_],Finish,[Finish|T]). greedy([Path|Rest],Finish,R) :- findall(Z,prolong(Path,Z),NewPathes), place(NewPathes,Rest,NewQueue), !,greedy(NewQueue,Finish,R). greedy([P|T],F,R) :- greedy(T,F,R). • Будем продлевать первым путь, ближайший к цели с точки зрения эвристики

  16. Порядок просмотра путей жадным алгоритмом | ?- search_grd(a,i,R). 2-->[[d,a],[f,a]] 3-->[[e,d,a],[b,d,a],[f,a]] 3-->[[i,e,d,a],[b,d,a],[f,a]] R = [i,e,d,a] ? ; 4-->[[h,i,e,d,a],[c,i,e,d,a],[b,d,a],[f,a]] 4-->[[c,i,e,d,a],[b,d,a],[g,h,i,e,d,a],[f,a]] 4-->[[b,d,a],[g,h,i,e,d,a],[b,c,i,e,d,a],[f,a]] 4-->[[c,b,d,a],[g,h,i,e,d,a],[b,c,i,e,d,a],[f,a]] 4-->[[i,c,b,d,a],[g,h,i,e,d,a],[b,c,i,e,d,a],[f,a]] R = [i,c,b,d,a] ? ; 5-->[[e,i,c,b,d,a],[h,i,c,b,d,a],[g,h,i,e,d,a],[b,c,i,e,d,a],[f,a]] 4-->[[h,i,c,b,d,a],[g,h,i,e,d,a],[b,c,i,e,d,a],[f,a]] 4-->[[g,h,i,e,d,a],[b,c,i,e,d,a],[g,h,i,c,b,d,a],[f,a]] 4-->[[b,c,i,e,d,a],[g,h,i,c,b,d,a],[f,a],[f,g,h,i,e,d,a]] 3-->[[g,h,i,c,b,d,a],[f,a],[f,g,h,i,e,d,a]] 3-->[[f,a],[f,g,h,i,e,d,a],[f,g,h,i,c,b,d,a]] 3-->[[g,f,a],[f,g,h,i,e,d,a],[f,g,h,i,c,b,d,a]] 3-->[[h,g,f,a],[f,g,h,i,e,d,a],[f,g,h,i,c,b,d,a]] 3-->[[i,h,g,f,a],[f,g,h,i,e,d,a],[f,g,h,i,c,b,d,a]] R = [i,h,g,f,a] ? ; 4-->[[e,i,h,g,f,a],[c,i,h,g,f,a],[f,g,h,i,e,d,a],[f,g,h,i,c,b,d,a]] .... 1-->[[f,g,h,i,c,b,d,a]] 0-->[]

  17. Особенности алгоритма • Жадный алгоритм учитывает оптимальносить пути с точки зрения эвристики, но не учитывает вес пути • Не обеспечивается нахождение кратчайшего пути • Хорошо бы иметь алгоритм: • Который находит кратчайший путь (допустимый) • Который делает это оптимальным образом, с учётом направления на цель

  18. Алгоритм A f(X) = g(X) + h(X) A g(X) • Где • g(X) – длина текущего пути от начальной вершины до X • h(X) – эвристическая функция • f(X) – весовая функция, по которой осуществляется отбор пути … X … … Z h(X) В качестве весовой функции при выборе направления поиска будем рассматривать

  19. Реализация алгоритма A wt(C:[A|T],H) :- h(A,Z), H is C+Z. place([],L,L). place([X|T],L,R) :- insert(X,L,L1), place(T,L1,R). insert(P,[P1|R],[P,P1|R]) :- wt(P,C), wt(P1,C1), C<C1,!. insert(P,[X|T],[X|R]) :-insert(P,T,R). insert(P,[],[P]). path_a(Start,Finish,Res):- a([0:[Start]],Finish,_:Res). a([C:[Finish|T]|_],Finish,C:[Finish|T]). a([Path|Rest],Finish,R) :- findall(Z,prolong(Path,Z),NewPathes), place(NewPathes,Rest,NewQueue), !, a(NewQueue,Finish,R). a([P|T],F,R) :- a(T,F,R).

  20. Порядок просмотра путей алгоритмом A | ?- search_ast(a,i,R). 2-->[4:[d,a],2:[f,a]] 3-->[2:[f,a],7:[e,d,a],8:[b,d,a]] 3-->[7:[e,d,a],4:[g,f,a],8:[b,d,a]] 3-->[4:[g,f,a],10:[i,e,d,a],8:[b,d,a]] 3-->[6:[h,g,f,a],10:[i,e,d,a],8:[b,d,a]] 3-->[9:[i,h,g,f,a],10:[i,e,d,a],8:[b,d,a]] R = [i,h,g,f,a] ? ; 4-->[10:[i,e,d,a],8:[b,d,a],12:[e,i,h,g,f,a],13:[c,i,h,g,f,a]] R = [i,e,d,a] ? ; 5-->[8:[b,d,a],12:[e,i,h,g,f,a],13:[h,i,e,d,a],13:[c,i,h,g,f,a],14:[c,i,e,d,a]] 5-->[12:[e,i,h,g,f,a],13:[h,i,e,d,a],12:[c,b,d,a],13:[c,i,h,g,f,a],14:[c,i,e,d,a]] 5-->[13:[h,i,e,d,a],12:[c,b,d,a],13:[c,i,h,g,f,a],14:[c,i,e,d,a],15:[d,e,i,h,g,f,a]] 5-->[12:[c,b,d,a],13:[c,i,h,g,f,a],14:[c,i,e,d,a],15:[d,e,i,h,g,f,a],15:[g,h,i,e,d,a]] 5-->[16:[i,c,b,d,a],13:[c,i,h,g,f,a],14:[c,i,e,d,a],15:[d,e,i,h,g,f,a],15:[g,h,i,e,d,a]] R = [i,c,b,d,a] ? ; 6-->[13:[c,i,h,g,f,a],14:[c,i,e,d,a],15:[d,e,i,h,g,f,a],15:[g,h,i,e,d,a],19:[e,i,c,b,d,a],19:[h,i,c,b,d,a]] 6-->[14:[c,i,e,d,a],15:[d,e,i,h,g,f,a],15:[g,h,i,e,d,a],19:[e,i,c,b,d,a],19:[h,i,c,b,d,a],17:[b,c,i,h,g,f,a]] ... 3-->[23:[c,b,d,e,i,h,g,f,a],24:[e,d,b,c,i,h,g,f,a],23:[f,g,h,i,c,b,d,a]] 2-->[24:[e,d,b,c,i,h,g,f,a],23:[f,g,h,i,c,b,d,a]] 1-->[23:[f,g,h,i,c,b,d,a]] 0-->[]

  21. Допустимость алгоритма поиска • Алгоритм поиска называется допустимым (admissible), если он в первую очередь находит оптимальный путь в смысле заданного критерия. • Поскольку на функцию h(.) не накладывается никаких ограничений, возможна ситуация, когда «хороший» (оптимальный) путь не рассматривается, т.к. ему соответствует бОльшее значение h(.) • Чтобы алгоритм поиска A был допустимым, необходимо наложить ограничения на h(.)

  22. Критерий допустимости A* • f(X)=g(X)+h(X), где • g(X) – длина текущего пути от A до X • h(X) – показатель близости конечной вершины Z • Раз мы складываем g(.) и h(.), логично требовать, чтобы они были одной размерности • Реально интересно минимизировать длину оптимального пути f*(X) = g*(X)+h*(X), где • g*(X) – длина кратчайшего пути из A в X • h*(X) – длина кратчайшего пути из X в Z • Теорема. Алгоритм поиска A является допустимым, если для всех вершин графа 0 h(x)  h*(x); в этом случае алгоритм поиска называется алгоритмом A*.

  23. Сравнение алгоритмов поиска

  24. Информированность • h(x)=0 - удовлетворяет условию допустимости • Получаем UCS • Чем больше значение функции h(·), тем больше информации об особенностях пространства поиска мы сообщаем алгоритму • Определение. Алгоритм эвристического поиска с функцией h1(x) называется более информированным по сравнению с алгоритмом с функцией h2(x), если для всех вершин графа x имеет место h1(x) h2(x).

  25. Монотонность • Определение.Эвристическая функция h(x) называется монотонной, если h(e)=0 для конечного состояния e, и для любых вершин u,v лежащих на одном пути имеет место |h(u)-h(v)|cost(u,v), где cost(u,v) — стоимость пути от u до v. • Теорема.  Любая монотонная эвристика допустима. • Действительно, для некоторого пути a1a2... ane из свойства монотонности следует, что h(ai-1)-h(ai)  cost(ai-1,ai), что при суммировании дает h(a1) = h(a1)-h(e) cost(a1,e) = h*(a1).

  26. Пример: эвристика для игры в 8 dist([],[],0). dist([A|T],[B|R],Z) :- dist(T,R,D), ndiff(A,B,E), Z is D+E. ndiff([],[],0). ndiff([A|T],[A|R],Z) :- ndiff(T,R,Z), !. ndiff([_|T],[_|R],Z) :- ndiff(T,R,D), Z is D+1.  h(S,R) :- final(F), dist(S,F,R). • Длина пути измеряется в количестве шагов • Эвристическая функция не должна быть больше, чем число шагов до финиша • Предлагаем использовать количество фишек не на своих местах

  27. Алгоритм IDA* • Идею итерационного заглубления можно использовать для реализации A* • Тонкие моменты: • В ID приращение идет по числу шагов (целочисленное), в IDA* - по длине пути • Имеет смысл устанавливать каждый раз некоторый диапазон возможных длин => не гарантируется допустимость в строгом смысле

  28. Метод градиентного спуска • В некоторых случаях пространство состояний имеет очень сложную природу, что не позволяет хранить пути из состояний в памяти • Пример: экспертные системы • Пример: состояние работающей программы • В этих случаях возможно использование алгоритмов поиска, которые рассматривают только одно направление движения • Движение в оптимальном направлении даёт нам алгоритм градиентного спуска • Оптимальное направление может задаваться эвристической функцией • Проблема: остановка в локальном максимуме/минимуме

  29. Представление списка путей деревом [a,b,c] [a,b,d,e] [a,b,d,f] t(a,[t(b,[l(c),t(d,[l(e),l(f)])])]) • В очереди путей часто присутствует множество путей с общим началом • За счёт представления таких путей деревом можно сильно выиграть по памяти

  30. Tree Search search_t(S,F,P) :- t_search(F,l(S),P). t_search(Finish,Tree,Path):- expand(Finish,[],Tree,Tree1,Path), ( nonvar(Path); var(Path), t_search(Finish,Tree,Path)). expand(Finish,Past,l(Finish),_,[Finish|Past]). expand(_,Past,l(Current),t(Current,Sub),_):- findall( NextLeave, t_prolong(NextLeave,[Current|Past]), Sub). expand(Finish,Past,t(Current,Sub),t(Current,Sub1),Path):- expand_all(Finish,[Current|Past],Sub,[],Sub1,Path). t_prolong(l(Next),[Current|Past]):- move(Current,Next), not(member(Next,Past)). expand_all(_,_,[],[T|TT],[T|TT],_). expand_all(Finish,Path0,[T|TT],TT1,Sub1,Path):- expand(Finish,Path0,T,T1,Path), ( nonvar(Path); var(Path),!, expand_all(Finish,Path0,TT,[T1|TT1],Sub1,Path); expand_all(Finish,Path0,TT,TT1,Sub1,Path) ).

  31. Closed Vertex List • В рассмотренных методах поиска мы не производили обход уже пройденных вершин в рамках одного пути • При откате назад путь укорачивается, и возможно повторное рассмотрение вершины в рамках другого пути • Для запоминания пройденных вершин на протяжении всего поиска можно использовать список closed list • Глобальные переменные • Представление путей парами

  32. Использование глобального списка пройденных вершин get_global(G,X) :- value(G,X).store_global(G,X) :- retractall(value(G,_)), asserta(value(G,X)).create_global(G,X) :- asserta(value(G,X)). search_cdpth(A,B,L) :- create_global(closed,[]), cdpth([A],B,L). cdpth([X|T],X,[X|T]). cdpth(P,F,L) :- cprolong(P,P1), cdpth(P1,F,L). cprolong([X|T],[Y,X|T]) :- get_global(closed,C), move(X,Y), not(member(Y,C)), store_global(closed,[Y|C]). get_global(G,X) :- value(G,X). store_global(G,X) :- retractall(value(G,_)), asserta(value(G,X)). create_global(G,X) :- asserta(value(G,X)).

  33. Поиск с представлением путей парами search_cbdth(X,Y,L) :- cbdth([pair(X,nil)],[],Y,R,C), reconstruct(R,C,L). cbdth([pair(Y,Z)|_],C,Y,pair(Y,Z),C). cbdth([pair(S,P)|Q],C,Y,R,CC) :- findall(Z,prolong(S,Q,C,Z),L), append(Q,L,NewQ),!, cbdth(NewQ,[pair(S,P)|C],Y,R,CC). cbdth([_|Q],C,Y,R,CC) :- cbdth(Q,C,Y,R,CC). prolong(S,Q,C,pair(X,S)) :- move(S,X), not(member(pair(X,_),Q)), not(member(pair(X,_),C)). reconstruct(pair(X,nil),_,[X]). reconstruct(pair(X,Y),L,[X|T]) :- member(pair(Y,Z),L), reconstruct(pair(Y,Z),L,T).

  34. Представление путей парами 1 --> [pair(a,nil)] : [] 2 --> [pair(d,a),pair(f,a)] : [pair(a,nil)] 3 --> [pair(f,a),pair(e,d),pair(b,d)] : [pair(d,a),pair(a,nil)] 3 --> [pair(e,d),pair(b,d),pair(g,f)] : [pair(f,a),pair(d,a),pair(a,nil)] 3 --> [pair(b,d),pair(g,f),pair(i,e)] : [pair(e,d),pair(f,a),pair(d,a),pair(a,nil)] 3 --> [pair(g,f),pair(i,e),pair(c,b)] : [pair(b,d),pair(e,d),pair(f,a),pair(d,a),pair(a,nil)] R = [i,e,d,a] ? ; 3 --> [pair(i,e),pair(c,b),pair(h,g)] : [pair(g,f),pair(b,d),pair(e,d),pair(f,a),pair(d,a),pair(a,nil)] 2 --> [pair(c,b),pair(h,g)] : [pair(i,e),pair(g,f),pair(b,d),pair(e,d),pair(f,a),pair(d,a),pair(a,nil)] 1 --> [pair(h,g)] : [pair(c,b),pair(i,e),pair(g,f),pair(b,d), pair(e,d),pair(f,a),pair(d,a),pair(a,nil)]

  35. Мораль • Эвристические алгоритмы поиска позволяет сократить пространство перебора за счет введения некоторой «внешней» эвристической функции • Для сохранения свойства допустимости эвристическую функцию нужно определять «с умом» • Компромисс между критерием допустимости и информированностью • Возможно комбинирование эвристических методов с более эффективными способами представления путей в памяти • Для сложных случаев используют градиентный эвристический спуск (hill climbing)

More Related