| 1 | % (c) 2009-2019 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_packing,[reset_stored_values/0, | |
| 6 | precompile_state_packing/0, % to be called after b_global_sets precompiled | |
| 7 | pack_state/2, unpack_state/2, | |
| 8 | incremental_pack_state/4, | |
| 9 | pack_values/2, unpack_values/2, | |
| 10 | pack_value/2, unpack_value/2, | |
| 11 | print_stored_values/0, retract_stored_values_with_statistics/0]). | |
| 12 | ||
| 13 | % a module to pack/compress states before asserting them in state_space | |
| 14 | :- use_module(specfile,[ csp_mode/0]). % b_or_z_mode/0, | |
| 15 | :- use_module(tools). | |
| 16 | :- use_module(b_global_sets). | |
| 17 | :- use_module(error_manager). | |
| 18 | ||
| 19 | :- use_module(module_information). | |
| 20 | :- module_info(group,animator). | |
| 21 | :- module_info(description,'This module packs and upacks states and values.'). | |
| 22 | ||
| 23 | :- dynamic bind_skeleton/2. % stores the list of variable names | |
| 24 | % we assume they are always in the same order; otherwise there is a problem | |
| 25 | % there is a separate skeleton for const_and_vars list of variables only and for full states with constants/variables (as generated by CBC checking) | |
| 26 | ||
| 27 | %pack_state(S,R) :- tools_printing:print_term_summary(S),nl,fail. | |
| 28 | pack_state(root,R) :- !, R=root. | |
| 29 | pack_state(const_and_vars(ID,S),R) :- % b_or_z_mode, % here for efficiency we assume that we are in B mode; any plug-in should not use this state constructor !! | |
| 30 | !, | |
| 31 | R='$cst_vars'(ID,PCS), | |
| 32 | % debug:time(state_packing:pack_bind_list(S,PS)). | |
| 33 | (bind_skeleton(const_and_vars,Skel) -> pack_bind_list(S,Skel,PS) | |
| 34 | ; pack_bind_list(S,Skel,PS), %print(vskel(Skel)),nl, | |
| 35 | (bind_skeleton(const_and_vars,OtherList) | |
| 36 | -> add_internal_error('Multiple bind skeletons:',OtherList:Skel) ; true), | |
| 37 | assert(bind_skeleton(const_and_vars,Skel))), | |
| 38 | compress_list(PS,PCS). | |
| 39 | %pack_state(concrete_constants(S),R) :- !, . % leads to further reduction in memory consumption, but to a slowdown | |
| 40 | % R = '$cst'(PCS), | |
| 41 | % (bind_skeleton(concrete_constants,Skel) -> pack_bind_list(S,Skel,PS) | |
| 42 | % ; pack_bind_list(S,Skel,PS), %print(vskel(Skel)),nl, | |
| 43 | % assert(bind_skeleton(concrete_constants,Skel))), | |
| 44 | % compress_list(PS,PCS). | |
| 45 | pack_state([bind(V,Val)|T],R) :- % b_or_z_mode, % again, for effiency we do not check whether we are in B mode here | |
| 46 | !, | |
| 47 | R='$bind_lst'(PV1,PCT), | |
| 48 | pack_value(Val,PV), | |
| 49 | (bind_skeleton(list,[V|Skel]) | |
| 50 | -> PV1=PV,pack_bind_list(T,Skel,PT1) | |
| 51 | ; pack_bind_list(T,Skel,PT), | |
| 52 | (bind_skeleton(list,OtherList) | |
| 53 | -> add_warning(pack_state,'Multiple bind skeletons:',OtherList:[V|Skel]), | |
| 54 | reorder(OtherList,[V|Skel],[PV|PT],[PV1|PT1]), print(reordered(PT1)),nl | |
| 55 | ; assert(bind_skeleton(list,[V|Skel])), PT=PT1,PV=PV1 | |
| 56 | ) | |
| 57 | ), | |
| 58 | compress_list(PT1,PCT). | |
| 59 | pack_state(csp_and_b(CSP,B),R) :- !, R=csp_and_b(PCSP,PB), | |
| 60 | pack_state(CSP,PCSP), | |
| 61 | pack_state(B,PB). | |
| 62 | pack_state(CSP,R) :- | |
| 63 | preference(use_state_packing,true),csp_mode,!, | |
| 64 | pack_csp_expression(CSP,PCSP), R=PCSP. | |
| 65 | pack_state(V,V). | |
| 66 | ||
| 67 | :- use_module(library(lists),[nth1/3]). | |
| 68 | reorder([],_,_,[]). | |
| 69 | reorder([ID|T1],Skel,Vals,[V2|T2]) :- nth1(Nr,Skel,ID), nth1(Nr,Vals,V2),!, | |
| 70 | reorder(T1,Skel,Vals,T2). | |
| 71 | reorder([ID|T1],Skel,Vals,Res) :- add_internal_error('Cannot find identifier:',ID), | |
| 72 | reorder(T1,Skel,Vals,Res). | |
| 73 | ||
| 74 | %compress_list([A,B,C,D|T],l4(A,B,C,D,CT)) :- !, compress_list(T,CT). | |
| 75 | %compress_list(List,'$bitvector'(Val,Len,CT)) :- compress_bv(List,Val,Len,T), !, compress_list(T,CT). | |
| 76 | compress_list([A,B,C|T],l3(A,B,C,CT)) :- !, compress_list(T,CT). | |
| 77 | %compress_list([A,B,C|T],l3c(ID,CT)) :- !, store_value((A,B,C),ID),compress_list(T,CT). % TO DO: use this when preferences:preference(use_state_packing,true) ? | |
| 78 | compress_list(T,T). | |
| 79 | ||
| 80 | %uncompress_list(l2(A,B,CT),[A,B|T]) :- uncompress_list(CT,T). | |
| 81 | uncompress_list(l3(A,B,C,CT),[A,B,C|T]) :- !, uncompress_list(CT,T). | |
| 82 | %uncompress_list('$bitvector'(Val,Len,CT),Res) :- !, uncompress_bv(Val,Len,T,Res), uncompress_list(CT,T). | |
| 83 | %uncompress_list(l3c(ID,CT),[A,B,C|T]) :- stored_value(ID,(A,B,C)),!,uncompress_list(CT,T). | |
| 84 | %uncompress_list(l4(A,B,C,D,CT),[A,B,C,D|T]) :- uncompress_list(CT,T). | |
| 85 | uncompress_list(T,T). | |
| 86 | ||
| 87 | ||
| 88 | :- use_module(error_manager,[add_internal_error/2]). | |
| 89 | pack_bind_list([],[],R) :- !,R=[]. | |
| 90 | pack_bind_list([bind(V,Val)|T],[V|VT],R) :- !,R=[PV|PT], | |
| 91 | pack_value(Val,PV), | |
| 92 | pack_bind_list(T,VT,PT). | |
| 93 | pack_bind_list(V,VT,R) :- | |
| 94 | add_internal_error('Illegal value: ',pack_bind_list(V,VT,R)),R=V. | |
| 95 | ||
| 96 | ||
| 97 | :- use_module(library(avl)). | |
| 98 | unpack_state(root,State) :- !, State=root. | |
| 99 | unpack_state(concrete_constants(C),State) :- !, State=concrete_constants(C). % comment out in case concrete_constants are packed after all | |
| 100 | unpack_state(PackedState,State) :- %empty_avl(E), %tools_printing:print_term_summary(unpack(PackedState,State)),nl, % trace, | |
| 101 | %tools_printing:print_term_summary(unpack_state(PackedState)), | |
| 102 | unpack_state2(PackedState,State). | |
| 103 | ||
| 104 | %unpack_state(concrete_constants(S),R) --> {b_or_z_mode},!, {R=concrete_constants(UPS)}, unpack_state(S,UPS). % leads to further reduction | |
| 105 | unpack_state2(const_and_vars(ID,CS),R) :- !, | |
| 106 | R=const_and_vars(ID,UPS), | |
| 107 | unpack_state2(CS,UPS). | |
| 108 | %unpack_state2('$cst'(CS),R) :- !, | |
| 109 | % R=concrete_constants(UPS), | |
| 110 | % uncompress_list(CS,S),get_bind_skeleton(concrete_constants,Skel), | |
| 111 | % unpack_bind_list(S,Skel,UPS). | |
| 112 | unpack_state2('$cst_vars'(ID,CS),R) :- % {b_or_z_mode}, we assume const_and_vars is only used in B or Z mode or is compatible | |
| 113 | !, | |
| 114 | R=const_and_vars(ID,UPS), | |
| 115 | uncompress_list(CS,S),get_bind_skeleton(const_and_vars,Skel), | |
| 116 | unpack_bind_list(S,Skel,UPS). | |
| 117 | unpack_state2('$bind_lst'(Val,CT),R) :- % {b_or_z_mode}, we assume $bind_lst not used by any plug-in | |
| 118 | !, | |
| 119 | uncompress_list(CT,T),get_bind_skeleton(list,[Var|Skel]),R=[bind(Var,UPV)|RT], | |
| 120 | unpack_value(Val,UPV), %!, | |
| 121 | unpack_bind_list(T,Skel,RT). | |
| 122 | unpack_state2(csp_and_b(CSP,B),csp_and_b(UPCSP,UPB)) :- !, unpack_state2(CSP,UPCSP), | |
| 123 | unpack_state2(B,UPB). | |
| 124 | unpack_state2(PCSP,R) :- | |
| 125 | csp_mode,preference(use_state_packing,true),!, | |
| 126 | unpack_csp_expression(PCSP,R). | |
| 127 | unpack_state2(R,R). | |
| 128 | ||
| 129 | unpack_bind_list([],[],[]). | |
| 130 | unpack_bind_list([Val|T],[Var|VT],R) :- R=[bind(Var,UPV)|UPT], | |
| 131 | unpack_value(Val,UPV), %!, | |
| 132 | unpack_bind_list(T,VT,UPT). | |
| 133 | %unpack_bind_list('$bind_lst'(Var,Val,_),_) --> {add_internal_error('Unpacking value failed: ',Var/Val),fail}. | |
| 134 | ||
| 135 | ||
| 136 | get_bind_skeleton(Category,X) :- | |
| 137 | (bind_skeleton(Category,X) -> true | |
| 138 | ; add_internal_error('No bind skeleton stored for: ',get_bind_skeleton(Category,X)),fail). | |
| 139 | ||
| 140 | % a simpler version for list of bind-pairs; does not require bind_skeleton to be set up / stored | |
| 141 | pack_values([],[]) :- !. | |
| 142 | pack_values([bind(V,Val)|T],R) :- !,R=[Bind|PT], | |
| 143 | pack_bind(Val,V,Bind), | |
| 144 | pack_values(T,PT). | |
| 145 | pack_values(V,R) :- add_internal_error('Illegal value: ',pack_values(V,R)),R=V. | |
| 146 | ||
| 147 | pack_bind([],V,R) :- !, R='$bind_empty_set'(V). | |
| 148 | pack_bind(pred_false,V,R) :- !, R='$bind_false'(V). % bind boolean values | |
| 149 | pack_bind(pred_true,V,R) :- !, R='$bind_true'(V). | |
| 150 | pack_bind(Val,V,'$bind'(V,PV)) :- pack_value(Val,PV). | |
| 151 | ||
| 152 | unpack_bind('$bind_empty_set'(V),V,[]). | |
| 153 | unpack_bind('$bind_false'(V),V,pred_false). | |
| 154 | unpack_bind('$bind_true'(V),V,pred_true). | |
| 155 | unpack_bind('$bind'(V,PV),V,Val) :- unpack_value(PV,Val). | |
| 156 | ||
| 157 | unpack_values([],[]) :- !. | |
| 158 | unpack_values([PBind|T],R) :- unpack_bind(PBind,V,Val),!, | |
| 159 | R=[bind(V,Val)|UPT], | |
| 160 | unpack_values(T,UPT). | |
| 161 | unpack_values(V,R) :- add_internal_error('Illegal value: ',unpack_values(V,R)),R=V. | |
| 162 | ||
| 163 | ||
| 164 | :- use_module(library(avl)). | |
| 165 | :- use_module(preferences,[preference/2]). | |
| 166 | :- use_module(custom_explicit_sets,[is_interval_closure/5, construct_interval_closure/3]). | |
| 167 | ||
| 168 | pack_value(Var,R) :- var(Var),!, | |
| 169 | add_internal_error('Illegal variable value: ', pack_value(Var,R)), | |
| 170 | R='$variable'(Var). | |
| 171 | pack_value(avl_set(A),R) :- !, %R\==[], | |
| 172 | avl_domain(A,AD), | |
| 173 | %avl_packed_domain(A,ADL,[]), | |
| 174 | (pack_fd_set(AD,Type,PackedInteger) -> R = '$avl_bv'(PackedInteger,Type) % avl bit vector %, print(packed(PackedInteger,AD)),nl | |
| 175 | ; l_pack_value(AD,ADL), | |
| 176 | (preferences:preference(use_state_packing,true) %ADL=[_,_|_] | |
| 177 | -> R='$stored_avl'(ID),store_value(ADL,ID) | |
| 178 | % , print(stored(ID,ADL)),nl | |
| 179 | ; R='$avl_exp'(ADL)) % ,print(packed(A,R)),nl | |
| 180 | ). | |
| 181 | pack_value((A,B),(PA,PB)) :- !, pack_value(A,PA), pack_value(B,PB). | |
| 182 | pack_value(fd(Nr,T),R) :- pack_basic_fd_value(T,Nr,Atom),!,Atom=R. | |
| 183 | pack_value(int(Nr),R) :- !, R=Nr. | |
| 184 | pack_value(closure(P,T,B),R) :- is_interval_closure(P,T,B,Low,Up),!, | |
| 185 | %print(pack_interval(Low,Up,B)),nl, | |
| 186 | R='$interval'(Low,Up). | |
| 187 | %pack_value(closure(P,T,B),R) :- is_cartesian_product_closure(CPA,A1,A2),!, | |
| 188 | % R='$cartesian_product'(PA1,PA2), | |
| 189 | % pack_value(A1,PA1), pack_value(A2,PA2). | |
| 190 | pack_value(V,V). | |
| 191 | % to do: records + maybe closures (interval-closures,... ?) | |
| 192 | ||
| 193 | /* not worth it : | |
| 194 | % compute avl_domain and apply pack_value in one go: | |
| 195 | avl_packed_domain(empty, Domain, Domain). | |
| 196 | avl_packed_domain(node(Key,_,_,L,R), Domain0, Domain) :- | |
| 197 | pack_value(Key,PKey), | |
| 198 | avl_packed_domain(L, Domain0, [PKey|Domain1]), | |
| 199 | avl_packed_domain(R, Domain1, Domain). | |
| 200 | */ | |
| 201 | ||
| 202 | l_pack_value([],[]). | |
| 203 | l_pack_value([H|T],[PH|PT]) :- pack_value(H,PH), l_pack_value(T,PT). | |
| 204 | ||
| 205 | % TO DO or [(fd,fd) as bit-vectors if <xx bits | |
| 206 | ||
| 207 | % Pack set of FD values as bit-vector representation | |
| 208 | pack_fd_set([fd(X,Type)|T],Type,Result) :- | |
| 209 | b_global_sets:b_get_fd_type_bounds(Type,1,UpBound), | |
| 210 | (UpBound < 28 -> true /* we are ok on 32-bit systems */ | |
| 211 | ; UpBound < 60, platform_is_64_bit), /* prolog_flag(max_tagged_integer,X), Y is 1<<59, Y<X. */ | |
| 212 | Acc is 1<<X, | |
| 213 | pack_fd_set_aux(T,Acc,Result). | |
| 214 | ||
| 215 | pack_fd_set_aux([],A,A). | |
| 216 | pack_fd_set_aux([fd(X,_)|T],Acc,Res) :- | |
| 217 | NewAcc is Acc \/ (1<<X), | |
| 218 | pack_fd_set_aux(T,NewAcc,Res). | |
| 219 | ||
| 220 | % unpack a bit-vector set representation | |
| 221 | unpack_fd_set(PackedInteger,Type,Value) :- | |
| 222 | unpack_fd_set_aux(PackedInteger,0,Type,ResList), %print(unpacked(PackedInteger,ResList)),nl, | |
| 223 | custom_explicit_sets:ord_list_to_avlset_direct(ResList,Value,unpack_fd_set). | |
| 224 | ||
| 225 | unpack_fd_set_aux(0,_,_,Res) :- !, Res=[]. | |
| 226 | unpack_fd_set_aux(Nr,X,Type,Res) :- | |
| 227 | (Nr mod 2 =:= 1 -> Res = [fd(X,Type)-true|T] ; Res=T), | |
| 228 | X1 is X+1, Nr1 is (Nr>>1), | |
| 229 | unpack_fd_set_aux(Nr1,X1,Type,T). | |
| 230 | ||
| 231 | % first rough attempt at packing CSP expressions | |
| 232 | pack_csp_expression(esharing(Set,B,C,Span),'$esharing'(PSet,PB,PC,PSpan)) :- !, | |
| 233 | pack_csp_expression(Set,PSet), pack_csp_expression(B,PB), | |
| 234 | pack_csp_expression(C,PC), pack_csp_expression(Span,PSpan). | |
| 235 | pack_csp_expression('|||'(A,B,Span),'|||'(PA,PB,PSpan)) :- !, | |
| 236 | pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(Span,PSpan). | |
| 237 | %pack_csp_expression('&'(A,B),'&'(PA,PB)) :- !, | |
| 238 | % pack_csp_expression(A,PA), pack_csp_expression(B,PB). | |
| 239 | pack_csp_expression('[]'(A,B,Span),'[]'(PA,PB,PSpan)) :- !, | |
| 240 | pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(Span,PSpan). | |
| 241 | pack_csp_expression(eaParallel(C,A,D,B,Span),eaParallel(PC,PA,PD,PB,PSpan)) :- !, | |
| 242 | pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(C,PC), | |
| 243 | pack_csp_expression(D,PD), pack_csp_expression(Span,PSpan). | |
| 244 | %pack_csp_expression(prefix(C,A,D,B,Span),prefix(PC,PA,PD,PB,PSpan)) :- !, | |
| 245 | % pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(C,PC), | |
| 246 | % pack_csp_expression(D,PD), pack_csp_expression(Span,PSpan). | |
| 247 | %pack_csp_expression(ifte(C,A,D,B,Span,S3),ifte(PC,PA,PD,PB,PSpan,S3)) :- !, | |
| 248 | % pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(C,PC), | |
| 249 | % pack_csp_expression(D,PD), pack_csp_expression(Span,PSpan). | |
| 250 | %pack_csp_expression(V,'$stored_csp'(ID)) :- store_value(V,ID). | |
| 251 | pack_csp_expression(V,ID) :- store_value(V,ID). | |
| 252 | ||
| 253 | unpack_csp_expression('$esharing'(PSet,PB,PC,PSpan),esharing(Set,B,C,Span)) :- !, | |
| 254 | unpack_csp_expression(PSet,Set), unpack_csp_expression(PB,B), | |
| 255 | unpack_csp_expression(PC,C), unpack_csp_expression(PSpan,Span). | |
| 256 | unpack_csp_expression('|||'(A,B,Span),'|||'(PA,PB,PSpan)) :- !, | |
| 257 | unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(Span,PSpan). | |
| 258 | %unpack_csp_expression('&'(A,B),'&'(PA,PB)) :- !, | |
| 259 | % unpack_csp_expression(A,PA), unpack_csp_expression(B,PB). | |
| 260 | unpack_csp_expression('[]'(A,B,Span),'[]'(PA,PB,PSpan)) :- !, | |
| 261 | unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(Span,PSpan). | |
| 262 | unpack_csp_expression(eaParallel(C,A,D,B,Span),eaParallel(PC,PA,PD,PB,PSpan)) :- !, | |
| 263 | unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(C,PC), | |
| 264 | unpack_csp_expression(D,PD), unpack_csp_expression(Span,PSpan). | |
| 265 | %unpack_csp_expression(prefix(C,A,D,B,Span),prefix(PC,PA,PD,PB,PSpan)) :- !, | |
| 266 | % unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(C,PC), | |
| 267 | % unpack_csp_expression(D,PD), unpack_csp_expression(Span,PSpan). | |
| 268 | %unpack_csp_expression(ifte(C,A,D,B,Span,S3),ifte(PC,PA,PD,PB,PSpan,S3)) :- !, | |
| 269 | % unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(C,PC), | |
| 270 | % unpack_csp_expression(D,PD), unpack_csp_expression(Span,PSpan). | |
| 271 | %unpack_csp_expression('$stored_csp'(ID),V) :- !, stored_value(ID,V). | |
| 272 | unpack_csp_expression(ID,V) :- !, stored_value(ID,V). | |
| 273 | unpack_csp_expression(V,V). | |
| 274 | ||
| 275 | %unpack_value(Val,UPVal) :- unpack_value(Val,UPVal,empty,_). | |
| 276 | ||
| 277 | unpack_value(V,R) :- var(V),!, | |
| 278 | add_internal_error('Illegal variable value: ', unpack_value(V,R)), R=V. | |
| 279 | unpack_value('$avl_exp'(AD),R) :- !, unpack_avl_expanded(AD,R). | |
| 280 | unpack_value('$stored_avl'(ID),R) :- !, | |
| 281 | (stored_value(ID,Val) -> true ; add_internal_error('No stored AVL: ',ID),fail), | |
| 282 | unpack_avl_expanded(Val,R). | |
| 283 | unpack_value('$avl_bv'(PackedInteger,Type),R) :- !, unpack_fd_set(PackedInteger,Type,R). | |
| 284 | /* comment in and re-add DCG to try and re-construct sharing; does seem to increase memory usage for vital_gradient_values | |
| 285 | unpack_value('$stored_avl'(ID),R,InEnv,OutEnv) :- !, | |
| 286 | (avl_fetch(ID,InEnv,ER) %(expanded(ID,ER),InEnv) | |
| 287 | -> R = ER, OutEnv=InEnv % reuse the already expanded value: will also decrease memory consumption due to sharing | |
| 288 | ; stored_value(ID,Val), | |
| 289 | avl_store(ID,InEnv,R,InEnv2), % OutEnv=[expanded(ID,R)|OutEnv2], % note: ID cannot occur inside Val | |
| 290 | unpack_avl_expanded(Val,R,InEnv2,OutEnv)). | |
| 291 | */ | |
| 292 | %unpack_value('$cartesian_product'(A,B),R) :- unpack_value(A,PA), unpack_value(B,PB), | |
| 293 | % construct_cartesian_product_closure(PA,PB,R). | |
| 294 | unpack_value('$interval'(A,B),R) :- !, construct_interval_closure(A,B,R). | |
| 295 | unpack_value((A,B),(PA,PB)) :- !, unpack_value(A,PA), unpack_value(B,PB). | |
| 296 | unpack_value(Nr,R) :- number(Nr),!, R=int(Nr). | |
| 297 | unpack_value(V,UPV) :- unpack_basic_fd_value(V,FD),!,UPV=FD. | |
| 298 | unpack_value(V,V). | |
| 299 | ||
| 300 | unpack_avl_expanded(AD,R) :- | |
| 301 | l_unpack_value(AD,ADT), | |
| 302 | custom_explicit_sets:ord_list_to_avlset_direct(ADT,R,unpack_value). | |
| 303 | ||
| 304 | l_unpack_value([],[]). | |
| 305 | l_unpack_value([H|T],[PH-true|PT]) :- unpack_value(H,PH), l_unpack_value(T,PT). | |
| 306 | ||
| 307 | % ------------------------- | |
| 308 | ||
| 309 | % a version of pack_state which makes use of a previously packed state and a ordered list of written variables | |
| 310 | % incremental_pack_state(State,PrevPackedState,WrittenVariables,PackedState) | |
| 311 | % The idea is to re-use the packed values from the previous state if possible | |
| 312 | ||
| 313 | % Note: bind_skeleton does not need to be stored as these clauses only apply when previous state of same type exists | |
| 314 | incremental_pack_state(const_and_vars(ID,T),'$cst_vars'(ID,PrevCT),Written,'$cst_vars'(ID,PCT)) :- !, | |
| 315 | uncompress_list(PrevCT,PrevT), | |
| 316 | incr_pack_bind_list(T,PrevT,Written,PT), | |
| 317 | compress_list(PT,PCT). | |
| 318 | incremental_pack_state([bind(V,Val)|T],'$bind_lst'(PrevV,PrevCT),Written,'$bind_lst'(PV,PCT)) :- !, | |
| 319 | uncompress_list(PrevCT,PrevT), | |
| 320 | incremental_pack_value(Val,V,PrevV,Written,PV), | |
| 321 | incr_pack_bind_list(T,PrevT,Written,PT), | |
| 322 | compress_list(PT,PCT). | |
| 323 | incremental_pack_state(State,_,_,PackedState) :- pack_state(State,PackedState). | |
| 324 | ||
| 325 | :- use_module(library(ordsets),[ord_member/2]). | |
| 326 | incremental_pack_value(int(Nr),_,_,_W,R) :- !, R=Nr. | |
| 327 | incremental_pack_value(Val,_,_,_W,R) :- not_packed(Val),!, R=Val. | |
| 328 | incremental_pack_value(Val,Var,_Prev,Written,PackedValue) :- ord_member(Var,Written), !, | |
| 329 | pack_value(Val,PackedValue). | |
| 330 | incremental_pack_value(_,_,PrevPackVal,_W,PrevPackVal). % copy previously packed value | |
| 331 | ||
| 332 | not_packed(pred_false). | |
| 333 | not_packed(pred_true). | |
| 334 | not_packed(string(_)). | |
| 335 | ||
| 336 | incr_pack_bind_list([],_,_,[]). | |
| 337 | incr_pack_bind_list([bind(V,Val)|T],[PrevV|PrevT],Written,[PackedValue|PT]) :- | |
| 338 | incremental_pack_value(Val,V,PrevV,Written,PackedValue), | |
| 339 | incr_pack_bind_list(T,PrevT,Written,PT). | |
| 340 | ||
| 341 | % ------------------------- | |
| 342 | ||
| 343 | :- dynamic pack_basic_fd_value/3, unpack_basic_fd_value/2. | |
| 344 | % associate precompiled atoms with all enumerated & deferred set elements; TO DO: only do for "smaller" SETS | |
| 345 | precompile_state_packing :- | |
| 346 | retractall(pack_basic_fd_value(_,_,_)), | |
| 347 | retractall(unpack_basic_fd_value(_,_)), | |
| 348 | ? | b_global_sets:enum_global_type(fd(Nr,T),_), |
| 349 | string_concatenate('$fd_',T,FDT), | |
| 350 | string_concatenate(FDT,Nr,NewAtom), | |
| 351 | %debug:debug_println(9,pack(T,Nr,NewAtom)), | |
| 352 | assert(pack_basic_fd_value(T,Nr,NewAtom)), | |
| 353 | assert(unpack_basic_fd_value(NewAtom,fd(Nr,T))),fail. | |
| 354 | precompile_state_packing. | |
| 355 | ||
| 356 | % ------------------------ | |
| 357 | ||
| 358 | :- dynamic stored_value/2, stored_value_hash_to_id/2, next_value_id/1. | |
| 359 | next_value_id(0). | |
| 360 | ||
| 361 | reset_stored_values :- | |
| 362 | retractall(bind_skeleton(_,_)), | |
| 363 | retractall(stored_value(_,_)), | |
| 364 | retractall(stored_value_hash_to_id(_,_)), | |
| 365 | retractall(next_value_id(_)), assert(next_value_id(0)). | |
| 366 | ||
| 367 | :- use_module(library(terms),[term_hash/3]). | |
| 368 | store_value(Value,ID) :- | |
| 369 | term_hash(Value,[range(smallint),algorithm(sdbm), depth(infinite),if_var(ignore)],Hash), | |
| 370 | %hashing:my_term_hash(Value,Hash), | |
| 371 | store_value_aux(Value,Hash,ID). | |
| 372 | ||
| 373 | store_value_aux(Value,Hash,ID) :- | |
| 374 | stored_value_hash_to_id(Hash,ID), | |
| 375 | stored_value(ID,Value),!. % we have already stored the value | |
| 376 | store_value_aux(Value,Hash,ID) :- | |
| 377 | retract(next_value_id(NID)), NID1 is NID+1, | |
| 378 | assert(next_value_id(NID1)), | |
| 379 | assert(stored_value(NID,Value)), assert(stored_value_hash_to_id(Hash,NID)), | |
| 380 | ID=NID. | |
| 381 | ||
| 382 | :- use_module(tools_printing, [print_dynamic_pred/3]). | |
| 383 | % state_packing:print_stored_values | |
| 384 | print_stored_values :- % for saving state_space to file | |
| 385 | print_dynamic_pred(state_packing,bind_skeleton,2), | |
| 386 | print_dynamic_pred(state_packing,stored_value,2), | |
| 387 | print_dynamic_pred(state_packing,stored_value_hash_to_id,2), | |
| 388 | print_dynamic_pred(state_packing,next_value_id,1). | |
| 389 | ||
| 390 | ||
| 391 | retract_stored_values_with_statistics :- | |
| 392 | retract_with_statistics(state_packing,[stored_value(_,_), | |
| 393 | stored_value_hash_to_id(_,_)]), | |
| 394 | reset_stored_values. | |
| 395 | ||
| 396 | % ------------------------------------- | |
| 397 | ||
| 398 | % utility to translate boolean variables into bit-vector integers (not used yet; degrades performance) | |
| 399 | ||
| 400 | :- use_module(self_check). | |
| 401 | :- assert_must_succeed((Input=[pred_false,pred_true,pred_false,1],state_packing:compress_bv(Input,Val,Len,Rest), state_packing:uncompress_bv(Val,Len,Rest,Res), Res=Input)). | |
| 402 | :- assert_must_succeed((Input=[pred_false,pred_false],state_packing:compress_bv(Input,Val,Len,Rest), state_packing:uncompress_bv(Val,Len,Rest,Res), Res=Input)). | |
| 403 | :- assert_must_succeed((Input=[pred_true,pred_true],state_packing:compress_bv(Input,Val,Len,Rest), state_packing:uncompress_bv(Val,Len,Rest,Res), Res=Input)). | |
| 404 | ||
| 405 | % compress successive boolean values (at least 2) | |
| 406 | compress_bv([P|T],Val,Len,Rest) :- get_bool_bv(P,Acc), compress_bv2(T,Acc,Val,Len,Rest). | |
| 407 | get_bool_bv(pred_true,1). | |
| 408 | get_bool_bv(pred_false,0). | |
| 409 | compress_bv2([P|T],Acc,Val,Len,Rest) :- get_bool_bv(P,BoolVal),!, | |
| 410 | Acc2 is Acc + BoolVal*2, % BoolVal+(Acc << 1), | |
| 411 | compress_bv3(T,Acc2,Val,2,Len,Rest). | |
| 412 | compress_bv3([P|T],Acc,Val,AccLen,Len,Rest) :- %get_bool_bv(P,BoolVal),!, | |
| 413 | (P=pred_true -> Acc2 is Acc + (1 << AccLen) ; P=pred_false -> Acc2 = Acc), !, | |
| 414 | %Acc2 is Acc + BoolVal*(2^AccLen), | |
| 415 | AccLen2 is AccLen+1, compress_bv3(T,Acc2,Val,AccLen2,Len,Rest). | |
| 416 | compress_bv3(Rest,Acc,Acc,AccLen,AccLen,Rest). | |
| 417 | ||
| 418 | % uncompress bitvector Val of Len bits into list of pred_true, pred_false elements | |
| 419 | uncompress_bv(_,Len,Rest,Res) :- Len =< 0, !, Res=Rest. | |
| 420 | uncompress_bv(Val,Len,Rest,[BV|TRes]) :- | |
| 421 | (Val mod 2 =:= 1 -> BV = pred_true ; BV=pred_false), | |
| 422 | Val2 is Val >> 1, Len1 is Len-1, | |
| 423 | uncompress_bv(Val2,Len1,Rest,TRes). | |
| 424 | ||
| 425 |