| 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 | | |
| 6 | | :- module(bvisual2,[ reset_bvisual/0 |
| 7 | | , bv_get_top_level/1 |
| 8 | | , bv_expand_formula/3 |
| 9 | | , bv_get_values/3 |
| 10 | | , bv_get_values/2 |
| 11 | | , bv_insert_formula/3 |
| 12 | | , bv_include_variables/0 |
| 13 | | , bv_get_value_unlimited/3 |
| 14 | | , bv_is_explanation_node/1 |
| 15 | | , bv_print_to_file/3 |
| 16 | | , bv_write_all_variables_and_constants/2 |
| 17 | | , set_bvisual2_translation_mode/1 |
| 18 | | , bv_get_top_level_formula/4 |
| 19 | | , bv_get_top_level_formula/5 |
| 20 | | , bv_value_to_atom/2 |
| 21 | | , bv_show_formula_origin/2 |
| 22 | | , bv_formula_description/2 |
| 23 | | , bv_is_typed_formula/1 |
| 24 | | , bv_is_typed_predicate/1 |
| 25 | | , bv_is_typed_identifier/2 |
| 26 | | , bv_get_stored_formula_expr/2 |
| 27 | | , tcltk_register_new_user_formula/1 |
| 28 | | , html_debug_operation_for_stateid/4 |
| 29 | | ]). |
| 30 | | |
| 31 | | :- use_module(library(lists)). |
| 32 | | :- use_module(library(codesio)). |
| 33 | | %:- use_module(library(timeout)). |
| 34 | | |
| 35 | | :- use_module(bmachine, [ b_machine_has_constants_or_properties/0 |
| 36 | | , b_get_machine_variables/1 |
| 37 | | , b_get_machine_constants/1 |
| 38 | | , b_get_machine_operation/4 |
| 39 | | , b_get_properties_from_machine/1 |
| 40 | | , b_get_invariant_from_machine/1 |
| 41 | | , b_get_static_assertions_from_machine/1 |
| 42 | | , b_get_assertions_from_main_machine/2 |
| 43 | | , b_get_dynamic_assertions_from_machine/1 |
| 44 | | , b_get_assertion_count/3 |
| 45 | | , b_get_operation_variant/3 |
| 46 | | ]). |
| 47 | | :- use_module(specfile, [ state_corresponds_to_initialised_b_machine/2 |
| 48 | | , state_corresponds_to_set_up_constants/2 |
| 49 | | ]). |
| 50 | | :- use_module(state_space, [ visited_expression/2 |
| 51 | | , current_state_id/1 |
| 52 | | , invariant_not_yet_checked/1 |
| 53 | | , invariant_violated/1 |
| 54 | | , transition/3 |
| 55 | | ]). |
| 56 | | :- use_module(store, [ empty_state/1 |
| 57 | | , normalise_store/2 |
| 58 | | ]). |
| 59 | | :- use_module(b_interpreter, [ b_test_boolean_expression_wf/3 |
| 60 | | , b_not_test_boolean_expression_wf/3 |
| 61 | | , b_test_boolean_expression/4 |
| 62 | | , b_compute_expression_nowf/4 |
| 63 | | , set_up_typed_localstate/6 |
| 64 | | ]). |
| 65 | | :- use_module(translate, [ translate_subst_or_bexpr_in_mode/3 |
| 66 | | , translate_bexpression_to_codes/2 |
| 67 | | , translate_bvalue_for_expression_with_limit/4 |
| 68 | | , translate_bvalue_for_expression/3 |
| 69 | | , translate_bvalue_with_type_and_limit/4 |
| 70 | | , translate_bvalue/2 |
| 71 | | ]). |
| 72 | | :- use_module(bsyntaxtree, [ get_texpr_expr/2 |
| 73 | | , get_texpr_type/2 |
| 74 | | , get_texpr_info/2 |
| 75 | | , get_texpr_id/2 |
| 76 | | , is_texpr/1 |
| 77 | | , create_texpr/4 |
| 78 | | , safe_create_texpr/3 |
| 79 | | , syntaxtraversion/6 |
| 80 | | , conjunction_to_list/2 |
| 81 | | , conjunct_predicates/2 |
| 82 | | , create_exists/3, create_forall/3 |
| 83 | | %, find_identifier_uses/3 |
| 84 | | ]). |
| 85 | | :- use_module(b_ast_cleanup, [ clean_up_pred/3 |
| 86 | | ]). |
| 87 | | :- use_module(error_manager, [ get_all_errors_and_clear/1 |
| 88 | | , time_out_with_enum_warning_one_solution/3 |
| 89 | | ]). |
| 90 | | :- use_module(preferences, [ get_preference/2 |
| 91 | | , set_preference/2 |
| 92 | | ]). |
| 93 | | :- use_module(kernel_waitflags, [ init_wait_flags/1 |
| 94 | | , ground_wait_flags/1]). |
| 95 | | :- use_module(b_enumerate, [ b_tighter_enumerate_values/2 ]). |
| 96 | | :- use_module(tools_files, [ put_codes/2]). |
| 97 | | |
| 98 | | :- use_module(module_information,[module_info/2]). |
| 99 | | :- module_info(group,analysis). |
| 100 | | :- module_info(description,'This module contains functionality to analyse B expressions and predicates by evaluating and decomposing them into substructures.'). |
| 101 | | |
| 102 | | :- dynamic top_level_node/1, subnode/2, supernode/2. |
| 103 | | :- dynamic stored_formula/2, expanded/1, explanation_parent/1. |
| 104 | | :- dynamic id_counter/1. |
| 105 | | :- dynamic formula_cache/3. |
| 106 | | % We store the information whether a node can introduce new values as an (counter-)example |
| 107 | | % in example_node/1; the value is computed in explore_node/2. |
| 108 | | % For such nodes, the found examples are stored in local_state/3. |
| 109 | | :- dynamic example_node/1,local_state/3. |
| 110 | | |
| 111 | | |
| 112 | | bv_value_to_atom(p(P),R) :- !, % a predicate value |
| 113 | | (P=true -> R='TRUE' ; P=false -> R='FALSE' ; R=P). |
| 114 | | bv_value_to_atom(e(_),R) :- !, R='ERROR'. |
| 115 | | bv_value_to_atom(v(V),R) :- !, R=V. % a value, already pretty-printed !?? |
| 116 | | bv_value_to_atom(i,R) :- !, R='INACTIVE'. |
| 117 | | bv_value_to_atom(V,V). |
| 118 | | |
| 119 | | |
| 120 | | :- dynamic variables_should_be_included/0. |
| 121 | | bv_include_variables :- |
| 122 | | ( variables_should_be_included -> true |
| 123 | | ; otherwise -> assert(variables_should_be_included)). |
| 124 | | |
| 125 | | clear_bvisual :- |
| 126 | | retractall(top_level_node(_)), |
| 127 | | retractall(subnode(_,_)), % TO DO: do not delete user formulas for a simple re-load ?! |
| 128 | | retractall(supernode(_,_)), |
| 129 | | retractall(stored_formula(_,_)), |
| 130 | | retractall(expanded(_)), |
| 131 | | retractall(explanation_parent(_)), |
| 132 | | retractall(formula_cache(_,_,_)), |
| 133 | | retractall(example_node(_)), |
| 134 | | retractall(local_state(_,_,_)). |
| 135 | | % This predicate should be called after loading a new specification |
| 136 | | % and before using the other predicates below |
| 137 | | reset_bvisual :- |
| 138 | | clear_bvisual, |
| 139 | | register_top_level. |
| 140 | | |
| 141 | | :- public portray_bvisual/0. % debugging utility |
| 142 | | portray_bvisual :- %listing(top_level_node/1), listing(subnode/2), listing(stored_formula/2) |
| 143 | | top_level_node(N), bv_portray(N,1),fail. |
| 144 | | portray_bvisual. |
| 145 | | bv_portray(ID,Level) :- |
| 146 | | (stored_formula(ID,Form) -> functor(Form,F,_) ; F = '??'), |
| 147 | | (expanded(ID) -> E=expanded ; E = 'not_expanded'), |
| 148 | | indent(Level),format('~w -> ~w [~w]~n',[ID,F,E]), |
| 149 | | L1 is Level+1, |
| 150 | | subnode(ID,ID2), |
| 151 | | bv_portray(ID2,L1). |
| 152 | | indent(0) :- !. |
| 153 | | indent(N) :- N>0,!, N1 is N-1, print(' '), indent(N1). |
| 154 | | |
| 155 | | % returns the top-level nodes as a list of IDs |
| 156 | | bv_get_top_level(Tops) :- |
| 157 | | findall( Id, top_level_node(Id), Tops ). |
| 158 | | |
| 159 | | % bv_expand_formula(+FormulaID,-LabelAtom,-) |
| 160 | | % Input: Id |
| 161 | | % Output: Label of Formula, list of children |
| 162 | | bv_expand_formula(Id,Label,Children) :- |
| 163 | | expanded(Id),!, |
| 164 | | get_node_label(Id,Label), |
| 165 | | findall(C, subnode(Id,C), Children). |
| 166 | | bv_expand_formula(Id,Label,Children) :- |
| 167 | | get_node_label(Id,Label), |
| 168 | | explore_node(Id,Children). |
| 169 | | |
| 170 | | % bv_get_values in current state |
| 171 | | bv_get_values(Ids,Values) :- |
| 172 | | current_state_id(StateId), |
| 173 | | bv_get_values(Ids,StateId,Values). |
| 174 | | |
| 175 | | :- use_module(specfile,[prepare_state_for_specfile_trans/2]). |
| 176 | | |
| 177 | | % bv_get_values(+IdsOfFormulas,+CurrentStateID,-ValuesOfFormulas) |
| 178 | | bv_get_values(Ids,StateId,Values) :- |
| 179 | | visited_expression(StateId,State),!, |
| 180 | | prepare_state_for_specfile_trans(State,PreparedState), |
| 181 | | get_preference(time_out,Timeout), |
| 182 | | bv_get_values2(Ids,PreparedState,StateId,Timeout,Values). |
| 183 | | bv_get_values(Ids,_StateId,Values) :- |
| 184 | | % in case that the state ID cannot be resolved, we |
| 185 | | % return an error for each formula |
| 186 | | same_length(Ids,Values), |
| 187 | | same_value(Values,e('unkown state')). |
| 188 | | same_value([],_). |
| 189 | | same_value([V|Rest],V) :- same_value(Rest,V). |
| 190 | | |
| 191 | | |
| 192 | | % Insert a new formula |
| 193 | | % bv_insert_formula(+TypeCheckedExpression,+ParentID,-IDofNewFormula) |
| 194 | | bv_insert_formula(TExpr,ParentId,Id) :- %print(bv_insert_formula(TExpr,ParentId)),nl, |
| 195 | | get_new_id(Id), |
| 196 | | assert( stored_formula(Id,TExpr) ), |
| 197 | | assert( subnode(ParentId,Id) ), |
| 198 | | assert( supernode(Id,ParentId) ), |
| 199 | | ( ParentId == top -> |
| 200 | | assert( top_level_node(Id) ) |
| 201 | | ; otherwise -> |
| 202 | | true). |
| 203 | | |
| 204 | | |
| 205 | | :- meta_predicate bv_time_out_call(0,-,-,-). |
| 206 | | bv_time_out_call(Call,ValueFromCall,Timeout,Value) :- |
| 207 | | (time_out_with_enum_warning_one_solution( Call, |
| 208 | | Timeout, |
| 209 | | Result) |
| 210 | | -> |
| 211 | | ( Result == success -> Value = ValueFromCall |
| 212 | | ; Result = virtual_time_out(failure_enumeration_warning(_Info,_,_,_,critical)) -> Value = e('?(\x221E\)') % Value = e('\x22A5\?(\x221E\)') % 8734 in decimal % Feedback for user: increasing MAXINT,... could mean ProB can find a solution; However, increasing TIMEOUT value will not help |
| 213 | | ; Result = virtual_time_out(_) -> Value = e('?(\x221E\)') % infinity symbol: Feedback to the user: probably no way to solve the issue apart from ensuring that set comprehensions are finite ... |
| 214 | | ; otherwise -> Value = e(timeout)) |
| 215 | | ). |
| 216 | | |
| 217 | | bv_get_values2([],_,_,_,[]). |
| 218 | | bv_get_values2([Id|Irest],State,StateId,Timeout,[Value|Vrest]) :- |
| 219 | | bv_get_value(Id,State,StateId,Timeout,Value), |
| 220 | | bv_get_values2(Irest,State,StateId,Timeout,Vrest). |
| 221 | | bv_get_value(Id,State1,StateId,Timeout,FinalValue) :- |
| 222 | | bv_get_value_unprocessed(Id,State1,StateId,Timeout,Value), |
| 223 | | value_post_processing(Value,FinalValue). |
| 224 | | bv_get_value_unprocessed(Id,State1,StateId,Timeout,Value) :- |
| 225 | | is_active(Id,StateId,State1,State,LocalState),!, %print(is_active(Id)), debug:nl_time, |
| 226 | | ( is_cached(Id,StateId,State1,Value1) -> |
| 227 | | FromCache = true |
| 228 | | ; bv_get_value1(Id,State,LocalState,Timeout,Value1) -> |
| 229 | | FromCache = false %, print(evaluated),debug:nl_time |
| 230 | | ; otherwise -> |
| 231 | | Value1 = e('evaluation failed'), |
| 232 | | FromCache = false), |
| 233 | | handle_errors(Value1,Value), |
| 234 | | ( FromCache==false, should_be_cached(Id) -> |
| 235 | | write_to_cache(Id,StateId,State1,Value) |
| 236 | | ; otherwise -> true). |
| 237 | | bv_get_value_unprocessed(_Id,_State1,_StateId,_Timeout,i). % INACTIVE |
| 238 | | bv_get_value1(Id,State,LocalState,Timeout,Value) :- |
| 239 | | stored_formula(Id,Formula), |
| 240 | | bv_get_value2(Formula,State,LocalState,Timeout,Value). |
| 241 | | bv_get_value2(Formula,State,LocalState,Timeout,Value) :- |
| 242 | | is_texpr(Formula),!, |
| 243 | | get_texpr_type(Formula,Type), |
| 244 | | bv_get_value3(Type,Formula,LocalState,State,Timeout,Value). |
| 245 | | bv_get_value2(bind(_ID,Value),_,_,_,btvalue(Value)). |
| 246 | | bv_get_value2(textnode(Value,_),_State,_LS,_,v(Value)). |
| 247 | | %bv_get_value2(cbc_path(_LastStateID,Path,_Last),_State,_LS,_,v(NrOfPaths)) :- |
| 248 | | % append(Path,_,Prefix), |
| 249 | | % findall(Last,sap:cb_path(_,Prefix,Last),AllPathsWithPrefix), |
| 250 | | % length(AllPathsWithPrefix,NrOfPaths). |
| 251 | | bv_get_value2(variant(_Name,_ConvOrAnt,Variant),State,LocalState,Timeout,Value) :- |
| 252 | | bv_get_value2(Variant,State,LocalState,Timeout,Value). |
| 253 | | bv_get_value2(guard(_Name,Parameters,Guard),State,LocalState,Timeout,Value) :- !, |
| 254 | | get_guard_formula(Parameters,Guard,Expr), |
| 255 | | bv_get_value2(Expr,State,LocalState,Timeout,Value). |
| 256 | | bv_get_value2(guard_theorems(_Name,Parameters,Guard,Theorems),State,LocalState,Timeout,Value) :- !, |
| 257 | | get_guard_theorems_formula(Parameters,Guard,Theorems,Expr), |
| 258 | | bv_get_value2(Expr,State,LocalState,Timeout,Value). |
| 259 | | bv_get_value3(pred,Formula,LocalState,State,Timeout,Value) :- |
| 260 | | !, |
| 261 | | % print('CHECKING PREDICATE: '), translate:print_bexpr(Formula),nl, |
| 262 | | ( bv_time_out_call(b_test_boolean_expression_wf(Formula,LocalState,State),true,Timeout,ValuePos) -> true |
| 263 | | ; otherwise -> ValuePos=false), |
| 264 | | ( get_preference(double_evaluation_when_analysing,true) -> |
| 265 | | ( bv_time_out_call(b_not_test_boolean_expression_wf(Formula,LocalState,State),true,Timeout,ValueNeg) -> true |
| 266 | | ; otherwise -> ValueNeg=false), |
| 267 | | combine_predicate_values(ValuePos,ValueNeg,Value) |
| 268 | | ; otherwise -> encode_predicate_value(ValuePos,Value)). |
| 269 | | bv_get_value3(_,Formula,LocalState,State,Timeout,Res) :- |
| 270 | | bv_time_out_call(b_compute_expression_nowf(Formula,LocalState,State,FValue),FValue,Timeout,Value),!, |
| 271 | | ( Value = e(E) -> Res = e(E) % e for exception or timeout |
| 272 | | ; otherwise -> Res = btvalue(Value,Formula) |
| 273 | | ). |
| 274 | | |
| 275 | | |
| 276 | | encode_predicate_value(e(Error),e(Error)). |
| 277 | | encode_predicate_value(true,p(true)). |
| 278 | | encode_predicate_value(false,p(false)). |
| 279 | | combine_predicate_values(e(_Error),true,p(false)) :- print('### Ignoring Timeout in Positive Case of DOUBLE_EVALUATION as Negated Predicate is TRUE'),nl. |
| 280 | | combine_predicate_values(e(_Error),false,p(true)) :- print('### Ignoring Timeout in Positive Case of DOUBLE_EVALUATION as Negated Predicate is FALSE'),nl. |
| 281 | | combine_predicate_values(e(Error),e(_),e(Error)). |
| 282 | | combine_predicate_values(true,false,p(true)). |
| 283 | | combine_predicate_values(false,true,p(false)). |
| 284 | | combine_predicate_values(true,true,e('both true and false')). |
| 285 | | combine_predicate_values(false,false,e(undefined)). |
| 286 | | combine_predicate_values(true,e(_Error),p(true)) :- print('### Ignoring Timeout in Negative Case of DOUBLE_EVALUATION'),nl. |
| 287 | | combine_predicate_values(false,e(_Error),p(false)) :- print('### Ignoring Timeout in Negative Case of DOUBLE_EVALUATION'),nl. |
| 288 | | |
| 289 | | :- dynamic get_unlimited_value/0. |
| 290 | | |
| 291 | | :- use_module(translate,[set_translation_mode/1,unset_translation_mode/1]). |
| 292 | | |
| 293 | | value_post_processing(In,Out) :- |
| 294 | | bvisual2_translation_mode(Mode), |
| 295 | | set_translation_mode(Mode), |
| 296 | | ( value_post_processing2(In,O) -> O=Out |
| 297 | | ; otherwise -> Out=e('internal error: failed to post-process value')), |
| 298 | | unset_translation_mode(Mode). |
| 299 | | value_post_processing2(v(Value),v(Value)). |
| 300 | | value_post_processing2(p(Value),p(Value)). |
| 301 | | value_post_processing2(e(Error),e(Error)). |
| 302 | | value_post_processing2(i,i). |
| 303 | | value_post_processing2(btvalue(BValue,Expr),v(Value)) :- |
| 304 | | (get_unlimited_value -> translate_bvalue_for_expression(BValue,Expr,Value) |
| 305 | | ; translate_bvalue_for_expression_with_limit(BValue,Expr,600,Value) % one can always use bv_get_value_unlimited |
| 306 | | ). |
| 307 | | value_post_processing2(btvalue(BValue),v(Value)) :- |
| 308 | | % TO DO: get type for variables and constants |
| 309 | | (get_unlimited_value -> translate_bvalue(BValue,Value) |
| 310 | | ; translate_bvalue_with_type_and_limit(BValue,any,600,Value)). |
| 311 | | |
| 312 | | |
| 313 | | |
| 314 | | |
| 315 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 316 | | % caching of some values |
| 317 | | :- use_module(store,[no_value_for_variable/2]). |
| 318 | | |
| 319 | | % we do not compute the theorems node, only its subnodes |
| 320 | | is_cached(theoremsc,_,_,v('')) :- !. |
| 321 | | is_cached(theoremscm,_,_,v('')) :- !. |
| 322 | | is_cached(theoremsv,_,_,v('')) :- !. |
| 323 | | is_cached(theoremsvm,_,_,v('')) :- !. |
| 324 | | is_cached(goal,_,_,v('')) :- !. |
| 325 | | % we use the invariant_violated flag of the state space as a kind of cache |
| 326 | | is_cached(inv,StateId,_State,Value) :- |
| 327 | | \+ invariant_not_yet_checked(StateId), |
| 328 | | ( invariant_violated(StateId) -> Value=p(false) |
| 329 | | ; otherwise -> Value=p(true)). |
| 330 | | % axioms are usually true in the constants' state |
| 331 | | is_cached(axioms,StateId,concrete_constants(State),R) :- !, |
| 332 | | is_cached_constants_state(StateId,State,R). |
| 333 | | is_cached(axioms,StateId,[_|_],R) :- !, % states consisting of just a list are either constructed by |
| 334 | | % find valid state, state-based MC,... or when there are no constants |
| 335 | | % We assume PROPERTIES/axioms to be true; by constructing these commands have to satisfy the properties |
| 336 | | is_cached_constants_state(StateId,[],R). |
| 337 | | % this formula was already computed and cached for the given state |
| 338 | | is_cached(FormulaId,StateId,_State,Value) :- |
| 339 | | formula_cache(FormulaId,StateId,Value),!. |
| 340 | | % in case of axiom, we can look at the reverences constants' state |
| 341 | | is_cached(FormulaId,_,expanded_const_and_vars(ConstId,_,_),Value) :- is_cached_axiom(FormulaId,ConstId,Value). |
| 342 | | is_cached(FormulaId,_,const_and_vars(ConstId,_),Value) :- is_cached_axiom(FormulaId,ConstId,Value). |
| 343 | | is_cached_axiom(FormulaId,ConstId,Value) :- |
| 344 | | is_axiom_or_static_theorem(FormulaId), |
| 345 | | visited_expression(ConstId,ConstState), |
| 346 | | is_cached(FormulaId,ConstId,ConstState,Value),!. |
| 347 | | |
| 348 | | is_cached_constants_state(StateId,State,R) :- |
| 349 | | % only if a partial_setup_constants event led to that |
| 350 | | % state, then something did not work |
| 351 | | ( transition(root,'$partial_setup_constants',StateId) -> |
| 352 | | (member(bind(_,Val),State), no_value_for_variable(Val,_) |
| 353 | | -> R = e('some constants have no values') |
| 354 | | ; animation_minor_mode(eventb) -> R = e('some axioms may be false') |
| 355 | | ; otherwise -> R = e('some properties may be false') |
| 356 | | ) |
| 357 | | ; otherwise -> |
| 358 | | R = p(true)). |
| 359 | | |
| 360 | | should_be_cached(FormulaId) :- |
| 361 | | is_axiom_or_static_theorem(FormulaId). |
| 362 | | |
| 363 | | write_to_cache(FormulaId,_StateId,const_and_vars(ConstId,_),Value) :- |
| 364 | | is_axiom_or_static_theorem(FormulaId),!, |
| 365 | | visited_expression(ConstId,ConstState), |
| 366 | | write_to_cache(FormulaId,ConstId,ConstState,Value). |
| 367 | | write_to_cache(FormulaId,StateId,_State,Value) :- |
| 368 | | assert(formula_cache(FormulaId,StateId,Value)). |
| 369 | | |
| 370 | | is_axiom_or_static_theorem(axioms) :- !. |
| 371 | | is_axiom_or_static_theorem(theoremsc) :- !. |
| 372 | | is_axiom_or_static_theorem(theoremscm) :- !. |
| 373 | | is_axiom_or_static_theorem(FormulaId) :- |
| 374 | | supernode(FormulaId,Parent),is_axiom_or_static_theorem(Parent). |
| 375 | | |
| 376 | | handle_errors(_,e(ErrorMsg)) :- |
| 377 | | get_all_errors_and_clear([Error|_]),!, % TO DO: use proper error scoping and do not trigger when error stored before calling bvisual2 |
| 378 | | write_to_codes(Error,ErrorCodes), |
| 379 | | limit_error(ErrorCodes,ErrorCodes2), |
| 380 | | atom_codes(ErrorMsg,ErrorCodes2). |
| 381 | | handle_errors(Value,Value). |
| 382 | | |
| 383 | | limit_error(ErrorCodes,ErrorCodes) :- |
| 384 | | length(ErrorCodes,L),L < 200,!. |
| 385 | | limit_error(In,Out) :- |
| 386 | | prefix_length(In,Start,200), |
| 387 | | append(Start,"...",Out). |
| 388 | | |
| 389 | | % is_active(+FormulaID,+InState,-PossiblyExpandedState) |
| 390 | | % says if a FormulaID makes sense for the current state, if not: it will be grayed out |
| 391 | | is_active(user,StateId,InState,OutState,LocalState) :- !, |
| 392 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 393 | | is_active(inv,_StateId,InState,OutState,LocalState) :- !, |
| 394 | | empty_state(LocalState), |
| 395 | | state_corresponds_to_initialised_b_machine(InState,OutState). |
| 396 | | is_active(axioms,_StateId,InState,OutState,LocalState) :- !, |
| 397 | | InState \= root, |
| 398 | | empty_state(LocalState), |
| 399 | | state_corresponds_to_set_up_constants(InState,OutState), |
| 400 | | !. |
| 401 | | is_active(variants,StateId,InState,OutState,LocalState) :- !, |
| 402 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 403 | | is_active(theoremsc,StateId,InState,OutState,LocalState) :- !, |
| 404 | | is_active(axioms,StateId,InState,OutState,LocalState). |
| 405 | | is_active(theoremscm,StateId,InState,OutState,LocalState) :- !, |
| 406 | | is_active(axioms,StateId,InState,OutState,LocalState). |
| 407 | | is_active(theoremsv,StateId,InState,OutState,LocalState) :- !, |
| 408 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 409 | | is_active(theoremsvm,StateId,InState,OutState,LocalState) :- !, |
| 410 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 411 | | is_active(guards,StateId,InState,OutState,LocalState) :- !, |
| 412 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 413 | | is_active(guard_theorems,StateId,InState,OutState,LocalState) :- !, |
| 414 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 415 | | is_active(variables,StateId,InState,OutState,LocalState) :- !, |
| 416 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 417 | | is_active(constants,StateId,InState,OutState,LocalState) :- !, |
| 418 | | is_active(axioms,StateId,InState,OutState,LocalState). |
| 419 | | is_active(sets,_StateId,InState,OutState,LocalState) :- !, b_or_z_successsful_mode, |
| 420 | | empty_state(LocalState), InState=OutState. |
| 421 | | is_active(freetypes,_StateId,InState,OutState,LocalState) :- !, |
| 422 | | empty_state(LocalState), InState=OutState. |
| 423 | | is_active(goal,StateId,InState,OutState,LocalState) :- !, |
| 424 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 425 | | is_active(user_formulas,StateId,InState,OutState,LocalState) :- !, |
| 426 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 427 | | is_active(definitions,StateId,InState,OutState,LocalState) :- !, |
| 428 | | is_active(inv,StateId,InState,OutState,LocalState). |
| 429 | | is_active(channels,_StateId,S,OutState,LocalState) :- !, |
| 430 | | csp_mode, OutState=S,empty_state(LocalState). |
| 431 | | is_active(datatypes,_StateId,S,OutState,LocalState) :- !, |
| 432 | | csp_mode, OutState=S,empty_state(LocalState). |
| 433 | | is_active(subtypes,_StateId,S,OutState,LocalState) :- !, |
| 434 | | csp_mode, OutState=S,empty_state(LocalState). |
| 435 | | %is_active(cbc_tests,_StateId,_InState,_OutState,_LocalState) :- !, |
| 436 | | % sap:cb_path(_,[_],_). % show cbc_tests if we ran CBC test-case generator |
| 437 | | is_active(NodeId,StateId,InState,OutState,LocalState) :- |
| 438 | | supernode(NodeId,Super), |
| 439 | | is_active(Super,StateId,InState,OutState,InLocalState), |
| 440 | | % check if the parent node introduces example values (e.g. in a exists-clause) |
| 441 | | % If yes, the local state is extended by the values |
| 442 | | ( example_node(Super) -> |
| 443 | | find_example(Super,StateId,OutState,InLocalState,LocalState) |
| 444 | | ; otherwise -> |
| 445 | | InLocalState = LocalState). |
| 446 | | |
| 447 | | find_example(NodeId,StateId,_State,_InLocalState,LocalState) :- |
| 448 | | % check if the value was computed and cached before |
| 449 | | local_state(NodeId,StateId,Result),!, |
| 450 | | % if Result is not of the form example/1, no example |
| 451 | | % was found. Just fail to show inactive state |
| 452 | | Result = example(LocalState). |
| 453 | | find_example(NodeId,StateId,State,InLocalState,LocalState) :- |
| 454 | | % how the example is computed depends on the expression (e.g. exists) |
| 455 | | % and the outcome of the parent node (true or false) |
| 456 | | bv_get_values([NodeId],StateId,[V]),!, |
| 457 | | stored_formula(NodeId,Formula), |
| 458 | | ( find_example1(Formula,V,State,InLocalState,LocalState) -> |
| 459 | | Result = example(LocalState) |
| 460 | | ; otherwise -> |
| 461 | | Result = not_found), |
| 462 | | % currently we just ignore errors |
| 463 | | handle_errors(_,_), |
| 464 | | assert( local_state(NodeId,StateId,Result) ), |
| 465 | | Result = example(_). |
| 466 | | find_example1(TExpr,V,State,InLocalState,LocalState) :- |
| 467 | | is_texpr(TExpr),!, |
| 468 | | get_texpr_expr(TExpr,Expr), |
| 469 | | find_example2(Expr,V,State,InLocalState,LocalState). |
| 470 | | find_example1(guard(_Name,Parameters,Guard),V,State,InLocalState,LocalState) :- |
| 471 | | create_exists(Parameters,Guard,Exists), |
| 472 | | find_example1(Exists,V,State,InLocalState,LocalState). |
| 473 | | find_example1(guard_theorems(_Name,Parameters,Guard,Theorems),V,State,InLocalState,LocalState) :- |
| 474 | | create_forall(Parameters,b(implication(Guard,Theorems),pred,[]),ForAll), |
| 475 | | find_example1(ForAll,V,State,InLocalState,LocalState). |
| 476 | | find_example2(let_predicate(Ids,AssignmentExprs,Pred),Status,State,InLocalState,LocalState) :- |
| 477 | | % translate LET back to exists |
| 478 | | create_exists_for_let(Ids,AssignmentExprs,Pred,_,ExistsPred), |
| 479 | | find_example2(exists(Ids,ExistsPred),Status,State,InLocalState,LocalState). |
| 480 | | find_example2(exists(Ids,Predicate),p(true),State,InLocalState,LocalState) :- |
| 481 | | find_solution_for_predicate(Ids,Predicate,State,InLocalState,LocalState). |
| 482 | | find_example2(exists(Ids,Predicate),p(false),State,InLocalState,LocalState) :- |
| 483 | | Predicate = b(conjunct(_,_),pred,_), % we have a false conjunct: try and find maximal prefix that is satisfiable |
| 484 | | conjunction_to_list(Predicate,PredList), |
| 485 | | maxsat_conjunct(Ids,PredList,[],State,InLocalState,no_solution,LocalState), |
| 486 | | LocalState \= no_solution, |
| 487 | | !. |
| 488 | | find_example2(exists(Ids,Predicate),p(false),State,InLocalState,LocalState) :- |
| 489 | | safe_create_texpr(negation(Predicate),pred,Negation), |
| 490 | | find_solution_for_predicate(Ids,Negation,State,InLocalState,LocalState). |
| 491 | | find_example2(forall(Ids,Pre,Condition),p(false),State,InLocalState,LocalState) :- |
| 492 | | safe_create_texpr(negation(Condition),pred,Negation), |
| 493 | | conjunct_predicates([Pre,Negation],Predicate), |
| 494 | | find_solution_for_predicate(Ids,Predicate,State,InLocalState,LocalState). |
| 495 | | find_example2(forall(Ids,Pre,Condition),p(true),State,InLocalState,LocalState) :- |
| 496 | | conjunct_predicates([Pre,Condition],Predicate), |
| 497 | | find_solution_for_predicate(Ids,Predicate,State,InLocalState,LocalState), |
| 498 | | !. |
| 499 | | find_example2(forall(Ids,Pre,_),p(true),State,InLocalState,LocalState) :- |
| 500 | | % the LHS of the forall is never true; try find maximal subsequence for it: |
| 501 | | find_example2(exists(Ids,Pre),p(false),State,InLocalState,LocalState). |
| 502 | | find_solution_for_predicate(Ids,Predicate,State,InLocalState,NormedLocalState) :- |
| 503 | | get_preference(time_out,Timeout), |
| 504 | | set_up_typed_localstate(Ids,_FreshVars,TypedVals,InLocalState,LocalState,positive), |
| 505 | | (time_out_with_enum_warning_one_solution( (init_wait_flags(WF), |
| 506 | | b_tighter_enumerate_values(TypedVals,WF), |
| 507 | | b_test_boolean_expression(Predicate,LocalState,State,WF), |
| 508 | | ground_wait_flags(WF)), |
| 509 | | Timeout,Result) |
| 510 | | -> Result == success, |
| 511 | | normalise_store(LocalState,NormedLocalState) |
| 512 | | ). |
| 513 | | |
| 514 | | create_exists_for_let(Ids,AssignmentExprs,Pred,Equalities,ExistsPred) :- |
| 515 | | maplist(create_equality,Ids,AssignmentExprs,Equalities), |
| 516 | | append(Equalities,[Pred],L), |
| 517 | | conjunct_predicates(L,ExistsPred). |
| 518 | | |
| 519 | | create_equality(ID,Expr,Equality) :- |
| 520 | | safe_create_texpr(equal(ID,Expr),pred,Equality). |
| 521 | | |
| 522 | | % find maximal subsequence of conjuncts that are satisfiable and return LocalState solution found |
| 523 | | maxsat_conjunct(Ids,[LHS|Rest],ConSoFar,State,InLocalState,_BestLocalStateSoFar,ResLocalState) :- |
| 524 | | append(ConSoFar,[LHS],NewConjunctList), |
| 525 | | %print('TRY: '), translate:print_bexpr(LHS),nl, |
| 526 | | conjunct_predicates(NewConjunctList,NewConjunct), |
| 527 | | find_solution_for_predicate(Ids,NewConjunct,State,InLocalState,LocalState), |
| 528 | | !, % print('+'), |
| 529 | | maxsat_conjunct(Ids,Rest,NewConjunctList,State,InLocalState, LocalState,ResLocalState). |
| 530 | | maxsat_conjunct(Ids,[_|Rest],ConSoFar,State,InLocalState,BestLocalStateSoFar,Res) :- !, % allows skipping conjuncts |
| 531 | | maxsat_conjunct(Ids,Rest,ConSoFar,State,InLocalState,BestLocalStateSoFar,Res). |
| 532 | | maxsat_conjunct(_Ids,_Rest,_ConSoFar,_State,_InLocalState,BestLocalStateSoFar,Res) :- |
| 533 | | Res = BestLocalStateSoFar. |
| 534 | | |
| 535 | | explore_node(Id,Children) :- |
| 536 | | stored_formula(Id,Formula), |
| 537 | | check_if_example_node(Id,Formula), |
| 538 | | get_subformulas(Formula,Subs,Kind), |
| 539 | | assert( expanded(Id) ), |
| 540 | | (Kind = explanation |
| 541 | | -> assert_as_explanation(Id,ExplId), Children = [ExplId|Children1], |
| 542 | | register_formulas(Subs,Id,Children1) |
| 543 | | ; register_formulas(Subs,Id,Children)). |
| 544 | | |
| 545 | | assert_as_explanation(Parent,Id) :- |
| 546 | | assert(explanation_parent(Parent)), |
| 547 | | % add a text line; showing that we did an equivalence rewrite |
| 548 | | get_new_id(Id), |
| 549 | | assert( stored_formula(Id,textnode('\x21D4\',[])) ), % unicode translation |
| 550 | | assert( subnode(Parent,Id) ), |
| 551 | | assert( supernode(Id,Parent) ). |
| 552 | | |
| 553 | | bv_is_explanation_node(NodeId) :- |
| 554 | | supernode(NodeId,ParentId), |
| 555 | | explanation_parent(ParentId). |
| 556 | | |
| 557 | | % the following predicates determine whether the node introduces |
| 558 | | % example values and stores that information in example_node/1. |
| 559 | | check_if_example_node(Id,Formula) :- |
| 560 | | is_example_node(Formula),!, |
| 561 | | assert( example_node(Id) ). |
| 562 | | check_if_example_node(_Id,_Formula). |
| 563 | | is_example_node(TFormula) :- |
| 564 | | is_texpr(TFormula),!, |
| 565 | | get_texpr_expr(TFormula,Formula), |
| 566 | | is_example_node2(Formula). |
| 567 | | is_example_node(guard(_Name,[_|_],_Guard)). |
| 568 | | is_example_node(guard_theorems(_Name,[_|_],_Guard,_Theorems)). |
| 569 | | is_example_node2(exists(_Ids,_Cond)). |
| 570 | | is_example_node2(forall(_Ids,_Pre,_Cond)). |
| 571 | | is_example_node2(let_predicate(_Ids,_E,_Cond)). |
| 572 | | |
| 573 | | % subformula_rule/4 defines wich subformulas should be |
| 574 | | % shown in an evaluation tree for a formula. If no |
| 575 | | % rule matches, the standard subformulas are used |
| 576 | | subformula_rule(equal(A,B),TF,[Sub1,Sub2],explanation) :- |
| 577 | | get_texpr_type(A,T),T=set(SType), |
| 578 | | \+ (kernel_objects:max_cardinality(SType,Max),number(Max),Max<10), % sets can never be very large |
| 579 | | is_not_bvexpr(TF), % do not apply to explanation expressions |
| 580 | | no_empty_set(A),no_empty_set(B), |
| 581 | | !, |
| 582 | | create_bvexpr(set_subtraction(A,B),T,AminusB), |
| 583 | | create_bvexpr(set_subtraction(B,A),T,BminusA), |
| 584 | | create_bvexpr(empty_set,T,Empty), |
| 585 | | create_bvexpr(equal(AminusB,Empty),pred,Sub1), |
| 586 | | create_bvexpr(equal(BminusA,Empty),pred,Sub2). |
| 587 | | subformula_rule(subset(A,B),_,[Equals],explanation) :- |
| 588 | | subset_rule(A,B,Equals). |
| 589 | | subformula_rule(subset_strict(A,B),_,[AmBEmpty,NotEquals],explanation) :- |
| 590 | | subset_rule(A,B,AmBEmpty), |
| 591 | | get_texpr_type(A,T), |
| 592 | | create_bvexpr(set_subtraction(B,A),T,BminusA), |
| 593 | | create_bvexpr(empty_set,T,Empty), |
| 594 | | create_bvexpr(not_equal(BminusA,Empty),pred,NotEquals). |
| 595 | | subformula_rule(not_subset(A,B),_,Subs,Kind) :- |
| 596 | | subformula_rule(subset(A,B),_,Subs,Kind). % it is an equivalent rewrite to the negation |
| 597 | | subformula_rule(not_subset_strict(A,B),_,Subs,Kind) :- |
| 598 | | subformula_rule(subset_strict(A,B),_,Subs,Kind). % it is an equivalent rewrite to the negation |
| 599 | | subformula_rule(forall(Ids,P,R),_,Subs,quantifier) :- |
| 600 | | append(Ids,[P,R],Subs). |
| 601 | | subformula_rule(let_predicate(Ids,AssignmentExprs,Pred),_,Subs,quantifier) :- |
| 602 | | create_exists_for_let(Ids,AssignmentExprs,Pred,Equalities,_ExistsPred), |
| 603 | | append(Equalities,[Pred],EP), % show equalities and then one subnode for the predicate |
| 604 | | append(Ids,EP,Subs). |
| 605 | | subformula_rule(exists(Ids,P),_,Subs,quantifier) :- |
| 606 | | conjunction_to_list(P,PL), |
| 607 | | append(Ids,PL,Subs). |
| 608 | | subformula_rule(conjunct(A,B),_,Subs,normal) :- |
| 609 | | safe_create_texpr(conjunct(A,B),pred,E), |
| 610 | | conjunction_to_list(E,Subs). |
| 611 | | subformula_rule(disjunct(A,B),_,Subs,normal) :- |
| 612 | | disjunction_to_list(A,B,Subs). |
| 613 | | subformula_rule(member(TM,TS),_,Children,explanation) :- |
| 614 | | get_texpr_expr(TS,S), |
| 615 | | subformula_member_rule(S,TM,TS,Children),!. |
| 616 | | |
| 617 | | subset_rule(A,B,Equals) :- |
| 618 | | get_texpr_type(A,T), |
| 619 | | create_bvexpr(set_subtraction(A,B),T,AminusB), |
| 620 | | create_bvexpr(empty_set,T,Empty), |
| 621 | | create_bvexpr(equal(AminusB,Empty),pred,Equals). |
| 622 | | |
| 623 | | :- use_module(bsyntaxtree,[is_just_type/1]). |
| 624 | | |
| 625 | | subformula_member_rule(partial_function(TDom,TRan),TM,TS,[TDoubles]) :- |
| 626 | | is_just_type(TDom), |
| 627 | | is_just_type(TRan), |
| 628 | | !, |
| 629 | | % this rule describes the plain function check, without |
| 630 | | % checking domains |
| 631 | | texpr_function_type(TS,FunctionType,DomType,RanType), |
| 632 | | create_texpr(identifier(d_1),DomType,[],TDomId), |
| 633 | | create_texpr(identifier(r_1),RanType,[],TRanId1), |
| 634 | | create_texpr(identifier(r_2),RanType,[],TRanId2), |
| 635 | | create_texpr(comprehension_set([TDomId,TRanId1],TExists),FunctionType,[],TDoubles), |
| 636 | | % create_exists([TRanId2],TPred,TExists1), % moved below so that used ids can be computed |
| 637 | | create_texpr(couple(TDomId,TRanId1),couple(DomType,RanType),[],TCouple1), |
| 638 | | create_texpr(couple(TDomId,TRanId2),couple(DomType,RanType),[],TCouple2), |
| 639 | | safe_create_texpr(not_equal(TRanId1,TRanId2),pred,Unequal), |
| 640 | | create_texpr(member(TCouple1,TM),pred,[],TMember1), |
| 641 | | create_texpr(member(TCouple2,TM),pred,[],TMember2), |
| 642 | | conjunct_predicates([Unequal,TMember1,TMember2],TPred), |
| 643 | | create_exists([TRanId2],TPred,TExists1), % now also computes used identifiers; cleanup no longer required ? |
| 644 | | % This is necessary to register the used identifiers |
| 645 | | clean_up_pred(TExists1,[],TExists). |
| 646 | | subformula_member_rule(partial_function(TA,TB),TM,TS,[TFunCheck|SetChecks]) :- |
| 647 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 648 | | create_domain_range_checks(TDomain,TRange,TA,TB,SetChecks). |
| 649 | | subformula_member_rule(total_function(TA,TB),TM,TS,[TFunCheck|SetChecks]) :- |
| 650 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 651 | | create_total_domain_range_checks(TDomain,TRange,TA,TB,SetChecks). |
| 652 | | subformula_member_rule(partial_injection(TA,TB),TM,TS,[TFunCheck,TInjCheck|SetChecks]) :- |
| 653 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 654 | | create_injection_check(TM,TS,TInjCheck), |
| 655 | | create_domain_range_checks(TDomain,TRange,TA,TB,SetChecks). |
| 656 | | subformula_member_rule(total_injection(TA,TB),TM,TS,[TFunCheck,TInjCheck|SetChecks]) :- |
| 657 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 658 | | create_injection_check(TM,TS,TInjCheck), |
| 659 | | create_total_domain_range_checks(TDomain,TRange,TA,TB,SetChecks). |
| 660 | | subformula_member_rule(partial_surjection(TA,TB),TM,TS,Children) :- |
| 661 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 662 | | create_texpr(equal(TRange,TB),pred,[],TRanCheck), |
| 663 | | create_optional_subset_check(TDomain,TA,DomChecks), |
| 664 | | append([TFunCheck|DomChecks],[TRanCheck],Children). |
| 665 | | subformula_member_rule(total_surjection(TA,TB),TM,TS,[TFunCheck,TDomCheck,TRanCheck]) :- |
| 666 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 667 | | create_texpr(equal(TDomain,TA),pred,[],TDomCheck), |
| 668 | | create_texpr(equal(TRange,TB),pred,[],TRanCheck). |
| 669 | | subformula_member_rule(total_bijection(TA,TB),TM,TS,[TFunCheck,TInjCheck,TDomCheck,TRanCheck]) :- |
| 670 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 671 | | create_injection_check(TM,TS,TInjCheck), |
| 672 | | create_texpr(equal(TDomain,TA),pred,[],TDomCheck), |
| 673 | | create_texpr(equal(TRange,TB),pred,[],TRanCheck). |
| 674 | | subformula_member_rule(partial_bijection(TA,TB),TM,TS,Children) :- |
| 675 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange), |
| 676 | | create_injection_check(TM,TS,TInjCheck), |
| 677 | | create_optional_subset_check(TDomain,TA,DomChecks), |
| 678 | | create_texpr(equal(TRange,TB),pred,[],TRanCheck), |
| 679 | | append([TFunCheck,TInjCheck|DomChecks],[TRanCheck],Children). |
| 680 | | subformula_member_rule(pow_subset(TA),TM,_TS,[NewCheck]) :- |
| 681 | | % TM : POW(TA) <=> TM \ TA = {} |
| 682 | | get_texpr_type(TM,Type), |
| 683 | | create_bvexpr(set_subtraction(TM,TA),Type,Diff), |
| 684 | | create_bvexpr(empty_set,Type,Empty), |
| 685 | | create_bvexpr(equal(Diff,Empty),pred,NewCheck). |
| 686 | | % TO DO: add rules for <:, <<:, FIN, POW1, FIN1 |
| 687 | | |
| 688 | | create_function_check(TM,TS,TFunCheck,TDomain,TRange) :- |
| 689 | | texpr_function_type(TS,FunctionType,DomType,RanType), |
| 690 | | translate:set_type_to_maximal_texpr(DomType,TDom), |
| 691 | | translate:set_type_to_maximal_texpr(RanType,TRan), |
| 692 | | create_bvexpr(partial_function(TDom,TRan),set(FunctionType),TFun), |
| 693 | | create_bvexpr(member(TM,TFun),pred,TFunCheck), |
| 694 | | create_bvexpr(domain(TM),set(DomType),TDomain), |
| 695 | | create_bvexpr(range(TM),set(RanType),TRange). |
| 696 | | |
| 697 | | create_domain_range_checks(TDomain,TRange,TA,TB,SetChecks) :- |
| 698 | | create_optional_subset_check(TDomain,TA,DomCheck), |
| 699 | | create_optional_subset_check(TRange,TB,RanCheck), |
| 700 | | append(DomCheck,RanCheck,SetChecks). |
| 701 | | create_total_domain_range_checks(TDomain,TRange,TA,TB,[TIsTotal|RanCheck]) :- |
| 702 | | create_texpr(equal(TDomain,TA),pred,[],TIsTotal), |
| 703 | | create_optional_subset_check(TRange,TB,RanCheck). |
| 704 | | create_optional_subset_check(TSubset,TSuperset,Check) :- |
| 705 | | ( is_just_type(TSuperset) -> |
| 706 | | Check = [] |
| 707 | | ; otherwise -> |
| 708 | | create_texpr(subset(TSubset,TSuperset),pred,[],TPred), |
| 709 | | Check = [TPred]). |
| 710 | | |
| 711 | | create_injection_check(TM,TS,TCheckExpr) :- |
| 712 | | texpr_function_type(TS,FunctionType,DomType,RanType), |
| 713 | | create_texpr(identifier(d_1),DomType,[],TDomId1), |
| 714 | | create_texpr(identifier(d_2),DomType,[],TDomId2), |
| 715 | | create_texpr(identifier(r_1),RanType,[],TRanId), |
| 716 | | create_texpr(comprehension_set([TDomId1,TRanId],TExists),FunctionType,[bv_function_check(TM)],TCheckExpr), |
| 717 | | %create_exists([TDomId2],TPred,TExists1), |
| 718 | | create_texpr(couple(TDomId1,TRanId),couple(DomType,RanType),[],TCouple1), |
| 719 | | create_texpr(couple(TDomId2,TRanId),couple(DomType,RanType),[],TCouple2), |
| 720 | | create_texpr(not_equal(TDomId1,TDomId2),pred,[],Unequal), |
| 721 | | create_texpr(member(TCouple1,TM),pred,[],TMember1), |
| 722 | | create_texpr(member(TCouple2,TM),pred,[],TMember2), |
| 723 | | conjunct_predicates([Unequal,TMember1,TMember2],TPred), |
| 724 | | create_exists([TDomId2],TPred,TExists1), % now also computes used identifiers; cleanup no longer required ? |
| 725 | | % This is necessary to register the used identifiers |
| 726 | | clean_up_pred(TExists1,[],TExists). |
| 727 | | |
| 728 | | texpr_function_type(TFun,FunType,DomType,RanType) :- |
| 729 | | get_texpr_type(TFun,set(FunType)), |
| 730 | | FunType = set(couple(DomType,RanType)). |
| 731 | | |
| 732 | | |
| 733 | | create_bvexpr(Expr,Type,TExpr) :- |
| 734 | | create_texpr(Expr,Type,[bvisual],TExpr). |
| 735 | | is_not_bvexpr(TExpr) :- |
| 736 | | get_texpr_info(TExpr,Infos),nonmember(bvisual,Infos). |
| 737 | | %is_bvexpr(TExpr) :- get_texpr_info(TExpr,Infos),memberchk(bvisual,Infos). |
| 738 | | |
| 739 | | no_empty_set(E) :- \+ is_empty_set(E). |
| 740 | | |
| 741 | | is_empty_set(b(E,_,_)) :- is_empty_set_aux(E). |
| 742 | | is_empty_set_aux(empty_set). |
| 743 | | is_empty_set_aux(empty_sequence). |
| 744 | | is_empty_set_aux(value(X)) :- X==[]. |
| 745 | | |
| 746 | | get_subformulas(TFormula,Subs,Kind) :- |
| 747 | | is_texpr(TFormula), |
| 748 | | get_texpr_expr(TFormula,Formula), |
| 749 | | subformula_rule(Formula,TFormula,Subs,Kind),!. |
| 750 | | get_subformulas(TFormula,Subs,syntaxtraversion) :- |
| 751 | | is_texpr(TFormula),!, |
| 752 | | syntaxtraversion(TFormula,_,_,_,Subs1,Names), |
| 753 | | ( Names = [] -> |
| 754 | | filter_trivial_expressions(Subs1,Subs) |
| 755 | | ; otherwise -> Subs = []). |
| 756 | | get_subformulas(textnode(_,Subs),Subs,textnode) :- !. |
| 757 | | get_subformulas(guard(_Name,Parameters,Guard),Subs,guard) :- !, |
| 758 | | conjunction_to_list(Guard,GuardSubs), |
| 759 | | append(Parameters,GuardSubs,Subs). |
| 760 | | get_subformulas(variant(_Name,_ConvOrAnt,Variant),Subs,variant) :- !, |
| 761 | | Subs = [Variant]. |
| 762 | | get_subformulas(guard_theorems(_Name,[],_Guard,Theorems),Subs,guard_theorems) :- !, |
| 763 | | conjunction_to_list(Theorems,Subs). |
| 764 | | get_subformulas(guard_theorems(_Name,Parameters,Guard,Theorems),Subs,guard_theorems) :- !, |
| 765 | | append(Parameters,[b(implication(Guard,Theorems),pred,[])],Subs). |
| 766 | | %get_subformulas(cbc_path(_,Path,_),Subs) :- !, |
| 767 | | % append(Path,[X],XPath), |
| 768 | | % findall(cbc_path(LastStateID,XPath,X), sap:cb_path(LastStateID,XPath,_), Subs). |
| 769 | | get_subformulas(_,[],none). |
| 770 | | |
| 771 | | filter_trivial_expressions([],[]). |
| 772 | | filter_trivial_expressions([TI|Irest],Out) :- |
| 773 | | get_texpr_expr(TI,I),get_texpr_info(TI,Info), |
| 774 | | ( is_trivial(I,Info) -> Out = Orest |
| 775 | | ; otherwise -> Out = [TI|Orest]), |
| 776 | | filter_trivial_expressions(Irest,Orest). |
| 777 | | |
| 778 | | % is_trivial/2 is true for expressions that should not appear as single nodes |
| 779 | | % in the evaluation tree, because they are too simple. |
| 780 | | % The first argument is the expression, the second its information list |
| 781 | | is_trivial(integer(_),_). |
| 782 | | is_trivial(integer_set(_),_). |
| 783 | | is_trivial(empty_set,_). |
| 784 | | is_trivial(boolean_true,_). |
| 785 | | is_trivial(boolean_false,_). |
| 786 | | is_trivial(bool_set,_). |
| 787 | | is_trivial(truth,_). |
| 788 | | is_trivial(falsity,_). |
| 789 | | is_trivial(identifier(_),Info) :- |
| 790 | | memberchk(given_set,Info). |
| 791 | | is_trivial(identifier(_),Info) :- |
| 792 | | memberchk(enumerated_set_element,Info). |
| 793 | | % TO DO: treat value(_) ? |
| 794 | | |
| 795 | | :- use_module(tools_strings,[ajoin/2]). |
| 796 | | :- use_module(specfile,[animation_minor_mode/1, csp_mode/0, b_or_z_mode/0, get_specification_description/2]). |
| 797 | | get_node_label(inv,invariants) :- animation_minor_mode(eventb),!. |
| 798 | | get_node_label(inv,I):- !, get_specification_description(invariant,I). |
| 799 | | get_node_label(axioms,axioms) :- animation_minor_mode(eventb),!. |
| 800 | | get_node_label(axioms,S):- !, get_specification_description(properties,S). |
| 801 | | get_node_label(variants,variants) :- animation_minor_mode(eventb),!. |
| 802 | | get_node_label(variants,'VARIANT') :- !. % not used there |
| 803 | | get_node_label(theoremsc,'theorems (on constants)') :- animation_minor_mode(eventb),!. |
| 804 | | get_node_label(theoremsc,'ASSUME (on constants)') :- animation_minor_mode(tla),!. |
| 805 | | get_node_label(theoremsc,'ALL ASSERTIONS (on CONSTANTS)') :- b_get_assertion_count(static,AllNr,MainNr), MainNr < AllNr, !. |
| 806 | | get_node_label(theoremsc,'ASSERTIONS (on CONSTANTS)') :- !. |
| 807 | | get_node_label(theoremscm,'MAIN ASSERTIONS (on CONSTANTS)') :- !. % should only trigger in B mode at the moment |
| 808 | | get_node_label(theoremsv,'theorems (on variables)') :- animation_minor_mode(eventb),!. |
| 809 | | get_node_label(theoremsv,'ALL ASSERTIONS (on VARIABLES)') :- b_get_assertion_count(dynamic,AllNr,MainNr), MainNr < AllNr, !. |
| 810 | | get_node_label(theoremsv,'ASSERTIONS (on VARIABLES)') :- !. |
| 811 | | get_node_label(theoremsvm,'MAIN ASSERTIONS (on VARIABLES)') :- !. % should only trigger in B mode at the moment |
| 812 | | get_node_label(sets,'sets') :- animation_minor_mode(eventb),!. |
| 813 | | get_node_label(sets,'SETS'). |
| 814 | | get_node_label(freetypes,'inductive datatypes') :- animation_minor_mode(eventb),!. |
| 815 | | get_node_label(freetypes,'FREETYPES'). |
| 816 | | get_node_label(goal,'GOAL'). |
| 817 | | get_node_label(variables,'variables') :- animation_minor_mode(eventb),!. |
| 818 | | get_node_label(variables,'VARIABLES'). |
| 819 | | get_node_label(constants,'constants') :- animation_minor_mode(eventb),!. |
| 820 | | get_node_label(constants,'CONSTANTS'). |
| 821 | | get_node_label(guards,'event guards') :- animation_minor_mode(eventb),!. |
| 822 | | get_node_label(guards,'ACTIONS (guards)') :- animation_minor_mode(tla),!. |
| 823 | | get_node_label(guards,'OPERATIONS (guards/preconditions)') :- !. % GUARDS/PRE |
| 824 | | get_node_label(guard_theorems,'theorems (in guards)') :- !. |
| 825 | | get_node_label(user_formulas,'USER FORMULAS') :- !. |
| 826 | | get_node_label(definitions,'DEFINITIONS') :- !. |
| 827 | | %get_node_label(cbc_tests,'CBC_TESTS') :- !. |
| 828 | | get_node_label(channels,'channel'). |
| 829 | | get_node_label(datatypes,'datatype'). |
| 830 | | get_node_label(subtypes,'subtype'). |
| 831 | | get_node_label(Id,Label) :- |
| 832 | | stored_formula(Id,Formula), |
| 833 | | get_node_label2(Formula,Label). |
| 834 | | |
| 835 | | get_node_label2(textnode(Text,_),Text) :- !. |
| 836 | | get_node_label2(bind(TID,_),ID) :- !, |
| 837 | | (is_texpr(TID),get_texpr_id(TID,R) -> ID = R ; ID = TID). |
| 838 | | get_node_label2(guard(Name,_Parameters,_Guard),Name) :- !. |
| 839 | | get_node_label2(guard_theorems(Name,_Parameters,_Guard,_Theorems),Name) :- !. |
| 840 | | get_node_label2(variant(OpName,ConvOrAnt,_Variant),Name) :- !, |
| 841 | | ajoin([OpName,' |-> ',ConvOrAnt],Name). |
| 842 | | get_node_label2(TExpr,Label) :- |
| 843 | | is_texpr(TExpr),!, |
| 844 | | bvisual2_translation_mode(Mode), |
| 845 | | translate_subst_or_bexpr_in_mode(Mode,TExpr,Label). % use unicode, latex or ascii; but unicode_mode makes Viewer very slow |
| 846 | | get_node_label2(Term,Label) :- |
| 847 | | functor(Term,F,Arity), |
| 848 | | ajoin(['unknown node type: ',F,'/',Arity],Label). |
| 849 | | |
| 850 | | :- dynamic bvisual2_translation_mode/1. |
| 851 | | bvisual2_translation_mode(unicode). % or ascii or latex |
| 852 | | set_bvisual2_translation_mode(X) :- retractall(bvisual2_translation_mode(_)), |
| 853 | | assert(bvisual2_translation_mode(X)). |
| 854 | | |
| 855 | | |
| 856 | | register_top_level :- register_top_level(_). |
| 857 | | register_top_level(Id) :- |
| 858 | ? | top_level2(Id,Formula,Subs), % print(register(Id,Subs)),nl, |
| 859 | | register_top_level_formula(Id,Formula,Subs), |
| 860 | | fail. |
| 861 | | register_top_level(_Id). |
| 862 | | |
| 863 | | |
| 864 | | :- use_module(specfile,[b_or_z_mode/0]). |
| 865 | | :- use_module(b_global_sets,[all_elements_of_type/2]). |
| 866 | | :- use_module(bmachine,[b_get_machine_goal/1]). |
| 867 | | :- use_module(specfile,[spec_file_has_been_successfully_loaded/0]). |
| 868 | | b_or_z_successsful_mode :- b_or_z_mode, |
| 869 | | true. %spec_file_has_been_successfully_loaded. % make unit test fail |
| 870 | | |
| 871 | | top_level2(variables,textnode('',Variables),Variables) :- b_or_z_successsful_mode, |
| 872 | | variables_should_be_included, |
| 873 | | b_get_machine_variables(Variables). |
| 874 | | top_level2(constants,textnode('',Constants),Constants) :- b_or_z_successsful_mode, |
| 875 | | variables_should_be_included, |
| 876 | | b_get_machine_constants(Constants). |
| 877 | | top_level2(sets,textnode('',Sets),Sets) :- b_or_z_successsful_mode, |
| 878 | | findall(bind(S,All), |
| 879 | | top_level_set(S,All),Sets), Sets \= []. |
| 880 | | top_level2(freetypes,textnode('',Sets),Sets) :- b_or_z_successsful_mode, |
| 881 | | findall(bind(S,All), top_level_freetype(S,All),Sets), Sets \= []. |
| 882 | | top_level2(goal,Goal,Subs) :- b_or_z_successsful_mode, |
| 883 | | b_get_machine_goal(Goal), |
| 884 | | conjunction_to_list(Goal,Subs). |
| 885 | | top_level2(inv,Invariant,Subs) :- b_or_z_successsful_mode, |
| 886 | | b_get_invariant_from_machine(Invariant), |
| 887 | | conjunction_to_list(Invariant,Subs). |
| 888 | | top_level2(variants,textnode('',Variants),Variants) :- animation_minor_mode(eventb), |
| 889 | | spec_file_has_been_successfully_loaded, |
| 890 | | findall(variant(Name,ConvOrAnt,Variant), |
| 891 | | b_get_operation_variant(Name,ConvOrAnt,Variant), |
| 892 | | Variants), |
| 893 | | Variants = [_|_]. |
| 894 | | top_level2(axioms,Props,Subs) :- b_or_z_successsful_mode, |
| 895 | | b_machine_has_constants_or_properties, |
| 896 | | b_get_properties_from_machine(Props), |
| 897 | | conjunction_to_list(Props,Subs). |
| 898 | | top_level2(theoremsc,Pred,Assertions) :- b_or_z_successsful_mode, |
| 899 | | b_get_static_assertions_from_machine(Assertions),Assertions\=[], |
| 900 | | conjunct_predicates(Assertions,Pred). |
| 901 | | top_level2(theoremscm,Pred,Assertions) :- b_or_z_successsful_mode, |
| 902 | | b_get_assertions_from_main_machine(static,Assertions), |
| 903 | | %Assertions\=[], % in case we have less: show that there are none |
| 904 | | b_get_assertion_count(static,AllNr,MainNr), MainNr < AllNr, |
| 905 | | conjunct_predicates(Assertions,Pred). |
| 906 | | top_level2(theoremsv,Pred,Assertions) :- b_or_z_successsful_mode, |
| 907 | | b_get_dynamic_assertions_from_machine(Assertions),Assertions\=[], |
| 908 | | conjunct_predicates(Assertions,Pred). |
| 909 | | top_level2(theoremsvm,Pred,Assertions) :- b_or_z_successsful_mode, |
| 910 | | b_get_assertions_from_main_machine(dynamic,Assertions), |
| 911 | | %Assertions\=[], % in case we have less: show that there are none |
| 912 | | b_get_assertion_count(dynamic,AllNr,MainNr), MainNr < AllNr, |
| 913 | | conjunct_predicates(Assertions,Pred). |
| 914 | | top_level2(guards,textnode('',EventGuards),EventGuards) :- b_or_z_successsful_mode, |
| 915 | | findall(guard(Name,Params,Guard), |
| 916 | | get_guard(Name,Params,Guard),EventGuards), |
| 917 | | EventGuards = [_|_]. |
| 918 | | top_level2(guard_theorems,textnode('',EventGuards),EventGuards) :- b_or_z_successsful_mode, |
| 919 | | findall(guard_theorems(Name,Params,Guard,GuardTheorems), |
| 920 | | ( b_get_machine_operation(Name,_,_,TBody), |
| 921 | | get_texpr_expr(TBody,Body), |
| 922 | | Body = rlevent(_Name,_Section,_Status,Params,Guard,Theorems, |
| 923 | | _Actions,_VWitnesses,_PWitnesses,_Unmod,_AbstractEvents), |
| 924 | | Theorems \= [], |
| 925 | | conjunct_predicates(Theorems,GuardTheorems) |
| 926 | | ), |
| 927 | | EventGuards), |
| 928 | | EventGuards = [_|_]. |
| 929 | | top_level2(user_formulas,textnode('',UserPredicates),UserPredicates) :- b_or_z_successsful_mode, |
| 930 | | findall(UP,subnode(user_formulas,UP),UserPredicates), UserPredicates\=[]. |
| 931 | | top_level2(definitions,textnode('',Defs),Defs) :- b_or_z_successsful_mode, |
| 932 | | findall(Node,get_definition(Node),Defs), Defs\=[]. |
| 933 | | top_level2(channels,textnode('',Channels),Channels) :- csp_mode, spec_file_has_been_successfully_loaded, |
| 934 | | findall(Node,get_csp_channel(Node),Cs), Cs\=[], sort(Cs,Channels). |
| 935 | | top_level2(datatypes,textnode('',DT),DT) :- csp_mode, spec_file_has_been_successfully_loaded, |
| 936 | | findall(Node,get_csp_datatype(Node),Cs), Cs\=[], sort(Cs,DT). |
| 937 | | top_level2(subtypes,textnode('',DT),DT) :- csp_mode, spec_file_has_been_successfully_loaded, |
| 938 | | findall(Node,get_csp_subtype(Node),Cs), Cs\=[], sort(Cs,DT). |
| 939 | | % we are now using a custom tree_inspector for the CBC Tests |
| 940 | | /* top_level2(cbc_tests,textnode('',Paths),Paths) :- b_or_z_mode, |
| 941 | | get_preference(user_is_an_expert_with_accessto_source_distribution,true), |
| 942 | | %sap:cb_path(_,[_],_), % we have generated at least one test-case |
| 943 | | % TO DO: we need a way to refresh this information after test-cases have been generated |
| 944 | | % currently the only way seems to close the evaluation view, reload, generate the tests and then open the view |
| 945 | | Paths = [cbc_path(root,[],'INITIALISATION')]. |
| 946 | | */ |
| 947 | | |
| 948 | | :- use_module(probcspsrc(haskell_csp),[channel_type_list/2, dataTypeDef/2, subTypeDef/2]). |
| 949 | | :- use_module(translate,[translate_cspm_expression/2]). |
| 950 | | get_csp_channel(bind(Channel,string(TypeString))) :- |
| 951 | | channel_type_list(Channel,TypeList), % something like [dataType('SubSubMsg'),intType,boolType] |
| 952 | | translate_cspm_expression(dotTuple(TypeList),TypeString). |
| 953 | | get_csp_datatype(bind(DT,string(TypeString))) :- |
| 954 | | dataTypeDef(DT,TypeList), % something like [dataType('SubSubMsg'),intType,boolType] |
| 955 | | translate_cspm_expression(dataTypeDef(TypeList),TypeString). |
| 956 | | get_csp_subtype(bind(DT,string(TypeString))) :- |
| 957 | | subTypeDef(DT,TypeList), % something like [dataType('SubSubMsg'),intType,boolType] |
| 958 | | translate_cspm_expression(dataTypeDef(TypeList),TypeString). |
| 959 | | |
| 960 | | :- use_module(bmachine). |
| 961 | | :- use_module(pref_definitions,[b_get_set_pref_definition/3]). |
| 962 | | get_definition(textnode('GOAL',Subs)) :- b_get_machine_goal(Goal), conjunction_to_list(Goal,Subs). |
| 963 | | get_definition(bind('SCOPE',string(S))) :- b_get_machine_searchscope(S). |
| 964 | | get_definition(textnode('HEURISTIC_FUNCTION',[F])) :- b_get_machine_heuristic_function(F). |
| 965 | | get_definition(textnode('ANIMATION_EXPRESSION',[F])) :- b_get_machine_animation_expression(F). |
| 966 | | get_definition(textnode(Name,[F])) :- b_get_machine_animation_function(F,Nr), |
| 967 | | number_codes(Nr,NC), append("ANIMATION_FUNCTION",NC,C), atom_codes(Name,C). |
| 968 | | get_definition(textnode(Name,[Term])) :- b_get_machine_setscope(SetName,Term), |
| 969 | | atom_codes(SetName,NC), append("scope_",NC,C), atom_codes(Name,C). |
| 970 | | get_definition(textnode(Name,[b(integer(Nr),integer,[])])) :- b_get_machine_operation_max(OpName,Nr), |
| 971 | | atom_codes(OpName,NC), append("MAX_OPERATIONS_",NC,C), atom_codes(Name,C). |
| 972 | | get_definition(bind(Name,string(F))) :- |
| 973 | | b_get_definition_string_from_machine(Name,F), atom_codes(Name,C), \+ append("SET_PREF_",_,C). |
| 974 | | get_definition(Res) :- |
| 975 | ? | b_get_set_pref_definition(DefName,_String,F), |
| 976 | ? | (extract_value(F,Val) -> Res = bind(DefName,Val) ; Res = textnode(DefName,[F])). |
| 977 | | |
| 978 | | extract_value(b(string(S),_,_),string(S)). |
| 979 | | extract_value(b(integer(S),_,_),int(S)). |
| 980 | | extract_value(b(boolean_true,_,_),pred_true). |
| 981 | | extract_value(b(boolean_false,_,_),pred_false). |
| 982 | | |
| 983 | | :- use_module(predicate_debugger,[get_unsimplified_operation_enabling_condition/5]). |
| 984 | | get_guard(OpName,Params,Guard) :- |
| 985 | ? | get_unsimplified_operation_enabling_condition(OpName,Params,Guard,_BecomesSuchVars,_Precise), |
| 986 | | \+ is_initialisation_op(OpName). |
| 987 | | |
| 988 | | is_initialisation_op('$setup_constants'). |
| 989 | | is_initialisation_op('$initialise_machine'). |
| 990 | | |
| 991 | | :- use_module(custom_explicit_sets,[construct_interval_closure/3]). |
| 992 | | :- use_module(kernel_freetypes,[registered_freetype/2]). |
| 993 | | :- use_module(bmachine,[b_get_machine_set/2]). |
| 994 | ? | top_level_set(TSet,AllEls) :- b_or_z_mode, |
| 995 | ? | b_get_machine_set(Set,TSet), |
| 996 | | all_elements_of_type(Set,AllEls). |
| 997 | | top_level_set('INT',INTVAL) :- % we can return both typed ids and atomic ids |
| 998 | | b_or_z_mode, |
| 999 | | \+ animation_minor_mode(_), % INT only exists in pure B mode |
| 1000 | | get_preference(maxint,MAXINT), get_preference(minint,MININT), |
| 1001 | | construct_interval_closure(MININT,MAXINT,INTVAL). |
| 1002 | | |
| 1003 | | top_level_freetype(Set,AllCases) :- |
| 1004 | | animation_minor_mode(eventb), % here types contain Prolog variables (polymorphism) + we have the constant(_) type |
| 1005 | | registered_freetype(SetP,Cases), |
| 1006 | | functor(SetP,Set,_), |
| 1007 | | %print(cases(Cases)),nl, |
| 1008 | | findall(string(CaseString), |
| 1009 | | (member(case(CaseP,T),Cases),functor(CaseP,Case,_), %print(t(T)),nl, |
| 1010 | | translate:pretty_type(T,TS), tools:ajoin([Case,':',TS],CaseString) |
| 1011 | | ),AllCases). |
| 1012 | | top_level_freetype(Set,AllCases) :- b_or_z_mode, \+ animation_minor_mode(eventb), |
| 1013 | | registered_freetype(Set,Cases), |
| 1014 | | % TO DO: improve presentation, maybe use translate:type_set(_Type,TDom); we also have constant(_) type here |
| 1015 | | findall(field(Case,closure(['_zzzz_unary'],[T],b(truth,pred,[]))), |
| 1016 | | member(case(Case,T),Cases), |
| 1017 | | Fields), |
| 1018 | | AllCases = struct(Fields). |
| 1019 | | |
| 1020 | | register_top_level_formula(Id,Formula,Subs) :- |
| 1021 | | assert( stored_formula(Id,Formula) ), |
| 1022 | | register_formulas(Subs,Id,_), |
| 1023 | | assert( top_level_node(Id) ), |
| 1024 | | assert( expanded(Id) ). |
| 1025 | | |
| 1026 | | register_formulas([],_Parent,[]). |
| 1027 | | register_formulas([Formula|Frest],Parent,[SubId|Srest]) :- |
| 1028 | | register_formula(Formula,Parent,SubId), |
| 1029 | | register_formulas(Frest,Parent,Srest). |
| 1030 | | register_formula(Formula,Parent,Id) :- |
| 1031 | | get_new_id(Id), |
| 1032 | | assert( stored_formula(Id,Formula) ), |
| 1033 | | assert( subnode(Parent,Id) ), |
| 1034 | | assert( supernode(Id,Parent) ). |
| 1035 | | |
| 1036 | | get_new_id(Id) :- |
| 1037 | | ( retract( id_counter(Old) ) -> true |
| 1038 | | ; otherwise -> Old = 0), |
| 1039 | | Id is Old+1, |
| 1040 | | assert( id_counter(Id) ). |
| 1041 | | |
| 1042 | | |
| 1043 | | disjunction_to_list(A,B,Out) :- |
| 1044 | | disjunction_to_list2(A,[B],Out,[]). |
| 1045 | | disjunction_to_list2(Expr,Rest) --> |
| 1046 | | {get_texpr_expr(Expr,disjunct(A,B)),!}, |
| 1047 | | disjunction_to_list2(A,[B|Rest]). |
| 1048 | | disjunction_to_list2(Expr,Rest) --> |
| 1049 | | [Expr],disjunction_to_list3(Rest). |
| 1050 | | disjunction_to_list3([]) --> !. |
| 1051 | | disjunction_to_list3([H|T]) --> disjunction_to_list2(H,T). |
| 1052 | | |
| 1053 | | |
| 1054 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 1055 | | % some predicates for the support of the Tcl/Tk UI |
| 1056 | | |
| 1057 | | :- meta_predicate call_with_temp_preference(*,*,0). |
| 1058 | | call_with_temp_preference(Prefs,Values,Call) :- |
| 1059 | | maplist(get_preference,Prefs,OldValues), |
| 1060 | | maplist(set_preference,Prefs,Values), |
| 1061 | | call_cleanup(Call,maplist(set_preference,Prefs,OldValues)),!. |
| 1062 | | |
| 1063 | | bv_get_value_unlimited(Id,StateId,Value) :- |
| 1064 | | visited_expression(StateId,State),!, |
| 1065 | | get_preference(time_out,Timeout), |
| 1066 | | assert(get_unlimited_value), |
| 1067 | | call_cleanup(call_with_temp_preference([expand_avl_upto],[-1],bv_get_value(Id,State,StateId,Timeout,Value)), |
| 1068 | | retractall(get_unlimited_value)). |
| 1069 | | bv_get_value_unlimited(_Id,_StateId,e('unknown state')). |
| 1070 | | |
| 1071 | | bv_get_value_unlimited_and_unprocessed(Id,StateId,Value) :- |
| 1072 | | visited_expression(StateId,State),!, |
| 1073 | | get_preference(time_out,Timeout), |
| 1074 | | call_with_temp_preference([expand_avl_upto],[-1],bv_get_value_unprocessed(Id,State,StateId,Timeout,Value)). |
| 1075 | | bv_get_value_unlimited_and_unprocessed(_Id,_StateId,e('unknown state')). |
| 1076 | | |
| 1077 | | :- use_module(tools_commands,[edit_file/2]). |
| 1078 | | :- use_module(probsrc(error_manager),[extract_file_line_col/6,extract_span_description/2]). |
| 1079 | | bv_show_formula_origin(Id,Desc) :- |
| 1080 | | bv_get_stored_formula_expr(Id,Formula), |
| 1081 | | extract_file_line_col(Formula,FILE,LINE,_COL,_Erow,_Ecol), |
| 1082 | | extract_span_description(Formula,Desc), |
| 1083 | | edit_file(FILE,LINE). |
| 1084 | | |
| 1085 | | :- use_module(probsrc(bsyntaxtree),[get_texpr_description/2]). |
| 1086 | | bv_formula_description(Id,Desc) :- |
| 1087 | | bv_get_stored_formula_expr(Id,Formula), |
| 1088 | | is_texpr(Formula), |
| 1089 | | get_texpr_description(Formula,Desc). |
| 1090 | | % ; Desc = 'No description available via @desc pragma'). |
| 1091 | | |
| 1092 | | bv_is_typed_formula(Id) :- bv_get_stored_formula_expr(Id,Formula), is_texpr(Formula). |
| 1093 | | bv_is_typed_predicate(Id) :- bv_get_stored_formula_expr(Id,Formula), Formula = b(_,pred,_). |
| 1094 | | bv_is_typed_identifier(Id,IDName) :- bv_get_stored_formula_expr(Id,Formula), Formula = b(identifier(IDName),_,_). |
| 1095 | | |
| 1096 | | bv_get_stored_formula_expr(Id,Formula) :- |
| 1097 | | stored_formula(Id,Stored), |
| 1098 | | extract_typed_formua(Stored,Formula). |
| 1099 | | |
| 1100 | | extract_typed_formua(bind(LHS,_),Formula) :- !, Formula=LHS. |
| 1101 | | extract_typed_formua(guard(_Name,Parameters,Guard),Formula) :- !, get_guard_formula(Parameters,Guard,Formula). |
| 1102 | | extract_typed_formua(variant(_Name,_ConvOrAnt,Variant),Formula) :- !, Formula=Variant. |
| 1103 | | extract_typed_formua(TF,TF). |
| 1104 | | |
| 1105 | | get_guard_formula([],Guard,Res) :- !, Res=Guard. |
| 1106 | | get_guard_formula(Parameters,Guard,Expr) :- create_exists(Parameters,Guard,Expr). |
| 1107 | | get_guard_theorems_formula([],_Guard,Theorems,Res) :- !, Res=Theorems. |
| 1108 | | get_guard_theorems_formula(Parameters,Guard,Theorems,Expr) :- |
| 1109 | | create_forall(Parameters,b(implication(Guard,Theorems),pred,[]),Expr). |
| 1110 | | |
| 1111 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 1112 | | % |
| 1113 | | :- use_module(tools_io). |
| 1114 | | bv_print_to_file(IdList,StateId,Filename) :- |
| 1115 | | call_with_temp_preference([expand_avl_upto],[-1],bv_print_to_file_aux(IdList,StateId,Filename)). |
| 1116 | | bv_print_to_file_aux(IdList,StateId,Filename) :- |
| 1117 | | safe_open_file(Filename,write,S,[]), |
| 1118 | | bv_print_to_stream_l(IdList,S,StateId,false), |
| 1119 | | close(S). |
| 1120 | | |
| 1121 | | bv_print_to_stream_l([],_S,_StateId,_WriteAnd). |
| 1122 | | bv_print_to_stream_l([Id|Rest],S,StateId,WriteAnd) :- |
| 1123 | | bv_print_to_stream(Id,S,StateId,OutType,WriteAnd), |
| 1124 | | ( OutType=predicate -> WriteAnd2=true |
| 1125 | | ; otherwise -> WriteAnd2=WriteAnd), |
| 1126 | | bv_print_to_stream_l(Rest,S,StateId,WriteAnd2). |
| 1127 | | |
| 1128 | | bv_print_to_stream(Id,S,StateId,predicate,WriteAnd) :- |
| 1129 | | stored_formula(Id,Formula), |
| 1130 | | bv_print_formula_to_stream(Formula,Id,S,StateId,WriteAnd),!,nl(S). |
| 1131 | | bv_print_to_stream(Id,S,StateId,other,_WriteAnd) :- |
| 1132 | | get_node_label(Id,Label), |
| 1133 | | bv_get_values([Id],StateId,[Value]), |
| 1134 | | write(S,'/* '),write(S,Label),write(S,': '), |
| 1135 | | bv_print_std_value(Value,S),write(S,' */\n'). |
| 1136 | | bv_print_std_value(e(Msg),S) :- write(S,'ERROR( '), write(S,Msg), write(S,' )'). |
| 1137 | | bv_print_std_value(p(Value),S) :- write(S,Value). |
| 1138 | | bv_print_std_value(v(Value),S) :- write(S,Value). |
| 1139 | | bv_print_std_value(i,S) :- write(S,'INACTIVE'). |
| 1140 | | |
| 1141 | | bv_print_formula_to_stream(Formula,Id,S,StateId,WriteAnd) :- |
| 1142 | | is_texpr(Formula), |
| 1143 | | get_texpr_type(Formula,Type), |
| 1144 | | bv_get_value_unlimited_and_unprocessed(Id,StateId,Value), |
| 1145 | | bv_print_formula_to_stream2(Type,Formula,Value,S,WriteAnd). |
| 1146 | | |
| 1147 | | bv_print_formula_to_stream2(pred,Formula,p(Value),S,WriteAnd) :- !, |
| 1148 | | bv_print_predicate_to_stream(Value,Formula,S,WriteAnd). |
| 1149 | | bv_print_formula_to_stream2(Type,Formula,btvalue(Value,_),S,WriteAnd) :- !, |
| 1150 | | create_texpr(value(Value),Type,[],TValue), |
| 1151 | | create_texpr(equal(Formula,TValue),pred,[],Equal), |
| 1152 | | write_bexpression(S,Equal,WriteAnd). |
| 1153 | | |
| 1154 | | bv_print_predicate_to_stream(true,Formula,S,WriteAnd) :- |
| 1155 | | write_bexpression(S,Formula,WriteAnd). |
| 1156 | | bv_print_predicate_to_stream(false,Formula,S,WriteAnd) :- |
| 1157 | | create_texpr(negation(Formula),pred,[],NegatedFormula), |
| 1158 | | write(S,' /* FALSE */ '),write_bexpression(S,NegatedFormula,WriteAnd). |
| 1159 | | |
| 1160 | | write_bexpression(Stream,Expression,WriteAnd) :- |
| 1161 | | ( WriteAnd = true -> write(Stream,' & \n') |
| 1162 | | ; otherwise -> true), |
| 1163 | | translate_bexpression_to_codes(Expression,Codes), |
| 1164 | | put_codes(Codes,Stream). |
| 1165 | | |
| 1166 | | bv_write_all_variables_and_constants(StateId,Filename) :- |
| 1167 | | call_with_temp_preference([expand_avl_upto],[-1],bv_write_all_variables_and_constants_aux(StateId,Filename)). |
| 1168 | | bv_write_all_variables_and_constants_aux(StateId,Filename) :- |
| 1169 | | bv_expand_formula(constants,_CLabel,ConstNodes), |
| 1170 | | bv_expand_formula(variables,_VLabel,VarNodes), |
| 1171 | | append(ConstNodes,VarNodes,Subnodes),expand_all(Subnodes), |
| 1172 | | append([constants|ConstNodes],[variables|VarNodes],Nodes), |
| 1173 | | bv_print_to_file(Nodes,StateId,Filename). |
| 1174 | | expand_all(Subnodes) :- |
| 1175 | | member(Node,Subnodes), |
| 1176 | | bv_expand_formula(Node,_,_), |
| 1177 | | fail. |
| 1178 | | expand_all(_Subnodes). |
| 1179 | | |
| 1180 | | |
| 1181 | | :- use_module(eventhandling,[register_event_listener/3]). |
| 1182 | | :- register_event_listener(clear_specification,clear_bvisual, |
| 1183 | | 'Clear module bvisual2.'). |
| 1184 | | :- register_event_listener(specification_initialised,reset_bvisual, |
| 1185 | | 'Initialise module bvisual2.'). |
| 1186 | | :- register_event_listener(change_of_animation_mode,reset_bvisual, |
| 1187 | | 'Initialise module bvisual2.'). |
| 1188 | | |
| 1189 | | :- use_module(self_check). |
| 1190 | | % a very small use-case: |
| 1191 | | :- assert_must_succeed(( |
| 1192 | | reset_bvisual, |
| 1193 | | bv_get_top_level(T), %print(top(T)),nl, |
| 1194 | | %T == [variables,constants,inv], |
| 1195 | | member(inv,T), |
| 1196 | | bv_expand_formula(inv,Text,Sub), |
| 1197 | | %print(expand(Text,Sub)),nl, |
| 1198 | | Text == 'INVARIANT', |
| 1199 | | Sub = [H|_], |
| 1200 | | bv_expand_formula(H,_Text1,_Sub1), |
| 1201 | | %print(expand1(Text1,Sub1)),nl, |
| 1202 | | bv_get_values(Sub,root,Values), |
| 1203 | | %print(values(Values)),nl, % should be [i,...] or e('unknown state') |
| 1204 | | Values = [VI|_], (VI=i ; VI=e(_)), |
| 1205 | | reset_bvisual |
| 1206 | | )). |
| 1207 | | |
| 1208 | | % example bv_get_top_level_formula(theoremsc,Txt,Labels,Vals) |
| 1209 | | |
| 1210 | | bv_get_top_level_formula(Category,CatText,Labels,Values) :- |
| 1211 | | current_state_id(StateId), |
| 1212 | | bv_get_top_level_formula(Category,CatText,StateId,Labels,Values). |
| 1213 | | bv_get_top_level_formula(Category,CatText,StateId,Labels,Values) :- |
| 1214 | | bv_get_top_level(TL), |
| 1215 | | member(Category,TL), |
| 1216 | | bv_expand_formula(Category,CatText,Subs), |
| 1217 | | maplist(get_node_label,Subs,Labels), |
| 1218 | | bv_get_values(Subs,StateId,Values). |
| 1219 | | |
| 1220 | | % ------------------------------------ |
| 1221 | | |
| 1222 | | % provide HTML output of operation guards upto MaxLevel |
| 1223 | | % TO DO: provide option to provide parameter values, output to Latex,... |
| 1224 | | html_debug_operation_for_stateid(Stream,OpName,StateId,MaxLevel) :- |
| 1225 | | stored_formula(Id,guard(OpName,_,_)), |
| 1226 | | enter_level(Stream,0), |
| 1227 | | traverse(Stream,StateId,0,MaxLevel,Id), |
| 1228 | | exit_level(Stream,0). |
| 1229 | | |
| 1230 | | :- use_module(tools,[html_escape/2]). |
| 1231 | | traverse(_,_StateId,Level,MaxLevel,_Id) :- Level>MaxLevel,!. |
| 1232 | | traverse(Stream,StateId,Level,MaxLevel,Id) :- |
| 1233 | | bv_expand_formula(Id,Label,Children), html_escape(Label,ELabel), |
| 1234 | | bv_get_values([Id],StateId,[Value]), |
| 1235 | | translate_value(Value,ValueS), html_escape(ValueS,EValueS), |
| 1236 | | % format('~w : ~w = ~w [~w] (level ~w)~n',[Id,Label,Value,ValueS,Level]), |
| 1237 | | stored_formula(Id,Formula), |
| 1238 | | (color_based_on_value(Value,Col) -> format(Stream,'<font color="~w">',[Col]) ; true), |
| 1239 | | (Formula = guard(_,_,_) |
| 1240 | | -> format(Stream,'<li>Guard of ~w = ~w</li>~n',[ELabel,EValueS]) |
| 1241 | | ; format(Stream,'<li>~w = ~w</li>~n',[ELabel,EValueS]) |
| 1242 | | ), |
| 1243 | | (color_based_on_value(Value,_) -> format(Stream,'</font>',[]) ; true), |
| 1244 | | (Level < MaxLevel |
| 1245 | | -> L1 is Level+1, |
| 1246 | | enter_level(Stream,L1), |
| 1247 | | maplist(traverse(Stream,StateId,L1,MaxLevel),Children), |
| 1248 | | exit_level(Stream,L1) |
| 1249 | | ; true). |
| 1250 | | |
| 1251 | | color_based_on_value(p(false),'INDIANRED'). |
| 1252 | | color_based_on_value(p(true),'DARKGREEN'). |
| 1253 | | color_based_on_value(e(_),red). |
| 1254 | | color_based_on_value(i,gray). |
| 1255 | | |
| 1256 | | enter_level(Stream,L1) :- indent_ws(Stream,L1), format(Stream,'<ul>~n',[]). |
| 1257 | | exit_level(Stream,L1) :- indent_ws(Stream,L1), format(Stream,'</ul>~n',[]). |
| 1258 | | |
| 1259 | | indent_ws(_,X) :- X<1,!. |
| 1260 | | indent_ws(Stream,X) :- write(Stream,' '), X1 is X-1, indent_ws(Stream,X1). |
| 1261 | | |
| 1262 | | |
| 1263 | | translate_value(p(V),R) :- !,R=V. |
| 1264 | | translate_value(v(V),R) :- R=V. |
| 1265 | | translate_value(e(M),R) :- !, ajoin(['ERROR(',M,')'],R). |
| 1266 | | translate_value(i,R) :- !, R='INACTIVE'. |
| 1267 | | translate_value(V,V). |
| 1268 | | |
| 1269 | | % -------------------------------- |
| 1270 | | |
| 1271 | | :- use_module(probsrc(error_manager),[add_error/3]). |
| 1272 | | :- use_module(probsrc(bmachine),[b_parse_machine_predicate_from_codes_open/5, b_parse_machine_formula_from_codes/7]). |
| 1273 | | tcltk_register_new_user_formula(F) :- tcltk_register_new_user_formula(formula,F). |
| 1274 | | tcltk_register_new_user_formula(Kind,F) :- |
| 1275 | | atom_codes(F,Codes), |
| 1276 | | TypingScope=[prob_ids(visible),variables], |
| 1277 | | (Kind=open_predicate |
| 1278 | | -> b_parse_machine_predicate_from_codes_open(exists,Codes,[],TypingScope,Typed) |
| 1279 | | ; b_parse_machine_formula_from_codes(Kind,Codes,TypingScope,Typed,_Type,true,Error) |
| 1280 | | ), |
| 1281 | | (Error=none -> true |
| 1282 | | ; add_error(tcltk_register_new_user_formula,'Error occured while parsing formula: ',Error),fail), |
| 1283 | | bv_insert_formula(Typed,user_formulas,_), |
| 1284 | | (top_level_node(user_formulas) -> true ; register_top_level(user_formulas) ). |
| 1285 | | %retractall(expanded(user_formulas)), |
| 1286 | | %bv_insert_formula(Typed,user,_),. |
| 1287 | | |
| 1288 | | % -------------------------------- |
| 1289 | | |
| 1290 | | |