| 1 | % (c) 2009-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
| 2 | % Heinrich Heine Universitaet Duesseldorf | |
| 3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
| 4 | ||
| 5 | ||
| 6 | :- module(state_space_dijkstra,[find_shortest_path_from_to/4, | |
| 7 | find_shortest_path_from_to_found_predicate/4, | |
| 8 | set_target_id/1, set_found_predicate/2, set_longest_trace_target/0 | |
| 9 | ]). | |
| 10 | ||
| 11 | :- use_module(tools). | |
| 12 | :- use_module(module_information). | |
| 13 | :- module_info(group,animator). | |
| 14 | :- module_info(description,'Tools for finding shortest paths between visited states.'). | |
| 15 | ||
| 16 | % can find the shortest path from a given node to | |
| 17 | % any node satisfying a genering "found_predicate" | |
| 18 | ||
| 19 | :- use_module(state_space). | |
| 20 | :- use_module(library(heaps)). | |
| 21 | :- use_module(library(lists)). | |
| 22 | ||
| 23 | ||
| 24 | :- dynamic found_predicate/2. % a predicate that should return true if we have found a target node | |
| 25 | :- dynamic mark_id/3. | |
| 26 | ||
| 27 | set_target_id(TargetID) :- | |
| 28 | retractall(found_predicate(_,_)), | |
| 29 | assertz(found_predicate(TargetID,_)). | |
| 30 | ||
| 31 | set_found_predicate(ID,COND) :- | |
| 32 | retractall(found_predicate(_,_)), | |
| 33 | assertz((found_predicate(ID,_Heap) :- COND)). | |
| 34 | ||
| 35 | % use Dijkstra to find longest trace from a node (usually root) | |
| 36 | set_longest_trace_target :- | |
| 37 | retractall(found_predicate(_,_)), | |
| 38 | assertz((found_predicate(ID,Heap) :- heaps:empty_heap(Heap), \+ any_new_transition(ID,_,_))). % last node processed has longest trace | |
| 39 | ||
| 40 | ||
| 41 | ||
| 42 | % find_shortest_path_from_to(FromStateID,ToStateID,-ResOpIDPath,-ResStateIDL) | |
| 43 | find_shortest_path_from_to(From,To,ResOpIDPath,ResIDL) :- | |
| 44 | set_target_id(To), | |
| 45 | find_shortest_path_from_to_found_predicate(From,ResOpIDPath,ResIDL,_). | |
| 46 | find_shortest_path_from_to_found_predicate(From,ResPath,ResIDL,TargetID) :- | |
| 47 | retractall(mark_id(_,_,_)), | |
| 48 | %tools:start_ms_timer(T1), | |
| 49 | empty_heap(H), | |
| 50 | add_to_heap(H,0,node(From,null,null),NH), | |
| 51 | dijkstra(NH,RP,RI,TargetID,500), | |
| 52 | %tools:stop_ms_timer_with_msg(T1,'Shortest path'), | |
| 53 | reverse(RP,ResPath), | |
| 54 | reverse(RI,ResIDL). | |
| 55 | ||
| 56 | :- use_module(debug). | |
| 57 | ||
| 58 | dijkstra(Heap,ResOpIDPath,ResIDList,TargetID,Cnt) :- | |
| 59 | (Cnt>0 -> C1 is Cnt-1 ; C1=1000, printsilent('.'),flush_output(user)), | |
| 60 | get_from_heap(Heap,Dist,node(ID,PrevID,TransID),NewHeap),!, | |
| 61 | %format('Processing: ~w dist: ~w~n',[ID,Dist]), | |
| 62 | (found_predicate(ID,NewHeap) -> TargetID=ID, %print(extracting_path(ID)),nl, | |
| 63 | assertz(mark_id(ID,PrevID,TransID)), | |
| 64 | nls, | |
| 65 | extract_path(ID,ResIDList,ResOpIDPath) %,print(res(ResIDList)),nl | |
| 66 | ; treat_node(ID,PrevID,TransID,Dist,NewHeap,NewHeap1), | |
| 67 | dijkstra(NewHeap1,ResOpIDPath,ResIDList,TargetID,C1) | |
| 68 | ). | |
| 69 | dijkstra(_,_,_,_,_) :- | |
| 70 | print('NO PATH EXISTS TO A NODE WITH found_predicate TRUE ! '),nl, | |
| 71 | fail. | |
| 72 | ||
| 73 | extract_path(ID,StateIDL,Path) :- | |
| 74 | mark_id(ID,PrevID,TransID), | |
| 75 | (PrevID=null -> StateIDL=[], Path=[] | |
| 76 | ; % any_transition(PrevID,TransID,ID), % not necessary ? | |
| 77 | % here we could choose a transition with minimal changes from previous transition | |
| 78 | StateIDL=[ID|TI],Path=[TransID|TP], | |
| 79 | extract_path(PrevID,TI,TP)). | |
| 80 | ||
| 81 | treat_node(ID,_,_,_,H,RH) :- mark_id(ID,_,_),!,RH=H. % node already treated | |
| 82 | treat_node(ID,PrevID,TransID,Dist,H,RH) :- assertz(mark_id(ID,PrevID,TransID)), | |
| 83 | findall(node(NewID,ID,NewTransID), | |
| 84 | any_new_transition(ID,NewTransID,NewID), | |
| 85 | Succs), | |
| 86 | D1 is Dist+1, | |
| 87 | add_nodes(Succs,D1,H,RH). | |
| 88 | ||
| 89 | any_new_transition(ID,NewTransID,NewID) :- | |
| 90 | ? | any_transition(ID,NewTransID,NewID), |
| 91 | \+ mark_id(NewID,_,_). % as all weights are 1, we do not need to add NewID: is already visited | |
| 92 | ||
| 93 | add_nodes([],_,H,H). | |
| 94 | add_nodes([N|T],Prio,H,RH) :- | |
| 95 | add_to_heap(H,Prio,N,H1), | |
| 96 | add_nodes(T,Prio,H1,RH). | |
| 97 | ||
| 98 | % use_module(state_space_dijkstra), find_shortest_path_to(root,22,P,I) | |
| 99 | ||
| 100 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
| 101 | ||
| 102 | ||
| 103 |