| 1 | % (c) 2009-2025 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, recompute_state_packing_preference/0, | |
| 6 | precompile_state_packing/0, % to be called after b_global_sets precompiled | |
| 7 | pack_state/2, unpack_state/2, | |
| 8 | unpack_state_top_level/2, | |
| 9 | incremental_pack_state/4, | |
| 10 | pack_values/2, unpack_values/2, | |
| 11 | pack_value/2, unpack_value/2, | |
| 12 | ||
| 13 | pack_bind_list/3, % pack a list of bind/2 terms and skeleton returning list of values | |
| 14 | unpack_bind_list/3, | |
| 15 | ||
| 16 | get_packed_b_state_with_uncompressed_lists/2, | |
| 17 | print_stored_values/1, set_next_value_id/1, | |
| 18 | retract_stored_values_with_statistics/0, | |
| 19 | print_state_packing_profile/0]). | |
| 20 | ||
| 21 | % a module to pack/compress states before asserting them in state_space | |
| 22 | :- use_module(specfile,[ csp_mode/0]). % b_or_z_mode/0, | |
| 23 | :- use_module(tools). | |
| 24 | :- use_module(b_global_sets). | |
| 25 | :- use_module(error_manager). | |
| 26 | :- use_module(debug,[debug_mode/1]). | |
| 27 | :- use_module(library(avl)). | |
| 28 | :- use_module(preferences,[preference/2, get_preference/2, set_preference/2]). | |
| 29 | :- use_module(custom_explicit_sets,[is_interval_closure/5, construct_interval_closure/3]). | |
| 30 | ||
| 31 | :- use_module(module_information). | |
| 32 | :- module_info(group,state_space). | |
| 33 | :- module_info(description,'This module packs and upacks states and values.'). | |
| 34 | ||
| 35 | :- dynamic bind_skeleton/2. % stores the list of variable names | |
| 36 | % we assume they are always in the same order; otherwise there is a problem | |
| 37 | % 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) | |
| 38 | ||
| 39 | %pack_state(S,R) :- print('pack '), tools_printing:print_term_summary(S),nl,fail. | |
| 40 | pack_state(root,R) :- !, R=root. | |
| 41 | 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 !! | |
| 42 | !, | |
| 43 | R='$cst_vars'(ID,PCS), | |
| 44 | % debug:time(state_packing:pack_bind_list(S,PS)). | |
| 45 | (bind_skeleton(const_and_vars,Skel) -> pack_bind_list(S,Skel,PS) | |
| 46 | ; pack_bind_list(S,Skel,PS), %print(vskel(Skel)),nl, | |
| 47 | (bind_skeleton(const_and_vars,OtherList) | |
| 48 | -> add_internal_error('Multiple bind skeletons for const_and_vars:',OtherList:Skel) ; true), | |
| 49 | assertz(bind_skeleton(const_and_vars,Skel))), | |
| 50 | compress_list(PS,PCS). | |
| 51 | pack_state(concrete_constants(S),R) :- preference(use_state_packing,full), | |
| 52 | !, | |
| 53 | % leads to further reduction in memory consumption, but to a slowdown | |
| 54 | R = '$cst'(PCS), | |
| 55 | (bind_skeleton(concrete_constants,Skel) -> pack_bind_list(S,Skel,PS) | |
| 56 | ; pack_bind_list(S,Skel,PS), %print(vskel(Skel)),nl, | |
| 57 | assertz(bind_skeleton(concrete_constants,Skel))), | |
| 58 | compress_list(PS,PCS). | |
| 59 | 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 | |
| 60 | !, | |
| 61 | R='$bind_lst'(PV1,PCT), | |
| 62 | pack_value(Val,PV), | |
| 63 | (bind_skeleton(list,[V|Skel]) | |
| 64 | -> PV1=PV,pack_bind_list(T,Skel,PT1) | |
| 65 | ; pack_bind_list(T,Skel,PT), | |
| 66 | (bind_skeleton(list,OtherList) | |
| 67 | -> add_warning(pack_state,'Multiple bind skeletons:',OtherList:[V|Skel]), | |
| 68 | reorder(OtherList,[V|Skel],[PV|PT],[PV1|PT1]) %,print(reordered(PT1)),nl | |
| 69 | ; assertz(bind_skeleton(list,[V|Skel])), PT=PT1,PV=PV1 | |
| 70 | ) | |
| 71 | ), | |
| 72 | compress_list(PT1,PCT). | |
| 73 | pack_state([],R) :- !, R=[]. | |
| 74 | pack_state(csp_and_b(CSP,B),R) :- !, R=csp_and_b(PCSP,PB), | |
| 75 | pack_state(CSP,PCSP), | |
| 76 | pack_state(B,PB). | |
| 77 | pack_state(expanded_const_and_vars(C,V,_,_),R) :- !, | |
| 78 | pack_state(const_and_vars(C,V),R). | |
| 79 | pack_state(expanded_vars(V,_),R) :- !, | |
| 80 | pack_state(V,R). | |
| 81 | pack_state(CSP,R) :- | |
| 82 | \+ preference(use_state_packing,false),csp_mode,!, | |
| 83 | pack_csp_expression(CSP,PCSP), R=PCSP. | |
| 84 | pack_state(V,V). | |
| 85 | ||
| 86 | :- use_module(library(lists),[nth1/3]). | |
| 87 | reorder([],_,_,[]). | |
| 88 | reorder([ID|T1],Skel,Vals,[V2|T2]) :- nth1(Nr,Skel,ID), nth1(Nr,Vals,V2),!, | |
| 89 | reorder(T1,Skel,Vals,T2). | |
| 90 | reorder([ID|T1],Skel,Vals,Res) :- add_internal_error('Cannot find identifier:',ID), | |
| 91 | reorder(T1,Skel,Vals,Res). | |
| 92 | ||
| 93 | %compress_list([A,B,C,D|T],l4(A,B,C,D,CT)) :- !, compress_list(T,CT). | |
| 94 | %compress_list(List,'$bitvector'(Val,Len,CT)) :- compress_bv(List,Val,Len,T), !, compress_list(T,CT). | |
| 95 | compress_list([A,B,C|T],l3(A,B,C,CT)) :- !, compress_list(T,CT). | |
| 96 | %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) ? | |
| 97 | compress_list(T,T). | |
| 98 | ||
| 99 | %uncompress_list(l2(A,B,CT),[A,B|T]) :- uncompress_list(CT,T). | |
| 100 | uncompress_list(l3(A,B,C,CT),[A,B,C|T]) :- !, uncompress_list(CT,T). | |
| 101 | %uncompress_list('$bitvector'(Val,Len,CT),Res) :- !, uncompress_bv(Val,Len,T,Res), uncompress_list(CT,T). | |
| 102 | %uncompress_list(l3c(ID,CT),[A,B,C|T]) :- stored_value(ID,(A,B,C)),!,uncompress_list(CT,T). | |
| 103 | %uncompress_list(l4(A,B,C,D,CT),[A,B,C,D|T]) :- uncompress_list(CT,T). | |
| 104 | uncompress_list(T,T). | |
| 105 | ||
| 106 | ||
| 107 | %pack_bind_list(Store,ValueList) :- pack_bind_list(Store,_,ValueList). | |
| 108 | ||
| 109 | :- use_module(error_manager,[add_internal_error/2]). | |
| 110 | pack_bind_list([],[],R) :- !,R=[]. | |
| 111 | pack_bind_list([bind(V,Val)|T],[V|VT],R) :- !,R=[PV|PT], | |
| 112 | %atom_concat(pack_,V,PackV),runtime_profiler:profile_single_call(PackV,state_packing:pack_value(Val,PV)), | |
| 113 | pack_value(Val,PV), | |
| 114 | pack_bind_list(T,VT,PT). | |
| 115 | pack_bind_list(V,VT,R) :- | |
| 116 | add_internal_error('Illegal call, probably illegal order of variables: ',pack_bind_list(V,VT,R)), | |
| 117 | R=V. | |
| 118 | ||
| 119 | ||
| 120 | % just unpack top-level constructor for matching against | |
| 121 | % WARNING: do not use state for any processing apart from checking top-level constructor and constants id | |
| 122 | % it can be used for something like state_corresponds_to_initialised_b_machine, state_corresponds_to_set_up_constants | |
| 123 | unpack_state_top_level(root,State) :- !, State=root. | |
| 124 | unpack_state_top_level(concrete_constants(C),State) :- !, State=concrete_constants(C). | |
| 125 | unpack_state_top_level(const_and_vars(ID,CS),R) :- !, R=const_and_vars(ID,CS). | |
| 126 | unpack_state_top_level('$cst'(CS),R) :- !, R=concrete_constants(CS). | |
| 127 | unpack_state_top_level('$cst_vars'(ID,CS),R) :- !, R=const_and_vars(ID,CS). | |
| 128 | unpack_state_top_level('$bind_lst'(Val,_),R) :- !, R=[bind(unknown,Val)]. | |
| 129 | unpack_state_top_level(csp_and_b(CSP,B),csp_and_b(UPCSP,UPB)) :- !, unpack_state_top_level(CSP,UPCSP), | |
| 130 | unpack_state_top_level(B,UPB). | |
| 131 | unpack_state_top_level(X,X). | |
| 132 | ||
| 133 | ||
| 134 | :- use_module(library(avl)). | |
| 135 | unpack_state(root,State) :- !, State=root. | |
| 136 | unpack_state(concrete_constants(C),State) :- !, State=concrete_constants(C). % comment out in case concrete_constants are packed after all | |
| 137 | unpack_state(PackedState,State) :- %empty_avl(E), %tools_printing:print_term_summary(unpack(PackedState,State)),nl, | |
| 138 | %tools_printing:print_term_summary(unpack_state(PackedState)), | |
| 139 | unpack_state2(PackedState,State). | |
| 140 | ||
| 141 | %unpack_state(concrete_constants(S),R) --> {b_or_z_mode},!, {R=concrete_constants(UPS)}, unpack_state(S,UPS). % leads to further reduction | |
| 142 | unpack_state2(const_and_vars(ID,CS),R) :- !, | |
| 143 | R=const_and_vars(ID,UPS), | |
| 144 | unpack_state2(CS,UPS). | |
| 145 | unpack_state2('$cst'(CS),R) :- !, | |
| 146 | R=concrete_constants(UPS), | |
| 147 | uncompress_list(CS,S),get_bind_skeleton(concrete_constants,Skel), | |
| 148 | unpack_bind_list(S,Skel,UPS). | |
| 149 | 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 | |
| 150 | !, | |
| 151 | R=const_and_vars(ID,UPS), | |
| 152 | uncompress_list(CS,S),get_bind_skeleton(const_and_vars,Skel), | |
| 153 | unpack_bind_list(S,Skel,UPS). | |
| 154 | unpack_state2('$bind_lst'(Val,CT),R) :- % {b_or_z_mode}, we assume $bind_lst not used by any plug-in | |
| 155 | !, | |
| 156 | uncompress_list(CT,T),get_bind_skeleton(list,[Var|Skel]),R=[bind(Var,UPV)|RT], | |
| 157 | %atom_concat(unpack_,Var,PackV),runtime_profiler:profile_single_call(PackV,state_packing:unpack_value(Val,UPV)), | |
| 158 | unpack_value(Val,UPV), %!, | |
| 159 | unpack_bind_list(T,Skel,RT). | |
| 160 | unpack_state2([],R) :- !, R=[]. | |
| 161 | unpack_state2(csp_and_b(CSP,B),csp_and_b(UPCSP,UPB)) :- !, unpack_state2(CSP,UPCSP), | |
| 162 | unpack_state2(B,UPB). | |
| 163 | unpack_state2(PCSP,R) :- | |
| 164 | csp_mode, \+ preference(use_state_packing,false),!, | |
| 165 | unpack_csp_expression(PCSP,R). | |
| 166 | unpack_state2(R,R). | |
| 167 | ||
| 168 | unpack_bind_list([],[],[]). | |
| 169 | unpack_bind_list([Val|T],[Var|VT],R) :- R=[bind(Var,UPV)|UPT], | |
| 170 | %atom_concat(unpack_,Var,PackV),runtime_profiler:profile_single_call(PackV,state_packing:unpack_value(Val,UPV)), | |
| 171 | unpack_value(Val,UPV), %!, | |
| 172 | unpack_bind_list(T,VT,UPT). | |
| 173 | %unpack_bind_list('$bind_lst'(Var,Val,_),_) --> {add_internal_error('Unpacking value failed: ',Var/Val),fail}. | |
| 174 | ||
| 175 | ||
| 176 | get_bind_skeleton(Category,X) :- | |
| 177 | (bind_skeleton(Category,X) -> true | |
| 178 | ; add_internal_error('No bind skeleton stored for: ',get_bind_skeleton(Category,X)),fail). | |
| 179 | ||
| 180 | % a simpler version for list of bind-pairs; does not require bind_skeleton to be set up / stored | |
| 181 | pack_values([],[]) :- !. | |
| 182 | pack_values([bind(V,Val)|T],R) :- !,R=[Bind|PT], | |
| 183 | pack_bind(Val,V,Bind), | |
| 184 | pack_values(T,PT). | |
| 185 | pack_values(V,R) :- add_internal_error('Illegal value, not a list of bindings: ',pack_values(V,R)),R=V. | |
| 186 | ||
| 187 | pack_bind([],V,R) :- !, R='$bind_empty_set'(V). | |
| 188 | pack_bind(pred_false,V,R) :- !, R='$bind_false'(V). % bind boolean values | |
| 189 | pack_bind(pred_true,V,R) :- !, R='$bind_true'(V). | |
| 190 | pack_bind(Val,V,'$bind'(V,PV)) :- pack_value(Val,PV). | |
| 191 | ||
| 192 | unpack_bind('$bind_empty_set'(V),V,[]). | |
| 193 | unpack_bind('$bind_false'(V),V,pred_false). | |
| 194 | unpack_bind('$bind_true'(V),V,pred_true). | |
| 195 | unpack_bind('$bind'(V,PV),V,Val) :- unpack_value(PV,Val). | |
| 196 | ||
| 197 | unpack_values([],[]) :- !. | |
| 198 | unpack_values([PBind|T],R) :- unpack_bind(PBind,V,Val),!, | |
| 199 | R=[bind(V,Val)|UPT], | |
| 200 | unpack_values(T,UPT). | |
| 201 | unpack_values(V,R) :- | |
| 202 | add_internal_error('Illegal value: ',unpack_values(V,R)),R=V. | |
| 203 | ||
| 204 | ||
| 205 | ||
| 206 | pack_value(Var,R) :- var(Var),!, | |
| 207 | add_internal_error('Illegal variable value: ', pack_value(Var,R)), | |
| 208 | R='$variable'(Var). | |
| 209 | pack_value(avl_set(A),R) :- !, pack_avl_set(A,R). | |
| 210 | pack_value((A,B),(PA,PB)) :- !, pack_value(A,PA), pack_value(B,PB). | |
| 211 | pack_value(fd(Nr,T),R) :- pack_basic_fd_value(T,Nr,Atom),!,Atom=R. | |
| 212 | pack_value(int(Nr),R) :- !, R=Nr. | |
| 213 | pack_value(closure(P,T,Body),R) :- pack_closure(P,T,Body,PC),!, R=PC. | |
| 214 | pack_value(rec(Fields),PFields) :- !, pack_fields(Fields,PFields). | |
| 215 | pack_value(freeval(ID,Case,Val),freeval(ID,Case,PVal)) :- !, pack_value(Val,PVal). | |
| 216 | pack_value(term(floating(Nr)),R) :- !, R=Nr. | |
| 217 | %pack_value(V,_) :- V \= [], V \= pred_true, V \= pred_false, V \= string(_), functor(V,F,N), write(cannot_pack(F,N)),nl,fail. | |
| 218 | pack_value(V,V). | |
| 219 | ||
| 220 | /* not worth it : compute avl_domain and apply pack_value in one go: | |
| 221 | avl_packed_domain(empty, Domain, Domain). | |
| 222 | avl_packed_domain(node(Key,_,_,L,R), Domain0, Domain) :- | |
| 223 | pack_value(Key,PKey), avl_packed_domain(L, Domain0, [PKey|Domain1]), | |
| 224 | avl_packed_domain(R, Domain1, Domain). | |
| 225 | */ | |
| 226 | ||
| 227 | :- use_module(bsyntaxtree,[transform_bexpr/3]). | |
| 228 | ||
| 229 | pack_closure(P,T,Body,R) :- is_interval_closure(P,T,Body,Low,Up),!, | |
| 230 | %print(pack_interval(Low,Up,B)),nl, | |
| 231 | R='$interval'(Low,Up). | |
| 232 | %pack_value(closure(P,T,B),R) :- is_cartesian_product_closure(CPA,A1,A2),!, | |
| 233 | % R='$cartesian_product'(PA1,PA2), | |
| 234 | % pack_value(A1,PA1), pack_value(A2,PA2). | |
| 235 | pack_closure(P,T,Body,R) :- | |
| 236 | (preference(use_state_packing,full) -> true ; preference(force_state_packing_for_closures,true)), | |
| 237 | R = '$closure'(P,T,PBody), | |
| 238 | %add_message(state_packing,'Packing closure: ',Body,Body), | |
| 239 | transform_bexpr(state_packing:pack_bexpr,Body,PBody). | |
| 240 | ||
| 241 | pack_fields([],[]). | |
| 242 | pack_fields([field(F,H)|T],'$field'(F,PH,PT)) :- pack_value(H,PH), pack_fields(T,PT). | |
| 243 | ||
| 244 | l_pack_value([],[]). | |
| 245 | l_pack_value([H|T],[PH|PT]) :- pack_value(H,PH), l_pack_value(T,PT). | |
| 246 | ||
| 247 | pack_bexpr(b(value(Val),T,I),b(value(PVal),T,I)) :- | |
| 248 | pack_value(Val,PVal). | |
| 249 | ||
| 250 | % -------------------- | |
| 251 | ||
| 252 | ||
| 253 | pack_avl_set(Avl,R) :- preference(use_state_packing,Pref), pack_avl_set_aux(Avl,Pref,R). | |
| 254 | ||
| 255 | pack_avl_set_aux(A,full,R) :- | |
| 256 | avl_top_val2(A,(_,Bool)), (Bool=pred_false ; Bool=pred_true), % we have a relation/function to BOOL | |
| 257 | !, | |
| 258 | pack_relation(A,DomSkel,RangeVals), | |
| 259 | compress_bv(RangeVals,BVVal,BVLen,[]), !, % Store function/relation skeleton separately and compress bv | |
| 260 | %print(rel_packed(Val,Len,Rest)),nl, | |
| 261 | R='$stored_avl_rel_bv_packed'(ID1,BVVal), | |
| 262 | store_value((BVLen,DomSkel),ID1). | |
| 263 | pack_avl_set_aux(A,full,R) :- %R\==[], | |
| 264 | avl_domain(A,AD), | |
| 265 | (pack_fd_set(AD,Type,PackedInteger) | |
| 266 | -> !, | |
| 267 | R = '$avl_bv'(PackedInteger,Type) % avl bit vector | |
| 268 | ; AD = [_,_|_], % at least two elements | |
| 269 | !, | |
| 270 | l_pack_value(AD,ADL), | |
| 271 | R='$stored_avl_exp'(ID), | |
| 272 | store_value(ADL,ID) | |
| 273 | ). | |
| 274 | pack_avl_set_aux(A,_Pref,R) :- A = node(fd(_,Type),_,_,_,_), | |
| 275 | % maybe we want to disable this for Pref=false ? TODO: benchmark (for nota.mch pack_fd_set seems slightly better) | |
| 276 | fd_type_can_be_packed_to_bv(Type), | |
| 277 | avl_domain(A,AD), | |
| 278 | pack_fd_set(AD,Type,PackedInteger),!, | |
| 279 | R = '$avl_bv'(PackedInteger,Type). | |
| 280 | pack_avl_set_aux(A,Pref,R) :- !, | |
| 281 | %avl_height(A,Height), format('Packing avl with height ~w (pref: ~w)~n',[Height,Pref]), | |
| 282 | pack_avl(A,PA), | |
| 283 | (try_store_avl(Pref,A,PA) | |
| 284 | -> R='$stored_avl_packed'(ID), store_value(PA,ID) | |
| 285 | ; PA = packed_leaf(AP) -> R='$avl_singleton'(AP) | |
| 286 | ; R='$avl_packed'(PA) | |
| 287 | ). | |
| 288 | ||
| 289 | :- use_module(probsrc(avl_tools),[avl_height_less_than/2]). | |
| 290 | try_store_avl(true,_A,PA) :- | |
| 291 | %\+ avl_height_less_than(A,5), % if the set is large enough, store it separately; TODO: provide preference? | |
| 292 | store_packed_avl(PA). | |
| 293 | ||
| 294 | store_packed_avl(packed_leaf(Val)) :- | |
| 295 | compound(Val). % no use storing simple singleton sets; maybe singleton sets in general? | |
| 296 | store_packed_avl(packed_node(_,_,_,_)). | |
| 297 | ||
| 298 | %avl_top_val(node(Val,_,_,_,_),Val). | |
| 299 | avl_top_val2(node(Val,_,_,L,R),Val) :- L \= empty, R\=empty. | |
| 300 | ||
| 301 | unpack_avl_expanded(AD,R) :- | |
| 302 | l_unpack_value(AD,ADT), | |
| 303 | custom_explicit_sets:ord_list_to_avlset_direct(ADT,R,unpack_value). | |
| 304 | ||
| 305 | % try to pack an AVL tree in-place without expanding to list first: | |
| 306 | pack_avl(empty, empty). | |
| 307 | pack_avl(node(Val,_,0,empty,empty), R) :- !, | |
| 308 | R= packed_leaf(PackedVal), | |
| 309 | pack_value(Val,PackedVal). | |
| 310 | pack_avl(node(Val,true,B,L0,R0), packed_node(PackedVal,B,L1,R1)) :- | |
| 311 | pack_value(Val,PackedVal), | |
| 312 | pack_avl(L0, L1), % TODO: we could store L, R separately | |
| 313 | pack_avl(R0, R1). | |
| 314 | ||
| 315 | unpack_avl(empty,empty). | |
| 316 | unpack_avl(packed_leaf(PackedVal), node(Val,true,0,empty,empty)) :- unpack_value(PackedVal,Val). | |
| 317 | unpack_avl(packed_node(PackedVal,B,L0,R0), node(Val,true,B,L1,R1)) :- | |
| 318 | unpack_value(PackedVal,Val), | |
| 319 | unpack_avl(L0, L1), | |
| 320 | unpack_avl(R0, R1). | |
| 321 | ||
| 322 | % pack relation: skeleton of relation and range values separately | |
| 323 | pack_relation(AVL,DomSkeleton,RangeValueList) :- pack_relation(AVL,DomSkeleton,RangeValueList,[]). | |
| 324 | pack_relation(empty, empty) --> []. | |
| 325 | pack_relation(node((DomVal,RanVal),true,B,L0,R0), packed_rel_node(PackedVal,B,L1,R1)) --> | |
| 326 | {pack_value(DomVal,PackedVal), | |
| 327 | RanVal=RanPackedVal %pack_value(RanVal,RanPackedVal) | |
| 328 | }, % enable compress_bv | |
| 329 | [RanPackedVal], | |
| 330 | pack_relation(L0, L1), | |
| 331 | pack_relation(R0, R1). | |
| 332 | ||
| 333 | unpack_relation(DomSkeleton,RangeValueList,AVL) :- unpack_relation(DomSkeleton,AVL,RangeValueList,[]). | |
| 334 | unpack_relation(empty, empty) --> []. | |
| 335 | unpack_relation(packed_rel_node(PackedVal,B,L1,R1), node((DomVal,RanVal),true,B,L0,R0)) --> | |
| 336 | {unpack_value(PackedVal,DomVal)}, | |
| 337 | [RanPackedVal], | |
| 338 | {RanPackedVal=RanVal}, %{unpack_value(RanPackedVal,RanVal)}, | |
| 339 | unpack_relation(L1, L0), | |
| 340 | unpack_relation(R1, R0). | |
| 341 | ||
| 342 | % avl_height but for packed AVLs | |
| 343 | packed_avl_height(AVL, Height) :- | |
| 344 | packed_avl_height(AVL, 0, Height). | |
| 345 | ||
| 346 | packed_avl_height(empty, H, H). | |
| 347 | packed_avl_height(packed_leaf(_), H0, H1) :- H1 is H0+1. | |
| 348 | packed_avl_height(packed_node(_,B,L,R), H0, H) :- | |
| 349 | H1 is H0+1, | |
| 350 | ( B >= 0 -> packed_avl_height(R, H1, H) | |
| 351 | ; packed_avl_height(L, H1, H) | |
| 352 | ). | |
| 353 | packed_avl_height(packed_rel_node(_,_,B,L,R), H0, H) :- | |
| 354 | H1 is H0+1, | |
| 355 | ( B >= 0 -> packed_avl_height(R, H1, H) | |
| 356 | ; packed_avl_height(L, H1, H) | |
| 357 | ). | |
| 358 | ||
| 359 | % -------------------- | |
| 360 | ||
| 361 | % TO DO or [(fd,fd) as bit-vectors if <xx bits | |
| 362 | ||
| 363 | % Pack set of FD values as bit-vector representation | |
| 364 | pack_fd_set([fd(X,Type)|T],Type,Result) :- | |
| 365 | fd_type_can_be_packed_to_bv(Type), | |
| 366 | Acc is 1<<X, | |
| 367 | pack_fd_set_aux(T,Acc,Result). | |
| 368 | ||
| 369 | :- use_module(tools_platform, [max_tagged_pow2/1]). | |
| 370 | fd_type_can_be_packed_to_bv(Type) :- | |
| 371 | b_get_fd_type_bounds(Type,1,UpBound), integer(UpBound). | |
| 372 | % max_tagged_pow2(MaxBound),UpBound < MaxBound | |
| 373 | % we no longer check that we can fit the bitvector in a single integer | |
| 374 | % experiments seem to show that using multi-precision integers results in better compression | |
| 375 | % and better performance (with and without operation_reuse) | |
| 376 | % see public_examples/B/PerformanceTests/Compression/LargeDefSet.mch and LargeDefSet2.mch | |
| 377 | ||
| 378 | pack_fd_set_aux([],A,A). | |
| 379 | pack_fd_set_aux([fd(X,_)|T],Acc,Res) :- | |
| 380 | NewAcc is Acc \/ (1<<X), | |
| 381 | pack_fd_set_aux(T,NewAcc,Res). | |
| 382 | ||
| 383 | % unpack a bit-vector set representation | |
| 384 | unpack_fd_set(PackedInteger,Type,Value) :- | |
| 385 | unpack_fd_set_aux(PackedInteger,0,Type,ResList), %print(unpacked(PackedInteger,ResList)),nl, | |
| 386 | custom_explicit_sets:ord_list_to_avlset_direct(ResList,Value,unpack_fd_set). | |
| 387 | ||
| 388 | unpack_fd_set_aux(0,_,_,Res) :- !, Res=[]. | |
| 389 | unpack_fd_set_aux(Nr,X,Type,Res) :- | |
| 390 | (Nr mod 2 =:= 1 -> Res = [fd(X,Type)-true|T] ; Res=T), | |
| 391 | X1 is X+1, Nr1 is (Nr>>1), | |
| 392 | unpack_fd_set_aux(Nr1,X1,Type,T). | |
| 393 | ||
| 394 | % first rough attempt at packing CSP expressions | |
| 395 | pack_csp_expression(esharing(Set,B,C,Span),'$esharing'(PSet,PB,PC,PSpan)) :- !, | |
| 396 | pack_csp_expression(Set,PSet), pack_csp_expression(B,PB), | |
| 397 | pack_csp_expression(C,PC), pack_csp_expression(Span,PSpan). | |
| 398 | pack_csp_expression('|||'(A,B,Span),'|||'(PA,PB,PSpan)) :- !, | |
| 399 | pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(Span,PSpan). | |
| 400 | %pack_csp_expression('&'(A,B),'&'(PA,PB)) :- !, | |
| 401 | % pack_csp_expression(A,PA), pack_csp_expression(B,PB). | |
| 402 | pack_csp_expression('[]'(A,B,Span),'[]'(PA,PB,PSpan)) :- !, | |
| 403 | pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(Span,PSpan). | |
| 404 | pack_csp_expression(eaParallel(C,A,D,B,Span),eaParallel(PC,PA,PD,PB,PSpan)) :- !, | |
| 405 | pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(C,PC), | |
| 406 | pack_csp_expression(D,PD), pack_csp_expression(Span,PSpan). | |
| 407 | %pack_csp_expression(prefix(C,A,D,B,Span),prefix(PC,PA,PD,PB,PSpan)) :- !, | |
| 408 | % pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(C,PC), | |
| 409 | % pack_csp_expression(D,PD), pack_csp_expression(Span,PSpan). | |
| 410 | %pack_csp_expression(ifte(C,A,D,B,Span,S3),ifte(PC,PA,PD,PB,PSpan,S3)) :- !, | |
| 411 | % pack_csp_expression(A,PA), pack_csp_expression(B,PB), pack_csp_expression(C,PC), | |
| 412 | % pack_csp_expression(D,PD), pack_csp_expression(Span,PSpan). | |
| 413 | %pack_csp_expression(V,'$stored_csp'(ID)) :- store_value(V,ID). | |
| 414 | pack_csp_expression(V,ID) :- store_value(V,ID). | |
| 415 | ||
| 416 | unpack_csp_expression('$esharing'(PSet,PB,PC,PSpan),esharing(Set,B,C,Span)) :- !, | |
| 417 | unpack_csp_expression(PSet,Set), unpack_csp_expression(PB,B), | |
| 418 | unpack_csp_expression(PC,C), unpack_csp_expression(PSpan,Span). | |
| 419 | unpack_csp_expression('|||'(A,B,Span),'|||'(PA,PB,PSpan)) :- !, | |
| 420 | unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(Span,PSpan). | |
| 421 | %unpack_csp_expression('&'(A,B),'&'(PA,PB)) :- !, | |
| 422 | % unpack_csp_expression(A,PA), unpack_csp_expression(B,PB). | |
| 423 | unpack_csp_expression('[]'(A,B,Span),'[]'(PA,PB,PSpan)) :- !, | |
| 424 | unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(Span,PSpan). | |
| 425 | unpack_csp_expression(eaParallel(C,A,D,B,Span),eaParallel(PC,PA,PD,PB,PSpan)) :- !, | |
| 426 | unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(C,PC), | |
| 427 | unpack_csp_expression(D,PD), unpack_csp_expression(Span,PSpan). | |
| 428 | %unpack_csp_expression(prefix(C,A,D,B,Span),prefix(PC,PA,PD,PB,PSpan)) :- !, | |
| 429 | % unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(C,PC), | |
| 430 | % unpack_csp_expression(D,PD), unpack_csp_expression(Span,PSpan). | |
| 431 | %unpack_csp_expression(ifte(C,A,D,B,Span,S3),ifte(PC,PA,PD,PB,PSpan,S3)) :- !, | |
| 432 | % unpack_csp_expression(A,PA), unpack_csp_expression(B,PB), unpack_csp_expression(C,PC), | |
| 433 | % unpack_csp_expression(D,PD), unpack_csp_expression(Span,PSpan). | |
| 434 | %unpack_csp_expression('$stored_csp'(ID),V) :- !, stored_value(ID,V). | |
| 435 | unpack_csp_expression(ID,V) :- !, stored_value(ID,V). | |
| 436 | unpack_csp_expression(V,V). | |
| 437 | ||
| 438 | %unpack_value(Val,UPVal) :- unpack_value(Val,UPVal,empty,_). | |
| 439 | ||
| 440 | unpack_value(V,R) :- var(V),!, | |
| 441 | add_internal_error('Illegal variable value: ', unpack_value(V,R)), R=V. | |
| 442 | unpack_value('$avl_packed'(AP),R) :- !, R=avl_set(A),unpack_avl(AP,A). | |
| 443 | unpack_value('$avl_singleton'(AP),R) :- !, R=avl_set(node(A,true,0,empty,empty)),unpack_value(AP,A). | |
| 444 | unpack_value('$avl_exp'(AD),R) :- !, unpack_avl_expanded(AD,R). | |
| 445 | unpack_value('$stored_avl_packed'(ID),R) :- !, | |
| 446 | (stored_value(ID,Val) -> R = avl_set(A), unpack_avl(Val,A) | |
| 447 | ; add_internal_error('No stored AVL: ',ID),fail). | |
| 448 | unpack_value('$stored_avl_exp'(ID),R) :- !, | |
| 449 | (stored_value(ID,Val) -> unpack_avl_expanded(Val,R) | |
| 450 | ; add_internal_error('No stored AVL: ',ID),fail). | |
| 451 | unpack_value('$stored_avl_rel_bv_packed'(ID1,Val),R) :- !, | |
| 452 | (stored_value(ID1,(Len,DomVal)) | |
| 453 | -> R = avl_set(A), | |
| 454 | uncompress_bv(Val,Len,[],RanVals), | |
| 455 | unpack_relation(DomVal,RanVals,A) | |
| 456 | ; add_internal_error('No stored length and Domain AVL / Range Value: ',ID1),fail). | |
| 457 | unpack_value('$avl_bv'(PackedInteger,Type),R) :- !, unpack_fd_set(PackedInteger,Type,R). | |
| 458 | /* comment in and re-add DCG to try and re-construct sharing; does seem to increase memory usage for vital_gradient_values | |
| 459 | unpack_value('$stored_avl'(ID),R,InEnv,OutEnv) :- !, | |
| 460 | (avl_fetch(ID,InEnv,ER) %(expanded(ID,ER),InEnv) | |
| 461 | -> R = ER, OutEnv=InEnv % reuse the already expanded value: will also decrease memory consumption due to sharing | |
| 462 | ; stored_value(ID,Val), | |
| 463 | avl_store(ID,InEnv,R,InEnv2), % OutEnv=[expanded(ID,R)|OutEnv2], % note: ID cannot occur inside Val | |
| 464 | unpack_avl_expanded(Val,R,InEnv2,OutEnv)). | |
| 465 | */ | |
| 466 | %unpack_value('$cartesian_product'(A,B),R) :- unpack_value(A,PA), unpack_value(B,PB), | |
| 467 | % construct_cartesian_product_closure(PA,PB,R). | |
| 468 | unpack_value((A,B),(PA,PB)) :- !, unpack_value(A,PA), unpack_value(B,PB). | |
| 469 | unpack_value('$interval'(A,B),R) :- !, construct_interval_closure(A,B,R). | |
| 470 | unpack_value('$closure'(P,T,PB),closure(P,T,B)) :- !, transform_bexpr(state_packing:unpack_bexpr,PB,B). | |
| 471 | unpack_value('$field'(Field,PH,PT),rec(F)) :- !, | |
| 472 | unpack_fields('$field'(Field,PH,PT),F). | |
| 473 | unpack_value(freeval(ID,Case,PVal),freeval(ID,Case,Val)) :- !, unpack_value(PVal,Val). | |
| 474 | unpack_value(Nr,R) :- integer(Nr),!, R=int(Nr). | |
| 475 | unpack_value(Nr,R) :- float(Nr),!, R=term(floating(Nr)). | |
| 476 | unpack_value(V,UPV) :- unpack_basic_fd_value(V,FD),!,UPV=FD. | |
| 477 | unpack_value(V,V). | |
| 478 | ||
| 479 | unpack_fields([],[]). | |
| 480 | unpack_fields('$field'(F,PH,PT),[field(F,H)|T]) :- unpack_value(PH,H), unpack_fields(PT,T). | |
| 481 | ||
| 482 | l_unpack_value([],[]). | |
| 483 | l_unpack_value([H|T],[PH-true|PT]) :- unpack_value(H,PH), l_unpack_value(T,PT). | |
| 484 | ||
| 485 | unpack_bexpr(b(value(PVal),T,I),b(value(Val),T,I)) :- | |
| 486 | unpack_value(PVal,Val). | |
| 487 | ||
| 488 | % ------------------------- | |
| 489 | ||
| 490 | % a version of pack_state which makes use of a previously packed state and a ordered list of Unchanged variables | |
| 491 | % incremental_pack_state(State,PrevPackedState,UnchangedVariables,PackedState) | |
| 492 | % The idea is to re-use the packed values from the previous state if possible | |
| 493 | ||
| 494 | % the packed state needs to be processed by get_packed_b_state_with_uncompressed_lists first | |
| 495 | ||
| 496 | % Note: bind_skeleton does not need to be stored as these clauses only apply when previous state of same type exists | |
| 497 | incremental_pack_state(const_and_vars(ID,T),const_and_vars(ID,PrevCT),Unchanged,'$cst_vars'(ID,PCT)) :- !, | |
| 498 | uncompress_list(PrevCT,PrevT), | |
| 499 | incr_pack_bind_list(T,PrevT,Unchanged,PT), | |
| 500 | compress_list(PT,PCT). | |
| 501 | incremental_pack_state([bind(V,Val)|T],[bind(V,PrevV)|PrevCT],Unchanged,'$bind_lst'(PV,PCT)) :- !, | |
| 502 | uncompress_list(PrevCT,PrevT), | |
| 503 | incremental_pack_value(Val,V,PrevV,Unchanged,PV,U2), | |
| 504 | incr_pack_bind_list(T,PrevT,U2,PT), | |
| 505 | compress_list(PT,PCT). | |
| 506 | incremental_pack_state(State,Prev,UC,PackedState) :- | |
| 507 | tools_printing:print_term_summary(non_incremental_pack_state(State,Prev,UC,PackedState)),nl, | |
| 508 | pack_state(State,PackedState). | |
| 509 | ||
| 510 | %ord_delete_existing_element(List,El,ResList) :- % ord_del_element also succeeds if El is not in the list ! | |
| 511 | % ord_intersection([El],List,[El],ResList). | |
| 512 | %:- use_module(library(ordsets),[ord_intersection/4]). | |
| 513 | ||
| 514 | incremental_pack_value(_,Var,PrevPackVal,[Var|U2],PackedValue,U2) :- % copy previously packed value | |
| 515 | !, PackedValue=PrevPackVal. | |
| 516 | incremental_pack_value(Val,_Var,_Prev,Unchanged,PackedValue,Unchanged) :- | |
| 517 | pack_value(Val,PackedValue). | |
| 518 | ||
| 519 | %not_packed(pred_false). | |
| 520 | %not_packed(pred_true). | |
| 521 | %not_packed(string(_)). | |
| 522 | ||
| 523 | incr_pack_bind_list([],_,Unchanged,[]) :- | |
| 524 | (Unchanged=[] -> true ; add_internal_error('Did not encounter these unchanged vars:',Unchanged)). | |
| 525 | incr_pack_bind_list([bind(V,Val)|T],[bind(V,PrevV)|PrevT],Unchanged,[PackedValue|PT]) :- | |
| 526 | incremental_pack_value(Val,V,PrevV,Unchanged,PackedValue,U2), | |
| 527 | incr_pack_bind_list(T,PrevT,U2,PT). | |
| 528 | ||
| 529 | % ------------------------- | |
| 530 | ||
| 531 | :- use_module(library(terms),[term_hash/2]). | |
| 532 | :- use_module(debug,[debug_format/3]). | |
| 533 | :- dynamic pack_basic_fd_value4/4, unpack_basic_fd_value/2. | |
| 534 | % associate precompiled atoms with all enumerated & deferred set elements; TO DO: only do for "smaller" SETS | |
| 535 | precompile_state_packing :- | |
| 536 | retractall(pack_basic_fd_value4(_,_,_,_)), | |
| 537 | retractall(unpack_basic_fd_value(_,_)), | |
| 538 | ? | b_global_set(T), |
| 539 | b_fd_card(T,Card), | |
| 540 | (integer(Card), Card < 1000 -> true | |
| 541 | ; debug_format(19,'Not precompiling state packing for ~w (size ~w)~n',[T,Card]),fail), | |
| 542 | ? | enum_global_type_limited(fd(Nr,T),_), % limits infinite deferred sets, which we don't precompile anyway |
| 543 | gen_fd_atom(Nr,T,NewAtom), | |
| 544 | %debug:debug_println(9,pack(T,Nr,NewAtom)), | |
| 545 | term_hash((T,Nr),Hash), % we could number the Types and use something like TypeNr*MaxSize + Nr | |
| 546 | assertz(pack_basic_fd_value4(Hash,T,Nr,NewAtom)), | |
| 547 | assertz(unpack_basic_fd_value(NewAtom,fd(Nr,T))),fail. | |
| 548 | precompile_state_packing. | |
| 549 | ||
| 550 | gen_fd_atom(Nr,T,NewAtom) :- | |
| 551 | atom_codes(T,TC), | |
| 552 | number_codes(Nr,NrC), | |
| 553 | append(TC,NrC,TNrC), | |
| 554 | atom_codes(NewAtom,[36,102,100,95|TNrC]). % generates '$fd_TNr atom | |
| 555 | ||
| 556 | % use term_hash in case we have very large enumerated/deferred sets | |
| 557 | pack_basic_fd_value(T,Nr,NewAtom) :- term_hash((T,Nr),Hash), | |
| 558 | pack_basic_fd_value4(Hash,T,Nr,NewAtom). | |
| 559 | ||
| 560 | % ------------------------ | |
| 561 | ||
| 562 | :- dynamic stored_value/2, stored_value_hash_to_id/2. | |
| 563 | ||
| 564 | reset_stored_values :- | |
| 565 | %(retract(stored_value(ID,_)), print(remove_stored_value(ID)),nl,fail ; true), | |
| 566 | retractall(bind_skeleton(_,_)), | |
| 567 | retractall(stored_value(_,_)), | |
| 568 | retractall(stored_value_hash_to_id(_,_)), | |
| 569 | bb_put(next_value_id,0), | |
| 570 | recompute_state_packing_preference. | |
| 571 | ||
| 572 | % the next is also called by auto_set_b_operation_cache after specification_initialised event | |
| 573 | % i.e., it will also work if SET_PREF_COMPRESSION is used in loaded B machine | |
| 574 | recompute_state_packing_preference :- | |
| 575 | get_preference(try_use_state_packing,X), | |
| 576 | compute_state_pack_setting(X,Setting), | |
| 577 | set_preference(use_state_packing,Setting). | |
| 578 | ||
| 579 | compute_state_pack_setting(auto,Setting) :- !, | |
| 580 | (state_packing_definitely_useful | |
| 581 | -> Setting=true | |
| 582 | ; Setting = false), | |
| 583 | debug_format(19,'Setting COMPRESSION to ~w~n',[Setting]). | |
| 584 | compute_state_pack_setting(X,X). | |
| 585 | ||
| 586 | state_packing_definitely_useful :- | |
| 587 | get_preference(operation_reuse_setting,X), X \= false. % for operation reuse COMPRESSION is often essential | |
| 588 | ||
| 589 | ||
| 590 | :- use_module(probsrc(hashing),[sdbm_term_hash/2]). | |
| 591 | store_value(Value,ID) :- | |
| 592 | sdbm_term_hash(Value,Hash), %[range(smallint),algorithm(sdbm), depth(infinite),if_var(ignore)],Hash), | |
| 593 | % instead of infinite we could use a lower bound, collisions are taken care of below | |
| 594 | store_value_aux(Value,Hash,ID). | |
| 595 | ||
| 596 | store_value_aux(Value,Hash,ID) :- | |
| 597 | stored_value_hash_to_id(Hash,ID), | |
| 598 | stored_value(ID,Stored_Value), | |
| 599 | Value=Stored_Value, % check that we have the exact value, could be expensive but collisions are possible | |
| 600 | !. % we have already stored the value | |
| 601 | store_value_aux(Value,Hash,ID) :- | |
| 602 | (bb_get(next_value_id,NID) -> true ; NID=0), | |
| 603 | NID1 is NID+1, | |
| 604 | bb_put(next_value_id,NID1), | |
| 605 | assertz(stored_value(NID,Value)), | |
| 606 | assertz(stored_value_hash_to_id(Hash,NID)), | |
| 607 | ID=NID. | |
| 608 | ||
| 609 | :- use_module(tools_printing, [print_dynamic_pred/4]). | |
| 610 | % state_packing:print_stored_values(user_output) | |
| 611 | print_stored_values(Stream) :- % for saving state_space to file | |
| 612 | print_dynamic_pred(Stream,state_packing,bind_skeleton,2), | |
| 613 | print_dynamic_pred(Stream,state_packing,stored_value,2), | |
| 614 | print_dynamic_pred(Stream,state_packing,stored_value_hash_to_id,2), | |
| 615 | (bb_get(next_value_id,NID) -> true ; NID=0), format(Stream,'~n:- dynamic next_value_id/1.~nnext_value_id(~w).~n~n',[NID]). | |
| 616 | ||
| 617 | % when loading state space from file | |
| 618 | set_next_value_id(ID) :- bb_put(next_value_id,ID). | |
| 619 | ||
| 620 | retract_stored_values_with_statistics :- | |
| 621 | retract_with_statistics(state_packing,[stored_value(_,_), | |
| 622 | stored_value_hash_to_id(_,_)]), | |
| 623 | reset_stored_values. | |
| 624 | ||
| 625 | % portray state packing infos | |
| 626 | print_state_packing_profile :- | |
| 627 | (bb_get(next_value_id,Nr) -> true ; Nr=0), | |
| 628 | format('Stored ~w AVL sets for state compression~n',[Nr]), | |
| 629 | (debug_mode(on) -> portray_stored_values ; true). | |
| 630 | ||
| 631 | portray_stored_values :- bind_skeleton(Kind,Skel), | |
| 632 | format('Binding skeleton for ~w:~n ~w~n',[Kind,Skel]), | |
| 633 | fail. | |
| 634 | portray_stored_values :- | |
| 635 | stored_value(NID,Value), functor(Value,F,N), | |
| 636 | (packed_avl_height(Value,Size) -> true ; length(Value,Size) -> true ; Size='?'), | |
| 637 | format('Value ~w : ~w/~w : size: ~w~n',[NID,F,N,Size]), | |
| 638 | fail. | |
| 639 | portray_stored_values. | |
| 640 | ||
| 641 | % ------------------------------------- | |
| 642 | ||
| 643 | % utility to translate boolean variables into bit-vector integers (not used yet; degrades performance) | |
| 644 | ||
| 645 | :- use_module(self_check). | |
| 646 | :- 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)). | |
| 647 | :- 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)). | |
| 648 | :- 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)). | |
| 649 | ||
| 650 | % compress successive boolean values (at least 2) | |
| 651 | compress_bv([P|T],Val,Len,Rest) :- get_bool_bv(P,Acc), compress_bv2(T,Acc,Val,Len,Rest). | |
| 652 | get_bool_bv(pred_true,1). | |
| 653 | get_bool_bv(pred_false,0). | |
| 654 | compress_bv2([P|T],Acc,Val,Len,Rest) :- get_bool_bv(P,BoolVal),!, | |
| 655 | Acc2 is Acc + BoolVal*2, % BoolVal+(Acc << 1), | |
| 656 | compress_bv3(T,Acc2,Val,2,Len,Rest). | |
| 657 | compress_bv3([P|T],Acc,Val,AccLen,Len,Rest) :- %get_bool_bv(P,BoolVal),!, | |
| 658 | (P=pred_true -> Acc2 is Acc + (1 << AccLen) ; P=pred_false -> Acc2 = Acc), !, | |
| 659 | %Acc2 is Acc + BoolVal*(2^AccLen), | |
| 660 | AccLen2 is AccLen+1, compress_bv3(T,Acc2,Val,AccLen2,Len,Rest). | |
| 661 | compress_bv3(Rest,Acc,Acc,AccLen,AccLen,Rest). % we have a non BOOL value | |
| 662 | ||
| 663 | % uncompress bitvector Val of Len bits into list of pred_true, pred_false elements | |
| 664 | uncompress_bv(_,Len,Rest,Res) :- Len =< 0, !, Res=Rest. | |
| 665 | uncompress_bv(Val,Len,Rest,[BV|TRes]) :- | |
| 666 | (Val mod 2 =:= 1 -> BV = pred_true ; BV=pred_false), | |
| 667 | Val2 is Val >> 1, Len1 is Len-1, | |
| 668 | uncompress_bv(Val2,Len1,Rest,TRes). | |
| 669 | ||
| 670 | % ------------------------------------- | |
| 671 | ||
| 672 | % a utility to get a state as List or const_and_vars(ID,List) with list of packed values with bind/2 terms | |
| 673 | ||
| 674 | get_packed_b_state_with_uncompressed_lists(csp_and_b(_,B),Res) :- !, | |
| 675 | get_packed_b_state_with_uncompressed_lists(B,Res). | |
| 676 | get_packed_b_state_with_uncompressed_lists(const_and_vars(ID,List),const_and_vars(ID,Res)) :- | |
| 677 | get_packed_b_state_with_uncompressed_lists(List,Res). | |
| 678 | get_packed_b_state_with_uncompressed_lists('$cst_vars'(ID,CS),const_and_vars(ID,Res)) :- | |
| 679 | uncompress_list(CS,List), | |
| 680 | get_bind_skeleton(const_and_vars,Skel), | |
| 681 | gen_packed_bind_list(List,Skel,Res). | |
| 682 | get_packed_b_state_with_uncompressed_lists('$bind_lst'(Val,CT),[bind(Var1,Val)|Res]) :- uncompress_list(CT,List), | |
| 683 | get_bind_skeleton(list,[Var1|Skel]), | |
| 684 | gen_packed_bind_list(List,Skel,Res). | |
| 685 | ||
| 686 | ||
| 687 | gen_packed_bind_list([],[],[]). | |
| 688 | gen_packed_bind_list([Val|T],[Var|VT],R) :- R=[bind(Var,Val)|UPT], | |
| 689 | gen_packed_bind_list(T,VT,UPT). | |
| 690 | ||
| 691 | ||
| 692 | % ------------------------------------- | |
| 693 | ||
| 694 | ||
| 695 |