1.2k likes | 1.43k Views
Програмиране на Пролог. доц. Светла Бойчева Факултет по математика и информатика СУ “Св. Климент Охридски”. Приложения на езика Пролог. част 1 3. стек, опашка Дървета Графи Търсене Комбинаторни задачи. СТЕК. pop. push. Основни операции. push - поставяне на елемент
E N D
Програмиране на Пролог доц. Светла Бойчева Факултет по математика и информатика СУ “Св. Климент Охридски”
Приложения на езика Пролог част 13
стек, опашка • Дървета • Графи • Търсене • Комбинаторни задачи
СТЕК pop push
Основни операции • push - поставяне на елемент push(X,Stack,[X|Stack]). • pop - вземане на елемент pop(Stack,_,_):- empty_stack(Stack), write('Empty stack'),nl. pop([X|Stack],X,Stack). • empty_stack - проверка дали даден стек е празен empty_stack([ ]).
ОПАШКА pop push
Основни операции • push - поставяне на елемент push(X,Queue,NewQueue):- append(Queue,[X], NewQueue). • pop - вземане на елемент pop(Queue,_,_):- empty_queue (Queue), write('Empty queue'),nl. pop([X|Queue],X, Queue). • empty_queue - проверка дали дадена опашка е празна empty_queue([ ]).
Задачи • Проверка дали даден елемент принадлежи на даден стек/опашка in_stack(X,Stack) in_queue(X,Queue)
in_stack(X,Stack):- \+ empty_stack(Stack),!, pop(Stack,Y,RestStack), ( X=Y, ! ; in_stack(X,RestStack) ).
% Graph - насочен граф arc(a,b). arc(b,c). arc(c,d). arc(d,e). arc(b,d). arc(c,e). arc(a,d). arc(c,a).
% Graph - ненасочен граф my_arc(a,b). my_arc(b,c). my_ arc(c,d). my_ arc(d,e). my_ arc(b,d). my_ arc(c,e). my_ arc(a,d). my_ arc(c,a). arc(X,Y):-my_ arc(X,Y). arc(X,Y):-my_ arc(Y,X).
% Graph g([ [a,[e,c]], [b,[d,a]], [c,[ ]], [d,[a]],[e,[c]]]). arc(X,Y):- g(Graph), member([X,Nodes],Graph), member(Y,Nodes).
Задача • Даден е възел X, да се намерят всички възли, до които има дъга, която ги свързва с X. succ(X,S):- findall(Y,arc(X,Y),S).
Задача • Даден е възел X, да се намерят всички родителски възли на X, т.е. от които има път, който ги свързва с X. • Даден е възел X, да се намерят всички възли наследници на X, т.е. до които има път, който от X.
successor(X,S):- findall(Y,arc(X,Y),S). offspring(X,S):- successor(X,DS), del_all(X,DS,DS1), succ_list(DS1,S2), append(DS1,S2,Temp), compress(Temp,S).
compress([],[]). compress([X|Rest],[X|Result]):- del_all(X,Rest,New), compress(New,Result). del_all(_,[],[]). del_all(X,[X|L],L1): - del_all(X,L,L1). del_all(X,[Y|L1],[Y|L2]):- X\=Y, del_all(X,L1,L2).
diff([],_,[]). diff(A,[],A). diff([X|A],B,[X|C]):- \+ member(X,B), diff(A,B,C). diff([_|A],B,C):-diff(A,B,C).
succ_list([],[]). succ_list([A1|Rest], S):- offspring(A1,S1), diff(Rest,S1,R1), succ_list(R1,S2), append(S1,S2,S3), compress(S3,S).
% Всички възли в графа nodes(N):- setof(X,Y^arc(X,Y),S1), setof(Y,X^arc(X,Y),S2), append(S1,S2,S), setof(X,member(X,S),N).
Задача • Дадени са два върха X и Y. Да се напише предикат way, който да намира път от X до Y в даден граф
way(X,Y,Path):- way1(X,Y,[ ],Path). way1(X,X, CurrentPath, FinalPath):- reverse([X|CurrentPath], FinalPath). way1(X,Y, CurrentPath, FinalPath):- arc(X,Z), \+ member(Z,CurrentPath), way1(Z,Y,[X|CurrentPath],FinalPath).
Задача • Даден е граф. Да се намерят всички пътища от даден връх X до друг даден връх Y, такива че да бъдат с дължина дадено естествено число К.
k_size_ways(X,Y,K,Paths):- findall( P, ( way(X,Y,P), length(P,K) ), Paths).
hamilton(HPaths):- nodes(Nodes), length(Nodes,N), findall( HP, ( member(X,Nodes), member(Y,Nodes), X \= Y, k_size_ways(X,Y,N,KP), member(HP,KP) ), HPaths).
is_hamilton(HPath):- nodes(Nodes), length(Nodes,N), length(HPath,N), equal(Nodes,HPath). equal([ ],[ ]). equal([X|A],B):- member(X,B), del(X,B,B1), equal(A,B1).
% Graph arc(a,b). arc(b,c). arc(c,d). arc(d,e). arc(b,d). arc(c,e). arc(a,d). hamilton(HPaths):- nodes(N), length(N,K), findall(P1, (member(X,N),member(Y,N), X \= Y, way(X,Y,[],P1),length(P1,K) ), HPaths).
%way(X,Y,Path):- % way1(X,Y,[ ],Path). way2(X,X, CurrentPath, FinalPath):- reverse(CurrentPath, FinalPath). % [X-Z, Z-T1, ..., Tn-Y] way2(X,Y, CurrentPath, FinalPath):- arc(X,Z), \+ member(X-Z,CurrentPath), way2(Z,Y,[X-Z|CurrentPath],FinalPath).
arc(a,b). arc(b,c). arc(c,d). arc(d,e). arc(b,d). arc(c,e). arc(a,d). all_arcs(A):- findall(X-Y,arc(X,Y),A).
euler(EPaths):- all_arcs(Arcs), length(Arcs,N), nodes(Nodes), findall( HP, ( member(X,Nodes), member(Y,Nodes), X \= Y, way2(X,Y,[ ],HP), length(HP,N) ), EPaths).
Търсене на целево състояние • Дадено: • Q – крайно множество от състояния • SQ – непразно множество от начални състояния • GQ – непразно множество от крайни(целеви) състояния • succs: Q ->p(Q) – функция, която по зададено състояние “s” връща всички състояния succs(s), които могат да се достигнат от “s” на една стъпка • cost : Q,Q -> Positive Number – функция, която по зададени две състояния S и S’ връща оценката при преминаването на една стъпка от S до S’. Функцията е дефинирана само ако състоянията S и S’ са съседни (т.е. съществува преход от едното състояние в другото на една стъпка) • Търси се: • Път (последователност от съседни състояния) от дадено начално състояние до дадено крайно състояние в Q
Търсене на целево състояние (Търсене на път в граф) • Графът (graph)се състои от множество Nотвъзли / върхове / състояния (nodes)и множествоAот наредени двойки от върхове, наречени дъги (arcs). • Върхът n2е съсед (neighbor)наn1, ако съществува дъга между n1 и n2, т.е. <n1,n2> є A. • Път (path)е последователност от върхове n0, n1, ...nk ¸такава че<ni-1,ni> є A, i=1..k .
Търсене на целево състояние (Търсене на път в граф) • Дадени са начални върхове/състояния (start nodes)и крайни/ целеви състояния (goal nodes), решение (solution)е път от начално състояние до крайно състояние.
Пример: Мрежа g s
Общ алгоритъм • Общ алгоритъм за търсене: • даден е граф • начални състояния • целеви състояния • последователно да се изследват пътищата от началните състояния
Общ алгоритъм • Поддържа се фронт/граница(frontier)от пътищата, които са били изследвани • По време на процеса на търсене фронта се разширява в посока към неизследваните възли, докато се достигне до целеви възел
Общ алгоритъм • Предполагаме, че след като алгоритъма за търсене намери един път, може да му бъде зададено да търси още решения и тогава процесът трябва да продължи • Начинът, по който фронта се разширява и това точно коя стойност от фронта се избира дефинира стратегията на търсене (search strategy).
frontier start node unexplored nodes explored nodes
Основни алгоритми • Неинформирано (сляпо) търсене • Информирано (евристично) търсене
Основни алгоритми • Неинформирано (сляпо) търсене • търсене в дълбочина (Depth-first search) • търсене в ширина (Breadth-first search) • търсене в ограничена дълбочина (Depth-bound search) • итеративно търсене по нива(Iterative-deepening search)
Търсене в дълбочина • При търсенето в дълбочина фронтът се обработва като стек • Ако фронта е [p1,p2, . . .] • избира се p1 • пътищата p1', p1'',…, p1(k), които разширяват p1се добавят в началото на стека (преди p2), т.е. [p1', p1'',…, p1(k),p2, . . .] • p2 се обработва едва след като всички пътища, които са продължение на p1 са били изследвани
Представяне на графа arc(Node1,Node2). arc(Node1,Node2,Cost). arc(a,b). arc(d,e). arc(a,d). arc(e,c). arc(b,a). arc(e,d). arc(b,c). arc(c,e). arc(d,a). arc(d,b). arc(d,c). b a c e d
Построяване на дървото Start arc(a,b). arc(a,d). arc(b,a). arc(b,c). arc(c,e). arc(d,a). arc(d,b). arc(d,c). arc(d,e). arc(e,c). arc(e,d). a Start a b b d Goal c b c e e c e c c Goal e d Goal d e Goal
Представяне на фронта приТърсене в дълбочина Начално състояние [[a]] [[b a] [d a]] [[c b a] [d a]] [[e c b a] [d a]] I-во решение: [e c b a] => [a b c e] Преудовлетворяване: [[d a]] [[b d a] [c d a] [e d a]] [[c b d a] [c d a] [e d a]] [[e c b d a] [c d a] [e d a]] II-ро решение: [e c b d a] => [a d b c e] Преудовлетворяване: [[c d a] [e d a]] [[e c d a] [e d a]] III-то решение: [e c d a] => [a d c e] Преудовлетворяване: [[e d a]] IV-то решение: [e d a] => [a d e] a b Целево състояние d c b c e e c c e d e
Търсене в дълбочина Start 1 Goal 2 3 13 Goal 4 12 14 16 15 5 7 Goal 8 10 6 Goal 9 11
Търсене в дълбочина (Depth-first) depth_first([Path|Stack],Goal,FinalPath) :- extend(Path,NewPaths), append(NewPaths, Stack,NewStack), depth_first(NewStack,Goal,FinalPath).
Търсене в дълбочина (Depth-first) depth_first([[Goal|Path]|_],Goal,FinalPath):- reverse([Goal|Path],FinalPath).
Разширяване на фронта extend([Node|Path],NewPaths) :- findall([NewNode,Node|Path], (arc(Node,NewNode), \+ member(NewNode,[Node|Path])), NewPaths).
Търсене в дълбочина (Depth-first) depth_first([[Goal|Path]|_],Goal,FinalPath):- reverse([Goal|Path],FinalPath). depth_first([Path|Stack],Goal,FinalPath) :- extend(Path,NewPaths), append(NewPaths,Stack,NewStack), depth_first(NewStack,Goal,FinalPath). extend([Node|Path],NewPaths) :- findall([NewNode,Node|Path], (arc(Node,NewNode), \+ member(NewNode,[Node|Path])), NewPaths).