1 % (c) 2009-2022 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 :- module(state_space_open_nodes_c,[not_all_transitions_added/1,
6 reset_open_ids/0,
7 add_id_at_front/1,
8 add_id_at_end/1,
9 add_id_random/1,
10 add_id_to_process/3,
11 add_id_with_weight/2,
12 pop_id_from_front_direct/1,
13 pop_id_from_end_direct/1,
14 pop_id_oldest_direct/1,
15 retract_open_node_direct/1,
16
17 open_ids_empty/0,
18 top_front_id/1,
19 top_front_weight/1,
20
21 retract_open_ids_with_statistics/0,
22 print_state_space_open_nodes/1,
23 assert_not_all_transitions_added/1, assert_not_all_z/1]).
24
25 :- use_module(tools).
26 :- use_module(debug).
27 :- use_module(error_manager).
28 :- use_module(module_information).
29 :- module_info(group,state_space).
30 :- module_info(description,'This module keeps track of the unprocessed states queue of the model checker/animator.').
31
32 % Open Node Queue Interface
33 % The interface for adding new ids and popping them from the list of open nodes:
34
35 :- dynamic not_all_transitions_added/1.
36 %not_all_transitions_added(v_0).
37
38
39 :- use_module(extension('myheap/myheap'),[myheap_init/0,
40 %myheap_reset/0,
41 myheap_add_node/2, myheap_add_node_at_front/1, myheap_add_node_at_end/1,
42 myheap_add_node_random/1,
43 %myheap_size/1,
44 myheap_empty/1, %myheap_isempty/0,
45 myheap_top_id/1, %myheap_top_weight/1,
46 myheap_pop/1,
47 myheap_top_weight/1,
48 myheap_pop_max/1]).
49
50
51 open_ids_empty :- myheap_empty(X),X==1.
52
53 top_front_id(X) :- myheap_top_id(X).
54 top_front_weight(X) :- myheap_top_weight(X).
55
56 reset_open_ids :- myheap_init, retractall(ids_still_to_process(_,_,_)),
57 retractall(not_all_transitions_added(_)).
58 retract_open_ids_with_statistics :-
59 ? retract_with_statistics(state_space_open_nodes,
60 [not_all_transitions_added(_), ids_still_to_process(_,_,_)]),
61 myheap_init. % To do: expand and compute statistics
62
63 :- dynamic ids_still_to_process/3. %ids for which we still have to compute the heuristic function
64 % purpose: delay the computation until all transitions have been added of PredecessorID
65
66 add_id_to_process(ID,Hash,PredecessorID) :-
67 assertz(ids_still_to_process(ID,Hash,PredecessorID)), assertz(not_all_transitions_added(ID)).
68
69 process_ids :- retract(ids_still_to_process(ID,Hash,PredID)), % we assume ID cannot be root
70 state_space:out_degree(PredID,Degree), % print(add_out_degree_id(ID,PredID,Degree)),nl,
71 Weight is Degree*1000 + Hash mod 1000,
72 % Weight = Degree,
73 myheap_add_node(ID,Weight),fail.
74 process_ids.
75
76
77 add_id_at_front(root) :- !,
78 myheap_add_node_at_front(-99),
79 assertz(not_all_transitions_added(root)).
80 add_id_at_front(NodeID) :-
81 myheap_add_node_at_front(NodeID),
82 % print_node(add_front,NodeID),
83 assertz(not_all_transitions_added(NodeID)).
84
85
86 add_id_at_end(root) :- !, myheap_add_node_at_end(-99), assertz(not_all_transitions_added(root)).
87 add_id_at_end(NodeID) :- myheap_add_node_at_end(NodeID),
88 % print_node(add_end,NodeID),
89 assertz(not_all_transitions_added(NodeID)).
90
91
92 add_id_with_weight(root,W) :- !, myheap_add_node(-99,W), assertz(not_all_transitions_added(root)).
93 add_id_with_weight(ID,W) :- myheap_add_node(ID,W), assertz(not_all_transitions_added(ID)).
94
95 add_id_random(root) :- !, myheap_add_node_random(-99), assertz(not_all_transitions_added(root)).
96 add_id_random(ID) :- myheap_add_node_random(ID), assertz(not_all_transitions_added(ID)).
97
98
99 % pop id with the smallest weight:
100 pop_id_from_front_direct(NodeID) :- nonvar(NodeID),!,
101 add_internal_error('Illegal call: ', pop_id_from_front_direct(NodeID)),fail.
102 pop_id_from_front_direct(RNodeID) :- process_ids,
103 myheap_pop(ID), ID \= -1,
104 translate_id(ID,NodeID),
105 % print_node(pop_front,NodeID),
106 (retract(not_all_transitions_added(NodeID)) -> RNodeID=NodeID
107 ; % the node has been retracted directly and already been processed
108 %print_message(no_node(NodeID)),
109 pop_id_from_front_direct(RNodeID) % simply get the next node
110 ).
111
112
113 % pop id with the highest weight:
114 pop_id_from_end_direct(NodeID) :- nonvar(NodeID),!,
115 add_internal_error('Illegal call: ', pop_id_from_end_direct(NodeID)),fail.
116 pop_id_from_end_direct(RNodeID) :- process_ids,
117 myheap_pop_max(ID), ID \= -1,
118 (ID= -99 -> NodeID=root ; NodeID=ID),
119 %print_node(pop_end,NodeID),
120 (retract(not_all_transitions_added(NodeID)) -> RNodeID=NodeID
121 ; % the node has been retracted directly and already been processed
122 print_message(node_already_processed(NodeID,ID)),
123 pop_id_from_end_direct2(RNodeID) % simply get the next node
124 ).
125 pop_id_from_end_direct2(RNodeID) :-
126 myheap_pop_max(ID), ID \= -1,
127 (ID= -99 -> NodeID=root ; NodeID=ID),
128 (retract(not_all_transitions_added(NodeID)) -> RNodeID=NodeID
129 ; print_message(node_already_processed(NodeID,ID)),
130 pop_id_from_end_direct(RNodeID) % simply get the next node
131 ).
132
133 % pop the oldest node
134 pop_id_oldest_direct(NodeID) :- nonvar(NodeID),!,
135 add_internal_error('Illegal call: ', pop_id_oldest_direct(NodeID)),fail.
136 pop_id_oldest_direct(NodeID) :-
137 ? retract(not_all_transitions_added(NodeID)).
138 % in principle we should try and delete the node; but currently this cannot be done efficiently in the multi-map
139
140 %print_node(Info,ID) :- state_space:visited_expression(ID,State), print(Info), print(' '),print(ID), print(' : '), print(State),nl.
141
142 translate_id(-99,X) :- !, X=root.
143 translate_id(X,X).
144
145
146 retract_open_node_direct(NodeID) :- retract(not_all_transitions_added(NodeID)),
147 (myheap_top_id(TID),translate_id(TID,NodeID)
148 -> myheap_pop(_)
149 ; debug_println(9,'Cannot delete node from C++ multimap yet; node will be ignored when popped'),
150 debug_println(9,NodeID)
151 % we would need to use another C++ datastructure (mymultimap.cpp ?)
152 %Note: here we simply use the fact that not_all_transitions_added(NodeID) has been removed to indicate that a node has been removed
153 ).
154
155
156 not_all_transitions_added_saved(X) :- not_all_transitions_added(X). % to avoid name clashes; as consulting occurs in state_space module
157 not_all_z_saved(_) :- fail. % just here for compatibility with Prolog version of Queue
158
159 :- use_module(tools_printing, [print_dynamic_pred/4]).
160 print_state_space_open_nodes(Stream) :- print_message(saving),
161 print_dynamic_pred(Stream,state_space_open_nodes_c,not_all_z_saved,1),
162 print_dynamic_pred(Stream,state_space_open_nodes_c,not_all_transitions_added_saved,1),
163 print_message('Cannot save open nodes C++ multimap yet; Node IDs will be reloaded in random order').
164 %print_dynamic_pred(Stream,state_space_open_nodes,not_all_z,1),
165
166 % called to transfer nodes back here when loading saved stated in state_space.pl:
167 assert_not_all_transitions_added(NodeID) :- add_id_random(NodeID).
168 assert_not_all_z(_). % nothing to do: this information is not used with C version of queue