| 1 | % (c) 2015-2019 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
| 2 | % Heinrich Heine Universitaet Duesseldorf | |
| 3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
| 4 | ||
| 5 | :- module(smt_solvers_interface, [smt_solve_predicate/4, | |
| 6 | smt_add_predicate/5, | |
| 7 | smt_solve_predicate_in_state/5, | |
| 8 | init/0]). | |
| 9 | ||
| 10 | :- use_module(probsrc(module_information),[module_info/2]). | |
| 11 | :- module_info(group,smt_solvers). | |
| 12 | :- module_info(description,'This module provides an interface to SMT-solvers like CVC4 or Z3.'). | |
| 13 | ||
| 14 | :- use_module(library(lists), [maplist/2,maplist/3,maplist/4, | |
| 15 | append/2,exclude/3, | |
| 16 | nth0/3,some/2]). | |
| 17 | :- use_module(library(sets), [list_to_set/2]). | |
| 18 | ||
| 19 | :- use_module(probsrc(bsyntaxtree), [map_over_typed_bexpr/3, | |
| 20 | find_typed_identifier_uses/2, | |
| 21 | find_typed_identifier_uses/3, | |
| 22 | get_texpr_type/2, | |
| 23 | get_texpr_info/2, | |
| 24 | get_texpr_expr/2, | |
| 25 | get_texpr_id/2, | |
| 26 | conjunction_to_list/2, | |
| 27 | conjunct_predicates/2, | |
| 28 | disjunction_to_list/2, | |
| 29 | syntaxtraversion/6]). | |
| 30 | :- use_module(probsrc(error_manager), [add_error_fail/3]). | |
| 31 | :- use_module(probsrc(translate), [translate_bexpression/2]). | |
| 32 | :- use_module(probsrc(preferences), [get_preference/2]). | |
| 33 | :- use_module(probsrc(b_global_sets), [b_global_deferred_set/1, | |
| 34 | unfixed_deferred_set/1, | |
| 35 | b_get_global_enumerated_sets/1, | |
| 36 | is_b_global_constant/3, | |
| 37 | b_global_set_cardinality/2]). | |
| 38 | :- use_module(probsrc(custom_explicit_sets), [expand_custom_set_to_list_now/2]). | |
| 39 | :- use_module(probsrc(eventhandling),[register_event_listener/3]). | |
| 40 | :- use_module(probsrc(external_functions), [is_external_function_name/1]). | |
| 41 | :- use_module(probsrc(debug), [debug_format/3]). | |
| 42 | ||
| 43 | :- use_module(model_translation, [translate_smt_model_to_b_values/4]). | |
| 44 | :- use_module(ast_cleanup_for_smt, [clean_up/2]). | |
| 45 | :- use_module(prob_state_predicates, [create_state_pred/4]). | |
| 46 | :- use_module(solver_dispatcher). | |
| 47 | :- use_module(smt_common_predicates). | |
| 48 | ||
| 49 | init :- | |
| 50 | preferences:get_preference(smt_supported_interpreter,true), !, | |
| 51 | register_event_listener(start_solving,retractall(backjumping_symbols(_)),'clean smt backjumping information'), | |
| 52 | register_event_listener(start_solving,init_interface(z3),'Init Z3 Interface for a new solving'), | |
| 53 | register_event_listener(end_solving,reset_interface(z3),'Reset Z3 Interface after solving'). | |
| 54 | init. | |
| 55 | ||
| 56 | :- block smt_add_predicate(-,?,?,?,?). | |
| 57 | smt_add_predicate(_EnumWf,Pred,ProBLocalState,ProBState,Symbol) :- | |
| 58 | backjump_on_symbol(Symbol), | |
| 59 | smt_add_predicate_to_solver(z3,Pred,ProBLocalState,ProBState,Symbol). | |
| 60 | ||
| 61 | smt_add_predicate_to_solver(Solver,Pred,ProBLocalState,ProBState,Symbol) :- | |
| 62 | init_interface(Solver), | |
| 63 | smt_solver_interface_call(Solver,push_frame), | |
| 64 | clean_up(Pred,CPred), | |
| 65 | find_typed_identifier_uses(CPred,[],Identifiers), | |
| 66 | (contains_introduced_identifiers(Identifiers,CPred) | |
| 67 | -> debug_format(9,'z3: skip: ~w~n because there were introduced identifiers', [Symbol]) | |
| 68 | ; create_state_pred(Identifiers,ProBLocalState,ProBState,StatePred), | |
| 69 | conjunction_to_list(StatePred,StatePredConjuncts), | |
| 70 | exclude(contains_unsupported_type_or_expression(Solver),StatePredConjuncts,FilteredStatePredConjuncts), | |
| 71 | conjunct_predicates(FilteredStatePredConjuncts,FilteredStatePred), | |
| 72 | conjunct_predicates([FilteredStatePred,CPred],FullPred), | |
| 73 | setup_sets(Solver,GlobalIdentifiers), | |
| 74 | create_smt_state(Solver,Identifiers,IdentifierState,_), | |
| 75 | append(IdentifierState,GlobalIdentifiers,GlobalState), | |
| 76 | mk_expr_skip(Solver,FullPred,[],GlobalState,Expr), | |
| 77 | translate_bexpression(FullPred,PPExpr), | |
| 78 | debug_format(9,'z3: add expr: ~w using symbol: ~w~n', [PPExpr,Symbol]), | |
| 79 | !, smt_add_predicate_aux(Solver,Expr,Symbol)). | |
| 80 | smt_add_predicate_to_solver(Solver,_,_,_,_) :- % in case the predicate contains unsupported types, etc. | |
| 81 | smt_solver_interface_call(Solver,pop_frame). | |
| 82 | ||
| 83 | contains_introduced_identifiers(FreeIDs,TExpr) :- | |
| 84 | syntaxtraversion(TExpr,_,Type,Infos,Subs,_), | |
| 85 | (member(introduced_by(_),Infos) % identifier that has been introduced | |
| 86 | -> % check if it is not bound by some quantifiers | |
| 87 | get_texpr_id(TExpr,Identifier), | |
| 88 | member(b(identifier(Identifier),Type,_),FreeIDs) | |
| 89 | ; some(contains_introduced_identifiers(FreeIDs),Subs)). | |
| 90 | ||
| 91 | smt_add_predicate_aux(Solver,Expr,Symbol) :- | |
| 92 | get_preference(time_out,TO), | |
| 93 | QuickTO is TO // 100, | |
| 94 | % smt solver is called multiple times anyway | |
| 95 | % and keeps its state inbetween | |
| 96 | % thus we can use only a fraction of the time_out | |
| 97 | % after e.g. 100 predicates, the whole timeout will be spent. | |
| 98 | smt_solver_interface_call(Solver,add_interpreter_constraint(Expr,Symbol,QuickTO,SMTResult)), | |
| 99 | (SMTResult = unsat(Core) -> % inconsistency detected | |
| 100 | debug_format(9,'z3: false with core: ~w~n',[Core]), | |
| 101 | store_core_for_backjumping(Core), | |
| 102 | fail ; | |
| 103 | otherwise -> true). | |
| 104 | smt_add_predicate_aux(Solver,_,_) :- | |
| 105 | % remove frame upon backtracking | |
| 106 | smt_solver_interface_call(Solver,pop_frame), fail. | |
| 107 | ||
| 108 | :- dynamic backjumping_symbols/1. | |
| 109 | store_core_for_backjumping(Core) :- | |
| 110 | retractall(backjumping_symbols(_)), | |
| 111 | cleanup_core_for_backjumping(Core,CleanCore), | |
| 112 | assert(backjumping_symbols(CleanCore)). | |
| 113 | cleanup_core_for_backjumping([],[]). | |
| 114 | cleanup_core_for_backjumping([E|Es],[CE|CEs]) :- | |
| 115 | tools:split_atom(E,['|'],[CE]), | |
| 116 | cleanup_core_for_backjumping(Es,CEs). | |
| 117 | ||
| 118 | backjump_on_symbol(Symbol) :- | |
| 119 | backjumping_symbols(Symbols), | |
| 120 | member(Symbol,Symbols), | |
| 121 | debug_format(9,'smt check for backjump:~ncurrent symbol: ~w~nbackjumping symbols: ~w~n',[Symbol,Symbols]), | |
| 122 | !, debug_format(9,'backjumping!',[]), fail. | |
| 123 | backjump_on_symbol(_) :- | |
| 124 | retractall(backjumping_symbols(_)). | |
| 125 | ||
| 126 | ||
| 127 | :- use_module(probsrc(specfile),[state_corresponds_to_set_up_constants/2]). | |
| 128 | :- use_module(probsrc(state_space),[visited_expression/2]). | |
| 129 | :- use_module(probsrc(error_manager),[add_internal_error/2]). | |
| 130 | % solve in a state stored in the state space | |
| 131 | smt_solve_predicate_in_state(StateID,Solver,Pred,SolutionState,Result) :- | |
| 132 | visited_expression(StateID,StateExpr), | |
| 133 | state_corresponds_to_set_up_constants(StateExpr,FullStore), | |
| 134 | !, | |
| 135 | append(FullStore,SolutionState,SMTState), | |
| 136 | smt_solve_predicate(Solver,Pred,SMTState,Result). | |
| 137 | smt_solve_predicate_in_state(StateID,Solver,Pred,SolutionState,Result) :- | |
| 138 | (StateID=root -> true | |
| 139 | ; add_internal_error('Illegal state:',smt_solve_predicate_in_state(StateID,Solver,Pred,SolutionState,Result))), | |
| 140 | smt_solve_predicate(Solver,Pred,SolutionState,Result). | |
| 141 | ||
| 142 | smt_solve_predicate(Solver,Pred,State,Result) :- | |
| 143 | get_texpr_type(Pred,pred), | |
| 144 | clean_up(Pred,CPred), !, | |
| 145 | catch(smt_solve_predicate_aux(Solver,CPred,State,Result), | |
| 146 | SolverException, % exception most likely happened in the setup phase; in check_sat the exceptions are caught | |
| 147 | treat_exception(Solver,SolverException,Result)). | |
| 148 | ||
| 149 | % not a predicate or cleanup failed | |
| 150 | smt_solve_predicate(_,_,_,error). | |
| 151 | ||
| 152 | % remove bindings from environment which are not relevant | |
| 153 | % (otherwise we get errors like z3exception in get_string: invalid usage) | |
| 154 | remove_useless_bindings(X,_,Res) :- var(X),!,Res=X. | |
| 155 | remove_useless_bindings([],_,[]). | |
| 156 | remove_useless_bindings([bind(Var,Val)|T],Ids,Res) :- | |
| 157 | (get_texpr_id(TVar,Var),member(TVar,Ids) -> Res = [bind(Var,Val)|RT] ; Res=RT), | |
| 158 | remove_useless_bindings(T,Ids,RT). | |
| 159 | ||
| 160 | smt_solve_predicate_aux(Solver,Pred,_,Result) :- | |
| 161 | contains_unsupported_type_or_expression(Solver,Pred,Un), !, | |
| 162 | Result = no_solution_found(unsupported_type_or_expression(Un)). | |
| 163 | smt_solve_predicate_aux(Solver,Pred,ProBState,Result) :- | |
| 164 | reset_interface(Solver) -> | |
| 165 | find_typed_identifier_uses(Pred,Identifiers), | |
| 166 | remove_useless_bindings(ProBState,Identifiers,ProBState2), | |
| 167 | create_state_pred(Identifiers,[],ProBState2,StatePred), | |
| 168 | conjunction_to_list(StatePred,StatePredConjuncts), | |
| 169 | exclude(contains_unsupported_type_or_expression(Solver),StatePredConjuncts,FilteredStatePredConjuncts), | |
| 170 | conjunct_predicates(FilteredStatePredConjuncts,FilteredStatePred), | |
| 171 | conjunct_predicates([FilteredStatePred,Pred],FullPred), | |
| 172 | ||
| 173 | setup_sets(Solver,GlobalIdentifiers), | |
| 174 | create_smt_state(Solver,Identifiers,IdentifierState,_), | |
| 175 | append(IdentifierState,GlobalIdentifiers,GlobalState), | |
| 176 | ||
| 177 | % trace, | |
| 178 | mk_expr(FullPred,Solver,[],GlobalState,PExpr), | |
| 179 | ||
| 180 | translate_bexpression(FullPred,PPPred), | |
| 181 | debug_format(9,'Sending to ~w:~w~n',[Solver,PPPred]), | |
| 182 | flush_output, | |
| 183 | (debug:debug_mode(off) -> true ; pretty_print_smt(Solver,PExpr)), | |
| 184 | !, % all preparations done, cut before calling solver | |
| 185 | % to avoid backtracking into setup and finding solutions twice | |
| 186 | catch(check_sat(Solver,PExpr,ProBState2,GlobalState,Identifiers,Result), | |
| 187 | model_translation_failed, Result = no_solution_found(model_translation_failed)) | |
| 188 | ; Result = no_solution_found(solver_not_available). | |
| 189 | smt_solve_predicate_aux(_,_Pred,_,no_solution_found(translation_or_setup_failed)). | |
| 190 | ||
| 191 | mk_expr_skip(Solver,Pred,[],GlobalState,Expr) :- | |
| 192 | clean_up(Pred,CPred), !, | |
| 193 | conjunction_to_list(CPred,List), | |
| 194 | exclude(contains_unsupported_type_or_expression(Solver),List,NList), | |
| 195 | conjunct_predicates(NList,NewCPred), | |
| 196 | mk_expr(NewCPred,Solver,[],GlobalState,Expr). | |
| 197 | mk_expr_skip(_,Pred,_,_,_) :- !, | |
| 198 | add_error_fail(smt_solvers_interface,'mk_expr_skip failed',Pred). | |
| 199 | ||
| 200 | check_sat(Solver,Expr,ProBState,State,Identifiers,Result) :- | |
| 201 | catch(check_sat_aux(Solver,Expr,ProBState,State,Identifiers,Result), | |
| 202 | SolverException, | |
| 203 | treat_exception(Solver,SolverException,Result)). | |
| 204 | treat_exception(Solver,Exc,Result) :- known_solver_exception(Exc,Reason),!, | |
| 205 | reset_interface(Solver),Result = no_solution_found(Reason). | |
| 206 | treat_exception(Solver,Exc,_) :- format('Unknown exception in solver ~w: ~w~n',[Solver,Exc]), | |
| 207 | throw(Exc). | |
| 208 | known_solver_exception(z3_exception(Reason),Reason). | |
| 209 | known_solver_exception(logic_exception(Reason),Reason). | |
| 210 | ||
| 211 | check_sat_aux(Solver,Expr,ProBState,State,Identifiers,Result) :- | |
| 212 | get_preference(time_out,TO), | |
| 213 | smt_solver_interface_call(Solver,query(Expr,TO,SMTResult)), | |
| 214 | get_model_or_return_result(SMTResult,Solver,Expr,ProBState,State,Identifiers,Result). | |
| 215 | ||
| 216 | get_model_or_return_result(unsat,_,_,_,_,_,contradiction_found). | |
| 217 | get_model_or_return_result(unknown,_,_,_,_,_,no_solution_found(solver_answered_unknown)). | |
| 218 | get_model_or_return_result(time_out,_,_,_,_,_,time_out). | |
| 219 | get_model_or_return_result(sat,Solver,_,ProBState,State,Identifiers,solution(Bindings)) :- | |
| 220 | exclude(is_smt_temp_var,Identifiers,FilteredIDs), | |
| 221 | (translate_smt_model_to_b_values(Solver,State,FilteredIDs,Bindings) | |
| 222 | -> (maplist(bind_in_prob_state(Bindings),ProBState) -> true | |
| 223 | ; throw(model_solution_extraction_failed) | |
| 224 | ) | |
| 225 | ; throw(model_translation_failed)). | |
| 226 | get_model_or_return_result(sat,Solver,Expr,ProBState,State,Identifiers,Result) :- | |
| 227 | next_result(Solver,Expr,ProBState,State,Identifiers,Result). | |
| 228 | ||
| 229 | bind_in_prob_state(Bindings,bind(Id,Val)) :- | |
| 230 | member(binding(Id,Z3Val,_),Bindings), %format('~w: ~w = ~w~n',[Id,Z3Val,Val]),nl, | |
| 231 | % Z3 may return solution in list form, ProB had it in AVL form: hence use equal_object | |
| 232 | kernel_objects:equal_object(Z3Val,Val). | |
| 233 | ||
| 234 | % no global identifiers -> no other solution | |
| 235 | next_result(_,_,_,_,[],Result) :- !, | |
| 236 | Result = contradiction_found. | |
| 237 | next_result(Solver,Expr,ProBState,State,Identifiers,Result) :- | |
| 238 | findall(Id,member(id(_,Id),State),ExprIds), | |
| 239 | smt_solver_interface_call(Solver,conjoin_negated_state(ExprIds,Expr,NewExpr)), | |
| 240 | check_sat(Solver,NewExpr,ProBState,State,Identifiers,Result). | |
| 241 | ||
| 242 | unary_operator(negation). | |
| 243 | unary_operator(unary_minus). | |
| 244 | binary_operator(equivalence). | |
| 245 | binary_operator(implication). | |
| 246 | binary_operator(less). | |
| 247 | binary_operator(less_equal). | |
| 248 | binary_operator(greater). | |
| 249 | binary_operator(greater_equal). | |
| 250 | binary_operator(add). | |
| 251 | binary_operator(modulo). | |
| 252 | binary_operator(minus). | |
| 253 | binary_operator(multiplication). | |
| 254 | binary_operator(div). | |
| 255 | binary_operator(power_of). | |
| 256 | binary_operator(member). | |
| 257 | binary_operator(subset). | |
| 258 | binary_operator(union). | |
| 259 | binary_operator(intersection). | |
| 260 | binary_operator(set_subtraction). | |
| 261 | ||
| 262 | mk_expr_maplist(Solver,LS,GS,Op,Expr) :- | |
| 263 | mk_expr(Op,Solver,LS,GS,Expr). | |
| 264 | ||
| 265 | mk_expr(b(Op,Type,_Infos),Solver,LS,GS,Expr) :- | |
| 266 | mk_expr_aux(Op,Type,Solver,LS,GS,Expr). | |
| 267 | ||
| 268 | % unary operators | |
| 269 | mk_expr_aux(Op,_,Solver,LS,GS,Expr) :- | |
| 270 | Op =.. [Functor,A], | |
| 271 | unary_operator(Functor), !, | |
| 272 | mk_expr(A,Solver,LS,GS,AE), | |
| 273 | smt_solver_interface_call(Solver,mk_op_arglist(Functor,[AE],Expr)). | |
| 274 | % binary operators | |
| 275 | mk_expr_aux(Op,_,Solver,LS,GS,Expr) :- | |
| 276 | Op =.. [Functor,A,B], | |
| 277 | binary_operator(Functor), !, | |
| 278 | mk_expr(A,Solver,LS,GS,AE), mk_expr(B,Solver,LS,GS,BE), | |
| 279 | smt_solver_interface_call(Solver,mk_op(Functor,AE,BE,Expr)). | |
| 280 | % conjunct and disjunct are deconstructed to lists | |
| 281 | mk_expr_aux(conjunct(A,B),pred,Solver,LS,GS,Expr) :- !, | |
| 282 | conjunction_to_list(b(conjunct(A,B),pred,[]),List), | |
| 283 | maplist(mk_expr_maplist(Solver,LS,GS),List,ExprList), | |
| 284 | % truth/0 are removed from the conjunction during list / from list | |
| 285 | % the list might be empty now! | |
| 286 | (ExprList = [] -> smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)) ; | |
| 287 | ExprList = [X] -> Expr = X ; | |
| 288 | otherwise -> smt_solver_interface_call(Solver,mk_op_arglist(conjunct,ExprList,Expr))). | |
| 289 | mk_expr_aux(disjunct(A,B),pred,Solver,LS,GS,Expr) :- !, | |
| 290 | disjunction_to_list(b(disjunct(A,B),pred,[]),List), | |
| 291 | maplist(mk_expr_maplist(Solver,LS,GS),List,ExprList), | |
| 292 | smt_solver_interface_call(Solver,mk_op_arglist(disjunct,ExprList,Expr)). | |
| 293 | % special case for if then else | |
| 294 | mk_expr_aux(if_then_else(Pred,A,B),_,Solver,LS,GS,Expr) :- !, | |
| 295 | maplist(mk_expr_maplist(Solver,LS,GS),[Pred,A,B],ArgList), | |
| 296 | smt_solver_interface_call(Solver,mk_op_arglist(if_then_else,ArgList,Expr)). | |
| 297 | % special case for partition | |
| 298 | mk_expr_aux(partition(S,Sets),pred,Solver,LS,GS,Expr) :- !, | |
| 299 | % definition: sets are disjoint and S is the union | |
| 300 | maplist(mk_expr_maplist(Solver,LS,GS),Sets,SetExprs), | |
| 301 | pairwise_union(SetExprs,Solver,UnionOfSets), | |
| 302 | mk_expr(S,Solver,LS,GS,SExpr), | |
| 303 | smt_solver_interface_call(Solver,mk_op(equal,SExpr,UnionOfSets,EqualToUnion)), % S = Union(Sets) | |
| 304 | % enforce sets pairwise disjoint (= intersection is empty) | |
| 305 | get_texpr_type(S,Type), | |
| 306 | smt_solver_interface_call(Solver,mk_empty_set(Type,EmptySet)), | |
| 307 | pairwise_disjoint(SetExprs,Solver,EmptySet,PWConstraint), | |
| 308 | smt_solver_interface_call(Solver,mk_op_arglist(conjunct,[EqualToUnion,PWConstraint],Expr)). | |
| 309 | % quantifiers | |
| 310 | mk_expr_aux(forall(IDs,b(truth,pred,_),B),pred,Solver,LS,GS,Expr) :- !, | |
| 311 | create_bounded_smt_state(Solver,IDs,State,SMTExprs), | |
| 312 | append(State,LS,NLS), | |
| 313 | mk_expr(B,Solver,NLS,GS,BE), | |
| 314 | smt_solver_interface_call(Solver,mk_quantifier(forall,SMTExprs,BE,Expr)). | |
| 315 | mk_expr_aux(forall(IDs,A,B),pred,Solver,LS,GS,Expr) :- !, | |
| 316 | create_bounded_smt_state(Solver,IDs,State,SMTExprs), | |
| 317 | append(State,LS,NLS), | |
| 318 | mk_expr(A,Solver,NLS,GS,AE), mk_expr(B,Solver,NLS,GS,BE), | |
| 319 | smt_solver_interface_call(Solver,mk_op(implication,AE,BE,InnerExpr)), | |
| 320 | smt_solver_interface_call(Solver,mk_quantifier(forall,SMTExprs,InnerExpr,Expr)). | |
| 321 | mk_expr_aux(exists(IDs,B),pred,Solver,LS,GS,Expr) :- !, | |
| 322 | create_bounded_smt_state(Solver,IDs,State,SMTExprs), | |
| 323 | append(State,LS,NLS), | |
| 324 | mk_expr(B,Solver,NLS,GS,InnerExpr), | |
| 325 | smt_solver_interface_call(Solver,mk_quantifier(exists,SMTExprs,InnerExpr,Expr)). | |
| 326 | % equality is a special case as it needs to distinguish | |
| 327 | % booleans and other types | |
| 328 | mk_expr_aux(equal(A,B),pred,Solver,LS,GS,Expr) :- !, | |
| 329 | mk_expr(A,Solver,LS,GS,AE), mk_expr(B,Solver,LS,GS,BE), | |
| 330 | get_texpr_type(A,Type), | |
| 331 | (Type = boolean -> smt_solver_interface_call(Solver,mk_op(equivalence,AE,BE,Expr)) ; | |
| 332 | otherwise -> smt_solver_interface_call(Solver,mk_op(equal,AE,BE,Expr))). | |
| 333 | % records | |
| 334 | mk_expr_aux(rec(ListOfFields),Type,Solver,LS,GS,Expr) :- !, | |
| 335 | findall(FieldExpr, member(field(_,FieldExpr),ListOfFields), FieldExprs), | |
| 336 | maplist(mk_expr_maplist(Solver,LS,GS),FieldExprs,SMTFieldExprs), | |
| 337 | smt_solver_interface_call(Solver,mk_record_const(Type,SMTFieldExprs,Expr)). | |
| 338 | mk_expr_aux(record_field(Record,FieldName),Type,Solver,LS,GS,Expr) :- !, | |
| 339 | get_texpr_type(Record,record(RFields)), | |
| 340 | nth0(FieldNr,RFields,field(FieldName,Type)), | |
| 341 | % debug_format(9,'Field: ~w Type: ~w~n-> FieldNr: ~w~n',[FieldName,RFields,FieldNr]), | |
| 342 | mk_expr(Record,Solver,LS,GS,SMTRecordExpr), | |
| 343 | smt_solver_interface_call(Solver,mk_record_field(SMTRecordExpr,FieldNr,FieldName,Expr)). | |
| 344 | % couple construction | |
| 345 | mk_expr_aux(couple(A,B),Type,Solver,LS,GS,Expr) :- !, | |
| 346 | mk_expr(A,Solver,LS,GS,AE), mk_expr(B,Solver,LS,GS,BE), | |
| 347 | smt_solver_interface_call(Solver,mk_couple(Type,AE,BE,Expr)). | |
| 348 | % constants and identifiers | |
| 349 | mk_expr_aux(identifier(Id),_,_Solver,LS,GS,Expr) :- !, | |
| 350 | lookup(Id,LS,GS,Expr). | |
| 351 | mk_expr_aux(integer(Int),integer,Solver,_LS,_GS,Expr) :- !, | |
| 352 | smt_solver_interface_call(Solver,mk_int_const(Int,Expr)). | |
| 353 | mk_expr_aux(min_int,integer,Solver,_LS,_GS,Expr) :- !, | |
| 354 | get_preference(minint,MinInt), | |
| 355 | smt_solver_interface_call(Solver,mk_int_const(MinInt,Expr)). | |
| 356 | mk_expr_aux(max_int,integer,Solver,_LS,_GS,Expr) :- !, | |
| 357 | get_preference(maxint,MaxInt), | |
| 358 | smt_solver_interface_call(Solver,mk_int_const(MaxInt,Expr)). | |
| 359 | mk_expr_aux(boolean_true,boolean,Solver,_LS,_GS,Expr) :- !, | |
| 360 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)). | |
| 361 | mk_expr_aux(boolean_false,boolean,Solver,_LS,_GS,Expr) :- !, | |
| 362 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,Expr)). | |
| 363 | mk_expr_aux(string(S),string,Solver,_LS,_GS,Expr) :- !, | |
| 364 | smt_solver_interface_call(Solver,mk_string_const(S,Expr)). | |
| 365 | mk_expr_aux(truth,pred,Solver,_LS,_GS,Expr) :- !, | |
| 366 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)). | |
| 367 | mk_expr_aux(falsity,pred,Solver,_LS,_GS,Expr) :- !, | |
| 368 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,Expr)). | |
| 369 | mk_expr_aux(bool_set,set(boolean),Solver,_LS,_GS,Expr) :- !, | |
| 370 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,True)), | |
| 371 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,False)), | |
| 372 | smt_solver_interface_call(Solver,mk_set([True,False],Expr)). | |
| 373 | mk_expr_aux(set_extension(List),set(T),Solver,LS,GS,Expr) :- !, | |
| 374 | maplist(mk_expr_maplist(Solver,LS,GS),List,SubExprs), | |
| 375 | (SubExprs = [] -> smt_solver_interface_call(Solver,mk_empty_set(set(T),Expr)) ; | |
| 376 | otherwise -> smt_solver_interface_call(Solver,mk_set(SubExprs,Expr))). | |
| 377 | mk_expr_aux(empty_set,Type,Solver,_LS,_GS,Expr) :- !, | |
| 378 | smt_solver_interface_call(Solver,mk_empty_set(Type,Expr)). | |
| 379 | % given values | |
| 380 | mk_expr_aux(value(V),Type,Solver,LS,GS,Expr) :- !, | |
| 381 | mk_value(Type,V,Solver,LS,GS,Expr). | |
| 382 | % ast nodes that can be ignored | |
| 383 | mk_expr_aux(convert_bool(P),boolean,Solver,LS,GS,Expr) :- !, | |
| 384 | mk_expr(P,Solver,LS,GS,Expr). | |
| 385 | % lets | |
| 386 | mk_expr_aux(let_expression(ListOfIDs,ListOfDefinitions,LetExpression),_Type,Solver,LS,GS,Expr) :- | |
| 387 | create_let_state(ListOfIDs,ListOfDefinitions,Solver,LS,GS,NewLS), | |
| 388 | mk_expr(LetExpression,Solver,NewLS,GS,Expr). | |
| 389 | mk_expr_aux(let_predicate(ListOfIDs,ListOfDefinitions,LetExpression),pred,Solver,LS,GS,Expr) :- | |
| 390 | create_let_state(ListOfIDs,ListOfDefinitions,Solver,LS,GS,NewLS), | |
| 391 | mk_expr(LetExpression,Solver,NewLS,GS,Expr). | |
| 392 | % error case | |
| 393 | mk_expr_aux(Expr,_,_,_,_,_) :- !, | |
| 394 | add_error_fail(smt_solvers_interface,'mk_expr failed',Expr). | |
| 395 | ||
| 396 | create_let_state([],[],_,S,_,S). | |
| 397 | create_let_state([ID|IDs],[Def|Defs],Solver,StateSoFar,GS,State) :- | |
| 398 | get_texpr_id(ID,UnwrappedId), | |
| 399 | mk_expr(Def,Solver,StateSoFar,GS,Expr), | |
| 400 | create_let_state(IDs,Defs,Solver,[id(UnwrappedId,Expr)|StateSoFar],GS,State). | |
| 401 | ||
| 402 | mk_value_maplist(Type,Solver,LS,GS,Val,Expr) :- | |
| 403 | mk_value(Type,Val,Solver,LS,GS,Expr). | |
| 404 | mk_value(integer,int(Int),Solver,_LS,_GS,Expr) :- | |
| 405 | smt_solver_interface_call(Solver,mk_int_const(Int,Expr)). | |
| 406 | mk_value(boolean,pred_false,Solver,_LS,_GS,Expr) :- | |
| 407 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,Expr)). | |
| 408 | mk_value(boolean,pred_true,Solver,_LS,_GS,Expr) :- | |
| 409 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)). | |
| 410 | % only supported thanks to z3 full sets | |
| 411 | mk_value(set(integer),global_set('INTEGER'),z3,_LS,_GS,Expr) :- | |
| 412 | smt_solver_interface_call(z3,mk_full_set(set(integer),Expr)). | |
| 413 | mk_value(set(global(X)),global_set(X),_Solver,LS,GS,Expr) :- | |
| 414 | lookup(X,LS,GS,Expr). | |
| 415 | mk_value(set(X),avl_set(Val),Solver,LS,GS,Expr) :- | |
| 416 | expand_custom_set_to_list_now(avl_set(Val),Values), | |
| 417 | mk_value(set(X),Values,Solver,LS,GS,Expr). | |
| 418 | mk_value(set(X),List,Solver,LS,GS,Expr) :- | |
| 419 | maplist(mk_value_maplist(X,Solver,LS,GS),List,SubExprs), | |
| 420 | (SubExprs = [] -> smt_solver_interface_call(Solver,mk_empty_set(set(X),Expr)) ; | |
| 421 | otherwise -> smt_solver_interface_call(Solver,mk_set(SubExprs,Expr))). | |
| 422 | mk_value(couple(AT,BT),(A,B),Solver,LS,GS,Expr) :- | |
| 423 | mk_value(AT,A,Solver,LS,GS,AE), | |
| 424 | mk_value(BT,B,Solver,LS,GS,BE), | |
| 425 | smt_solver_interface_call(Solver,mk_couple(couple(AT,BT),AE,BE,Expr)). | |
| 426 | mk_value(global(Name),fd(Num,Name),_Solver,LS,GS,Expr) :- | |
| 427 | is_b_global_constant(Name,Num,Constant), | |
| 428 | lookup(Constant,LS,GS,Expr). | |
| 429 | % error case | |
| 430 | mk_value(Type,Value,_,_,_,_) :- !, | |
| 431 | add_error_fail(smt_solvers_interface,'mk_value failed',[Type,Value]). | |
| 432 | ||
| 433 | pairwise_union([S],_Solver,S) :- !. | |
| 434 | pairwise_union([S|Sets],Solver,Expr) :- | |
| 435 | pairwise_union(Sets,Solver,SS), | |
| 436 | smt_solver_interface_call(Solver,mk_op(union,S,SS,Expr)). | |
| 437 | ||
| 438 | pairwise_disjoint([H,T],Solver,EmptySet,Constraint) :- !, | |
| 439 | pairwise_disjoint_mk_expr(Solver,H,T,EmptySet,Constraint). | |
| 440 | pairwise_disjoint([H|T],Solver,EmptySet,Constraint) :- | |
| 441 | pairwise_disjoint(H,T,Solver,EmptySet,SubConstraints), | |
| 442 | pairwise_disjoint(T,Solver,EmptySet,SubConstraint), | |
| 443 | smt_solver_interface_call(Solver,mk_op_arglist(conjunct,[SubConstraint|SubConstraints],Constraint)). | |
| 444 | ||
| 445 | pairwise_disjoint(E,[Last],Solver,EmptySet,[C]) :- !, | |
| 446 | pairwise_disjoint_mk_expr(Solver,E,Last,EmptySet,C). | |
| 447 | pairwise_disjoint(E,[H|T],Solver,EmptySet,[C|Cs]) :- | |
| 448 | pairwise_disjoint_mk_expr(Solver,E,H,EmptySet,C), | |
| 449 | pairwise_disjoint(E,T,Solver,EmptySet,Cs). | |
| 450 | ||
| 451 | pairwise_disjoint_mk_expr(Solver,A,B,EmptySet,PWConstraint) :- | |
| 452 | smt_solver_interface_call(Solver,mk_op(intersection,A,B,Inter)), | |
| 453 | smt_solver_interface_call(Solver,mk_op(equal,Inter,EmptySet,PWConstraint)). | |
| 454 | ||
| 455 | mk_sort(Solver,Set) :- | |
| 456 | smt_solver_interface_call(Solver,mk_sort(Set)). | |
| 457 | ||
| 458 | setup_sets(Solver,GlobalIdentifiers) :- | |
| 459 | % deferred sets -> only create a sort | |
| 460 | findall(X,b_global_deferred_set(X),DeferredSets), | |
| 461 | maplist(mk_sort(Solver),DeferredSets), | |
| 462 | mk_deferred_set_identifiers(Solver,DeferredSets,DefSetIdentifiers), | |
| 463 | % enumerated sets -> create a sort | |
| 464 | % & set up distinct identifiers | |
| 465 | b_get_global_enumerated_sets(EnumeratedSets), | |
| 466 | % can not use setof / bagof for some reason | |
| 467 | list_to_set(EnumeratedSets,EnumeratedSetsNoDuplicates), | |
| 468 | maplist(setup_enumerated_set(Solver),EnumeratedSetsNoDuplicates,IdentifierLists), | |
| 469 | append([DefSetIdentifiers|IdentifierLists],GlobalIdentifiers). | |
| 470 | ||
| 471 | % currently only functional for z3 | |
| 472 | mk_deferred_set_identifiers(cvc4,_,[]). | |
| 473 | mk_deferred_set_identifiers(z3,DeferredSets,DefSetIdentifiers) :- | |
| 474 | maplist(mk_deferred_set_identifiers2,DeferredSets,DefSetIdentifiers). | |
| 475 | mk_deferred_set_identifiers2(SetName,id(SetName,SetExpression)) :- | |
| 476 | smt_solver_interface_call(z3,mk_full_set(set(global(SetName)),SetExpression)). | |
| 477 | setup_enumerated_set(Solver,SetName,[SetIdentifier|Identifiers]) :- | |
| 478 | % find all global constants belonging to the given set | |
| 479 | findall(b(identifier(Cst),global(SetName),[]), | |
| 480 | is_b_global_constant(SetName,_,Cst), | |
| 481 | SetElements), | |
| 482 | b_global_set_cardinality(SetName,Cardinality), | |
| 483 | % make a new sort and create identifiers | |
| 484 | smt_solver_interface_call(Solver,mk_sort_with_cardinality(SetName,Cardinality)), | |
| 485 | create_smt_state(Solver,SetElements,Identifiers,Exprs), | |
| 486 | smt_solver_interface_call(Solver,setup_enumerated_set(Exprs)), | |
| 487 | SetIdentifier = id(SetName,SetExpression), | |
| 488 | smt_solver_interface_call(Solver,mk_set(Exprs,SetExpression)). | |
| 489 | ||
| 490 | create_smt_state(Solver,Identifiers,State,Exprs) :- | |
| 491 | exclude(is_external_function_identifier,Identifiers,LessIdentifiers), | |
| 492 | maplist(create_smt_identifier(Solver),LessIdentifiers,State,Exprs). | |
| 493 | create_bounded_smt_state(Solver,Identifiers,State,Exprs) :- | |
| 494 | maplist(create_bounded_smt_identifier(Solver),Identifiers,State,Exprs). | |
| 495 | create_smt_identifier(Solver,b(identifier(Id),Type,_Infos),id(Id,Expr),Expr) :- | |
| 496 | smt_solver_interface_call(Solver,mk_var(Type,Id,Expr)). | |
| 497 | create_bounded_smt_identifier(Solver,b(identifier(Id),Type,_Infos),id(Id,Expr),Expr) :- | |
| 498 | smt_solver_interface_call(Solver,mk_bounded_var(Type,Id,Expr)). | |
| 499 | ||
| 500 | is_external_function_identifier(Id) :- | |
| 501 | get_texpr_id(Id,Name), | |
| 502 | is_external_function_name(Name). | |
| 503 | ||
| 504 | lookup(Id,[],[id(Id,Expr)|_],Expr) :- !. | |
| 505 | lookup(Id,[],[_|T],Expr) :- lookup(Id,[],T,Expr). | |
| 506 | lookup(Id,[id(Id,Expr)|_],_,Expr) :- !. | |
| 507 | lookup(Id,[_|T],GS,Expr) :- lookup(Id,T,GS,Expr). | |
| 508 | ||
| 509 | contains_unsupported_type_or_expression(Solver,TExpr) :- | |
| 510 | contains_unsupported_type_or_expression(Solver,TExpr,_). | |
| 511 | contains_unsupported_type_or_expression(Solver,TExpr,Unsupported) :- | |
| 512 | % TODO: shouldnt this expansion by done automatically, | |
| 513 | % because map_over_typed_bexpr is a meta-predicate? | |
| 514 | map_over_typed_bexpr(smt_solvers_interface:contains_unsupported_aux(Solver),TExpr,Unsupported). | |
| 515 | :- public contains_unsupported_aux/3. | |
| 516 | contains_unsupported_aux(Solver,TExpr,Expr) :- | |
| 517 | get_texpr_expr(TExpr,Expr), | |
| 518 | get_texpr_type(TExpr,Type), | |
| 519 | unsupported_expr_or_type(Expr,Type,Solver). | |
| 520 | ||
| 521 | % these expressions are not supported at all | |
| 522 | unsupported_expr_or_type(general_union(_),_,_). | |
| 523 | unsupported_expr_or_type(general_intersection(_),_,_). | |
| 524 | unsupported_expr_or_type(general_product(_,_,_),_,_). | |
| 525 | unsupported_expr_or_type(general_sum(_,_,_),_,_). | |
| 526 | unsupported_expr_or_type(composition(_,_),_,_). | |
| 527 | unsupported_expr_or_type(first_of_pair(_),_,_). | |
| 528 | unsupported_expr_or_type(second_of_pair(_),_,_). | |
| 529 | unsupported_expr_or_type(iteration(_,_),_,_). | |
| 530 | unsupported_expr_or_type(closure(_),_,_). | |
| 531 | unsupported_expr_or_type(pow_subset(_),_,_). | |
| 532 | unsupported_expr_or_type(pow1_subset(_),_,_). | |
| 533 | unsupported_expr_or_type(fin_subset(_),_,_). | |
| 534 | unsupported_expr_or_type(fin1_subset(_),_,_). | |
| 535 | unsupported_expr_or_type(external_pred_call(_,_),_,_). | |
| 536 | unsupported_expr_or_type(external_function_call(_,_),_,_). | |
| 537 | unsupported_expr_or_type(function(Name,_),_,_) :- | |
| 538 | is_external_function_name(Name). | |
| 539 | % the following exprs should have been removed by a rewrite rule | |
| 540 | unsupported_expr_or_type(min(_),_,_). | |
| 541 | unsupported_expr_or_type(max(_),_,_). | |
| 542 | unsupported_expr_or_type(card(_),_,_). | |
| 543 | unsupported_expr_or_type(finite(_),_,_). | |
| 544 | unsupported_expr_or_type(comprehension_set(_,_),_,_). | |
| 545 | unsupported_expr_or_type(interval(_,_),_,_). | |
| 546 | unsupported_expr_or_type(integer_set(_),_,_). | |
| 547 | unsupported_expr_or_type(parallel_product(_,_),_,_). | |
| 548 | unsupported_expr_or_type(direct_product(_,_),_,_). | |
| 549 | unsupported_expr_or_type(domain_restriction(_,_),_,_). | |
| 550 | unsupported_expr_or_type(range_restriction(_,_),_,_). | |
| 551 | unsupported_expr_or_type(domain_subtraction(_,_),_,_). | |
| 552 | unsupported_expr_or_type(range_subtraction(_,_),_,_). | |
| 553 | unsupported_expr_or_type(overwrite(_,_),_,_). | |
| 554 | unsupported_expr_or_type(cartesian_product(_,_),_,_). | |
| 555 | unsupported_expr_or_type(image(_,_),_,_). | |
| 556 | unsupported_expr_or_type(range(_),_,_). | |
| 557 | unsupported_expr_or_type(domain(_),_,_). | |
| 558 | unsupported_expr_or_type(function(_,_),_,_). | |
| 559 | unsupported_expr_or_type(not_equal(_,_),_,_). | |
| 560 | unsupported_expr_or_type(not_member(_,_),_,_). | |
| 561 | unsupported_expr_or_type(relations(_,_),_,_). | |
| 562 | unsupported_expr_or_type(partial_function(_,_),_,_). | |
| 563 | unsupported_expr_or_type(total_function(_,_),_,_). | |
| 564 | unsupported_expr_or_type(partial_injection(_,_),_,_). | |
| 565 | unsupported_expr_or_type(total_injection(_,_),_,_). | |
| 566 | unsupported_expr_or_type(partial_surjection(_,_),_,_). | |
| 567 | unsupported_expr_or_type(total_surjection(_,_),_,_). | |
| 568 | unsupported_expr_or_type(total_relation(_,_),_,_). | |
| 569 | unsupported_expr_or_type(surjection_relation(_,_),_,_). | |
| 570 | unsupported_expr_or_type(total_surjection_relation(_,_),_,_). | |
| 571 | % certain values are not supported yet | |
| 572 | unsupported_expr_or_type(value(X),_,_) :- \+ ground(X). % can not translate unknown values | |
| 573 | unsupported_expr_or_type(value(couple(A,B)),couple(AT,BT),Solver) :- | |
| 574 | unsupported_expr_or_type(value(A),AT,Solver) ; | |
| 575 | unsupported_expr_or_type(value(B),BT,Solver). | |
| 576 | unsupported_expr_or_type(value(closure(_,_,_)),_,_). | |
| 577 | unsupported_expr_or_type(value(global_set('INTEGER')),_,cvc4). | |
| 578 | unsupported_expr_or_type(value(_),Type,_) :- | |
| 579 | unsupported_value_type(Type). | |
| 580 | unsupported_expr_or_type(value(fd(Num,SetName)),global(SetName),_) :- | |
| 581 | \+ is_b_global_constant(SetName,Num,_). % has been invented by prob but is unnamed | |
| 582 | % cvc4 does not support generating a full set of a sort, thus there | |
| 583 | % is currently no way of expressing a complete deferred set | |
| 584 | unsupported_expr_or_type(identifier(SetName),set(global(SetName)),cvc4). | |
| 585 | % some types are not supported / can not be translated at the moment | |
| 586 | unsupported_expr_or_type(_,Type,Solver) :- unsupported_type(Type,Solver). | |
| 587 | unsupported_type(string,z3). | |
| 588 | unsupported_type(any,_). | |
| 589 | unsupported_type(seq(_),_). | |
| 590 | unsupported_type(set(X),S) :- | |
| 591 | unsupported_type(X,S). | |
| 592 | unsupported_type(couple(A,B),S) :- | |
| 593 | unsupported_type(A,S) ; unsupported_type(B,S). | |
| 594 | % currently unsupported values | |
| 595 | unsupported_value_type(set(T)) :- | |
| 596 | unsupported_value_type(T). | |
| 597 | unsupported_value_type(couple(A,B)) :- | |
| 598 | unsupported_value_type(A) ; unsupported_value_type(B). | |
| 599 | unsupported_value_type(global(S)) :- | |
| 600 | unfixed_deferred_set(S). |