| 1 | % (c) 2015-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
| 2 | % Heinrich Heine Universitaet Duesseldorf | |
| 3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
| 4 | ||
| 5 | :- module(smt_solvers_interface, [smt_solve_predicate/4, | |
| 6 | smt_solve_predicate/5, | |
| 7 | smt_solve_predicate_free/3, | |
| 8 | smt_add_predicate/5, | |
| 9 | smt_solve_predicate_in_state/5, | |
| 10 | reset_smt_supported_interpreter/0, | |
| 11 | smt_add_cnf/3, smt_add_extra_clause_cnf/2, smt_solve_cnf/2, smt_reset_cnf/1]). | |
| 12 | ||
| 13 | :- use_module(library(terms), [term_size/2]). | |
| 14 | :- use_module(library(sets), [list_to_set/2]). | |
| 15 | :- use_module(library(lists), [same_length/2,maplist/2, maplist/3, maplist/4, | |
| 16 | append/2, exclude/3, include/3, select/3, | |
| 17 | nth0/3, some/2, is_list/1]). | |
| 18 | :- use_module(probsrc(tools_timeout),[get_time_out_with_factor/2]). | |
| 19 | :- use_module(probsrc(specfile),[get_state_for_b_formula/3]). | |
| 20 | :- use_module(probsrc(debug), [debug_mode/1, debug_level_active_for/1,debug_format/3]). | |
| 21 | :- use_module(probsrc(bmachine), [b_get_machine_set/1]). | |
| 22 | :- use_module(probsrc(kernel_objects), [infer_value_type/2, | |
| 23 | equal_object/2]). | |
| 24 | :- use_module(probsrc(bsyntaxtree), [map_over_typed_bexpr/3, | |
| 25 | safe_create_texpr/4, | |
| 26 | find_typed_identifier_uses/2, | |
| 27 | find_typed_identifier_uses/3, | |
| 28 | get_texpr_type/2, | |
| 29 | get_texpr_expr/2, | |
| 30 | get_texpr_id/2, | |
| 31 | predicate_components_in_scope/3, | |
| 32 | conjunction_to_list/2, | |
| 33 | conjunct_predicates/2, | |
| 34 | disjunction_to_list/2, | |
| 35 | syntaxtraversion/6]). | |
| 36 | :- use_module(probsrc(error_manager), [add_error_fail/3, add_message/2, add_message/3, add_message/4, | |
| 37 | add_error/3, add_internal_error/2, add_warning/3]). | |
| 38 | :- use_module(probsrc(tools), [start_ms_timer/1,stop_ms_timer_with_debug_msg/2,split_atom/3]). | |
| 39 | :- use_module(probsrc(tools_strings), [atom_prefix/2]). | |
| 40 | :- use_module(probsrc(translate), [translate_bexpression/2]). | |
| 41 | :- use_module(probsrc(preferences), [get_preference/2]). | |
| 42 | :- use_module(probsrc(b_interpreter), [b_test_boolean_expression_cs/5]). | |
| 43 | :- use_module(probsrc(tools_meta),[safe_time_out/3]). | |
| 44 | :- use_module(probsrc(b_global_sets), [b_global_deferred_set/1, | |
| 45 | unfixed_deferred_set/1, | |
| 46 | b_get_global_enumerated_sets/1, | |
| 47 | is_b_global_constant/3, | |
| 48 | get_user_defined_scope/4, | |
| 49 | list_contains_unfixed_deferred_set_id/1]). | |
| 50 | :- use_module(probsrc(custom_explicit_sets), [expand_custom_set_to_list_now/2]). | |
| 51 | :- use_module(probsrc(eventhandling),[register_event_listener/3]). | |
| 52 | :- use_module(probsrc(external_functions), [is_external_function_name/1]). | |
| 53 | :- use_module(cdclt_solver('cdclt_preprocessing'), [preprocess_predicate/6]). | |
| 54 | :- use_module(cdclt_solver('cdclt_pred_to_sat'), [predicate_to_sat/6]). | |
| 55 | :- use_module(smt_solvers_interface(model_translation), [translate_smt_model_to_b_values/4, | |
| 56 | consistent_deferred_set_sizes/0, | |
| 57 | store_explicit_set_unique_id/2, | |
| 58 | assert_virtual_deferred_set_id/2]). | |
| 59 | :- use_module(smt_solvers_interface(ast_cleanup_for_smt)). | |
| 60 | :- use_module(smt_solvers_interface(prob_state_predicates), [create_state_pred/4, create_state_pred/5]). | |
| 61 | :- use_module(smt_solvers_interface(solver_dispatcher)). | |
| 62 | :- use_module(smt_solvers_interface(smt_common_predicates)). | |
| 63 | ||
| 64 | :- use_module(probsrc(module_information),[module_info/2]). | |
| 65 | :- module_info(group,smt_solvers). | |
| 66 | :- module_info(description,'This module provides an interface to SMT-solvers like CVC4 or Z3.'). | |
| 67 | ||
| 68 | :- dynamic backjumping_symbols/1, solve_in_state/0. | |
| 69 | ||
| 70 | clear_state :- | |
| 71 | reset_interface(z3), | |
| 72 | garbage_collect, | |
| 73 | trimcore, | |
| 74 | retractall(solve_in_state), | |
| 75 | model_translation:clear_translation_state. | |
| 76 | ||
| 77 | init_smt_supported_interpreter :- | |
| 78 | retractall(backjumping_symbols(_)), %clean smt backjumping information | |
| 79 | (get_preference(smt_supported_interpreter,true) -> init_interface(z3) ; true). | |
| 80 | reset_smt_supported_interpreter :- | |
| 81 | (get_preference(smt_supported_interpreter,true) -> clear_state | |
| 82 | ; true). | |
| 83 | ||
| 84 | :- register_event_listener(start_solving,init_smt_supported_interpreter,'Init Z3 for new solving, clean backjumping'), | |
| 85 | register_event_listener(end_solving,reset_smt_supported_interpreter,'Reset Z3 after solving'). | |
| 86 | ||
| 87 | ||
| 88 | :- block smt_add_predicate(-,?,?,?,?). | |
| 89 | smt_add_predicate(_EnumWf, Pred, ProBLocalState, ProBState, Symbol) :- | |
| 90 | backjump_on_symbol(Symbol), | |
| 91 | smt_add_predicate_to_solver(z3, Pred, ProBLocalState, ProBState, Symbol). | |
| 92 | ||
| 93 | smt_add_predicate_to_solver(Solver, Pred, ProBLocalState, ProBState, Symbol) :- | |
| 94 | init_interface(Solver), | |
| 95 | smt_clean_up_opts(axiomatic, Pred, [instantiate_quantifier_limit(20)], AxmCPred), % constructive translation isn't fully supported by the incremental solver | |
| 96 | find_typed_identifier_uses(AxmCPred, [], Identifiers), | |
| 97 | ( contains_introduced_identifiers(Identifiers, AxmCPred) | |
| 98 | -> debug_format(9, 'z3: skip: ~w~n because there were introduced identifiers', [Symbol]) | |
| 99 | ; smt_solver_interface_call(Solver, push_frame), | |
| 100 | create_state_pred(Identifiers, ProBLocalState, ProBState, StatePred), | |
| 101 | conjunction_to_list(StatePred, StatePredConjuncts), | |
| 102 | exclude(contains_unsupported_type_or_expression(axiomatic, Solver), StatePredConjuncts, FilteredStatePredConjuncts), | |
| 103 | conjunct_predicates(FilteredStatePredConjuncts, FilteredStatePred), | |
| 104 | conjunct_predicates([FilteredStatePred, AxmCPred], FullPred), | |
| 105 | setup_sets(axiomatic, Solver, GlobalIdentifiers), | |
| 106 | create_smt_state(axiomatic, Solver, Identifiers, IdentifierState, _), | |
| 107 | append(IdentifierState, GlobalIdentifiers, GlobalState), | |
| 108 | mk_expr_skip(axiomatic, Solver, FullPred, [], GlobalState, Expr), | |
| 109 | translate_bexpression(FullPred, PPExpr), | |
| 110 | debug_format(9, 'z3: add expr: ~w using symbol: ~w~n', [PPExpr, Symbol]), | |
| 111 | !, | |
| 112 | smt_add_predicate_aux(Solver, Expr, Symbol) | |
| 113 | ). | |
| 114 | smt_add_predicate_to_solver(Solver, _, _, _, _) :- % in case the predicate contains unsupported types, etc. | |
| 115 | smt_solver_interface_call(Solver, pop_frame). | |
| 116 | ||
| 117 | contains_introduced_identifiers(FreeIDs,TExpr) :- | |
| 118 | syntaxtraversion(TExpr,_,Type,Infos,Subs,_), | |
| 119 | (member(introduced_by(_),Infos) % identifier that has been introduced | |
| 120 | -> % check if it is not bound by some quantifiers | |
| 121 | get_texpr_id(TExpr,Identifier), | |
| 122 | member(b(identifier(Identifier),Type,_),FreeIDs) | |
| 123 | ; some(contains_introduced_identifiers(FreeIDs),Subs)). | |
| 124 | ||
| 125 | smt_add_predicate_aux(Solver,Expr,Symbol) :- | |
| 126 | get_preference(time_out,TO), | |
| 127 | QuickTO is TO // 100, | |
| 128 | % smt solver is called multiple times anyway | |
| 129 | % and keeps its state inbetween | |
| 130 | % thus we can use only a fraction of the time_out | |
| 131 | % after e.g. 100 predicates, the whole timeout will be spent. | |
| 132 | smt_solver_interface_call(Solver,add_interpreter_constraint(Expr,Symbol,QuickTO,SMTResult)), | |
| 133 | ( SMTResult = unsat(Core) | |
| 134 | -> % inconsistency detected | |
| 135 | debug_format(9,'z3: false with core: ~w~n',[Core]), | |
| 136 | store_core_for_backjumping(Core), | |
| 137 | fail | |
| 138 | ; true | |
| 139 | ). | |
| 140 | smt_add_predicate_aux(Solver,_,_) :- | |
| 141 | % remove frame upon backtracking | |
| 142 | smt_solver_interface_call(Solver,pop_frame), fail. | |
| 143 | ||
| 144 | store_core_for_backjumping(Core) :- | |
| 145 | retractall(backjumping_symbols(_)), | |
| 146 | cleanup_core_for_backjumping(Core,CleanCore), | |
| 147 | assertz(backjumping_symbols(CleanCore)). | |
| 148 | cleanup_core_for_backjumping([],[]). | |
| 149 | cleanup_core_for_backjumping([E|Es],[CE|CEs]) :- | |
| 150 | split_atom(E,['|'],[CE]), | |
| 151 | cleanup_core_for_backjumping(Es,CEs). | |
| 152 | ||
| 153 | backjump_on_symbol(Symbol) :- | |
| 154 | backjumping_symbols(Symbols), | |
| 155 | member(Symbol,Symbols), | |
| 156 | debug_format(9,'smt check for backjump:~ncurrent symbol: ~w~nbackjumping symbols: ~w~n',[Symbol,Symbols]), | |
| 157 | !, debug_format(9,'backjumping!',[]), fail. | |
| 158 | backjump_on_symbol(_) :- | |
| 159 | retractall(backjumping_symbols(_)). | |
| 160 | ||
| 161 | % solve a predicate freely (without any given state or values) | |
| 162 | smt_solve_predicate_free(SolverName,Pred,Store) :- | |
| 163 | write(solving_with(SolverName)),nl, | |
| 164 | smt_solve_predicate(SolverName, Pred, _, Result), | |
| 165 | write(result(Result)),nl, | |
| 166 | % TODO: provide enumeration warnings / timeouts in other cases | |
| 167 | Result = solution(Bindings), | |
| 168 | maplist(translate_binding,Bindings,Store). | |
| 169 | ||
| 170 | % translate solver binding to ProB interpreter store | |
| 171 | translate_binding(binding(ID,Val,_),bind(ID,Val)). | |
| 172 | ||
| 173 | % solve in a state stored in the state space | |
| 174 | smt_solve_predicate_in_state(StateID, Solver, Pred, SolutionState, Result) :- | |
| 175 | get_state_for_b_formula(StateID, Pred, FullStore), | |
| 176 | !, | |
| 177 | asserta(solve_in_state), | |
| 178 | debug_format(19, 'Solving predicate with ~w in state ~w~n', [Solver,StateID]), | |
| 179 | append(FullStore, SolutionState, SMTState), | |
| 180 | smt_solve_predicate(Solver, Pred, SMTState, Result). | |
| 181 | smt_solve_predicate_in_state(StateID, Solver, _, _, _) :- | |
| 182 | debug_format(19, 'Cannot solve predicate with ~w in state ~w~n', [Solver,StateID]), | |
| 183 | fail. | |
| 184 | ||
| 185 | %% smt_solve_predicate(+SolverName, +Pred, +State, -Result). | |
| 186 | smt_solve_predicate(SolverName, Pred, State, Result) :- | |
| 187 | smt_solve_predicate(SolverName, [check_sat_skeleton(250),instantiate_quantifier_limit(50)], Pred, State, Result). | |
| 188 | ||
| 189 | %% smt_solve_predicate(+Solver, +OptionList, +Pred, +State, -Result). | |
| 190 | % valid options: decompose_into_components, check_sat_skeleton(+TimeOut) | |
| 191 | smt_solve_predicate(SolverName, Options, Pred, State, Result) :- | |
| 192 | translate_solver_name(SolverName,Solver,SelectedTranslations),!, | |
| 193 | get_preference(time_out, TO), | |
| 194 | safe_time_out(smt_solve_predicate6(SelectedTranslations, Solver, Options, Pred, State, TResult), TO, TORes), | |
| 195 | ( TORes == time_out | |
| 196 | -> Result = time_out, | |
| 197 | clear_state | |
| 198 | ; Result = TResult | |
| 199 | ). | |
| 200 | ||
| 201 | translate_solver_name(z3sat,z3,[sat,sat_cdcl]). % specialized SAT solver for QF_FD; runs two SAT solvers in parallel using local search and CDCL | |
| 202 | translate_solver_name(z3axm,z3,[axm_ninc]). % axiomatic translation | |
| 203 | translate_solver_name(z3cns,z3,[cns_ninc]). % constructive translation | |
| 204 | translate_solver_name(z3,z3,T) :- T=[axm_ninc,cns_ninc]. % multithreading of the above | |
| 205 | translate_solver_name(cvc4,cvc4,[axm_inc]). | |
| 206 | translate_solver_name(S,_,_) :- add_internal_error('Unknown solver name: ', S), fail. | |
| 207 | ||
| 208 | %% smt_solve_predicate6(+SelectedSolvers, +Solver, +Options, +Pred, +State, -Result). | |
| 209 | % +Solver is either cvc4 or z3. | |
| 210 | % We provide different translations and solver configurations for Z3, e.g., (non-)incremental. | |
| 211 | % For z3, SelectedSolvers is a list of atoms representing the names of specific solvers | |
| 212 | % defined in the Z3 C++ interface. | |
| 213 | smt_solve_predicate6(SelectedSolvers, Solver, Options, Pred, State, Result) :- | |
| 214 | model_translation:clear_translation_state, | |
| 215 | is_list(SelectedSolvers), | |
| 216 | get_texpr_type(Pred, pred), | |
| 217 | !, | |
| 218 | start_ms_timer(T0), | |
| 219 | smt_clean_up_pre(Pred, State, Options, CPred), | |
| 220 | stop_ms_timer_with_debug_msg(T0,smt_clean_up_pre(Solver,Options)), | |
| 221 | ( CPred = b(truth,pred,_) | |
| 222 | -> Result = solution([]) | |
| 223 | ; CPred = b(falsity,pred,_) | |
| 224 | -> Result = contradiction_found | |
| 225 | ; catch(smt_solve_predicate_aux(SelectedSolvers, Solver, Options, CPred, State, Result), | |
| 226 | SolverException, % exception most likely happened in the setup phase; in check_sat the exceptions are caught | |
| 227 | treat_exception(Solver, SolverException, Result)) | |
| 228 | ). | |
| 229 | % not a predicate or cleanup failed | |
| 230 | smt_solve_predicate6(SelectedSolvers, _, _, _, _, error) :- | |
| 231 | add_internal_error('Unknown solver config: ', SelectedSolvers). | |
| 232 | ||
| 233 | % remove bindings from environment which are not relevant | |
| 234 | % (otherwise we get errors like z3exception in get_model_string: invalid usage) | |
| 235 | remove_useless_bindings(X,_,Res) :- var(X),!,Res=X. | |
| 236 | remove_useless_bindings([],_,[]). | |
| 237 | remove_useless_bindings([bind(Var,Val)|T],Ids,Res) :- | |
| 238 | ( (get_texpr_id(TVar,Var), member(TVar,Ids)) | |
| 239 | -> Res = [bind(Var,Val)|RT] | |
| 240 | ; Res=RT | |
| 241 | ), | |
| 242 | remove_useless_bindings(T,Ids,RT). | |
| 243 | ||
| 244 | filter_unsupported_types_or_expressions(_, _, [], [], []). | |
| 245 | filter_unsupported_types_or_expressions(TranslationType, Solver, [LP|T], FilteredLPs, UnsupportedLPs) :- | |
| 246 | contains_unsupported_type_or_expression(TranslationType, Solver, LP), | |
| 247 | !, | |
| 248 | UnsupportedLPs = [LP|TUnsupportedLPs], | |
| 249 | filter_unsupported_types_or_expressions(TranslationType, Solver, T, FilteredLPs, TUnsupportedLPs). | |
| 250 | filter_unsupported_types_or_expressions(TranslationType, Solver, [LP|T], [LP|TFilteredLPs], UnsupportedLPs) :- | |
| 251 | filter_unsupported_types_or_expressions(TranslationType, Solver, T, TFilteredLPs, UnsupportedLPs). | |
| 252 | ||
| 253 | %% get_full_pred(+TranslationType, +Solver, +Pred, +ProBState, -FullPred, -FullProBState, -Filtered, -SkippedVars, -UnsupportedLPs). | |
| 254 | get_full_pred(TranslationType, Solver, Pred, ProBState, FullPred, FullProBState, Filtered, SkippedVars, UnsupportedLPs) :- | |
| 255 | find_typed_identifier_uses(Pred, Identifiers), | |
| 256 | remove_useless_bindings(ProBState, Identifiers, FullProBState), | |
| 257 | create_state_pred(Identifiers, [], FullProBState, StatePred, [skipped_variables(SkippedVars)]), | |
| 258 | % print(state),nl,translate:nested_print_bexpr(StatePred),nl, | |
| 259 | safe_create_texpr(conjunct(StatePred,Pred), pred, [], FullConj), | |
| 260 | conjunction_to_list(FullConj, LPs), | |
| 261 | filter_unsupported_types_or_expressions(TranslationType, Solver, LPs, FilteredLPs, UnsupportedLPs), | |
| 262 | ( same_length(LPs, FilteredLPs) | |
| 263 | -> Filtered = false | |
| 264 | ; Filtered = true, | |
| 265 | ( debug_mode(off) | |
| 266 | -> true | |
| 267 | ; include(contains_unsupported_type_or_expression(TranslationType, Solver), LPs, Unsupported), | |
| 268 | conjunct_predicates(Unsupported,US), | |
| 269 | add_message(Solver, 'Unsupported constraints were discarded for SMT solver: ', US, US) | |
| 270 | ) | |
| 271 | ), | |
| 272 | conjunct_predicates(FilteredLPs, FullPred). | |
| 273 | ||
| 274 | validate_selected_solvers(cvc4, SelectedSolvers) :- | |
| 275 | SelectedSolvers == [axm_inc], | |
| 276 | !. | |
| 277 | validate_selected_solvers(cvc4, _) :- | |
| 278 | add_error_fail(validate_selected_solvers, 'Only axiomatic translation with incremental solver (axm_inc) available for cvc4.', []). | |
| 279 | validate_selected_solvers(z3, SelectedSolvers) :- | |
| 280 | validate_selected_z3_solvers(SelectedSolvers). | |
| 281 | ||
| 282 | validate_selected_z3_solvers(SelectedSolvers) :- | |
| 283 | AvailableSolvers = [axm_inc,axm_ninc,sat,sat_cdcl,cns_ninc], % see z3interface/main.cpp:available_solvers | |
| 284 | findall(Solver, (member(Solver, SelectedSolvers), \+ member(Solver, AvailableSolvers)), UnavailableSolvers), | |
| 285 | UnavailableSolvers == [], | |
| 286 | !. | |
| 287 | validate_selected_z3_solvers(_) :- | |
| 288 | add_error_fail(validate_selected_z3_solvers, 'At least one selected Z3 solver is not available.', []). | |
| 289 | ||
| 290 | add_translation_for_solver(TranslationType, Solver, ProBState, Pred, Options, TranslationsAcc, NewAcc, IsUnfilteredTruth, Result) :- | |
| 291 | start_ms_timer(T0), | |
| 292 | smt_clean_up_post(TranslationType, Pred, Options, CPred), | |
| 293 | ( CPred = b(truth,pred,_) | |
| 294 | -> Result = solution([]) | |
| 295 | ; CPred = b(falsity,pred,_) | |
| 296 | -> Result = contradiction_found | |
| 297 | ; get_full_pred(TranslationType, Solver, CPred, ProBState, FullPred, FullProBState, Filtered, SkippedVars, UnsupportedLPs), | |
| 298 | stop_ms_timer_with_debug_msg(T0,add_translation_for_solver_preprocessing(TranslationType,Solver)), | |
| 299 | start_ms_timer(T1), | |
| 300 | ( nonvar(FullPred), FullPred = b(truth,pred,_) | |
| 301 | -> % fail if all operators are unsupported | |
| 302 | ( Filtered == false | |
| 303 | -> IsUnfilteredTruth = true, | |
| 304 | NewAcc = TranslationsAcc | |
| 305 | ; add_message(smt_solvers_interface, 'Could not translate predicate for solver: ', Solver:TranslationType), | |
| 306 | add_message(smt_solvers_interface, 'Unsupported predicates: ', UnsupportedLPs), | |
| 307 | fail | |
| 308 | ) | |
| 309 | ; IsUnfilteredTruth = false, | |
| 310 | setup_sets(TranslationType, Solver, GlobalIdentifiers), | |
| 311 | find_typed_identifier_uses(FullPred, Ids), | |
| 312 | create_smt_state(TranslationType, Solver, Ids, IdState, _), | |
| 313 | append(IdState, GlobalIdentifiers, GlobalState), | |
| 314 | mk_expr(FullPred, TranslationType, Solver, [], GlobalState, PExpr), | |
| 315 | %format("~w:~n", [TranslationType]), translate:nested_print_bexpr_as_classicalb(FullAxmPred),nl, | |
| 316 | ( debug:debug_mode(on) | |
| 317 | -> translate_bexpression(FullPred, PPPred), | |
| 318 | format('Sending ~w translation to ~w: ~w~n', [TranslationType,Solver,PPPred]) | |
| 319 | ; true | |
| 320 | ), | |
| 321 | flush_output, | |
| 322 | % comment next line in if you want to directly test ProB on the translated constraint: | |
| 323 | %write(solving_with_prob(TranslationType)),nl,(solver_interface:solve_predicate(FullPred,_,3,[],CBCResult) -> write(CBCResult) ; write(fail)),nl, | |
| 324 | Translation = (TranslationType,PExpr,ProBState,FullProBState,Ids,GlobalState,Filtered,SkippedVars,UnsupportedLPs), | |
| 325 | NewAcc = [Translation|TranslationsAcc] | |
| 326 | ), | |
| 327 | stop_ms_timer_with_debug_msg(T1,add_translation_for_solver_core(TranslationType,Solver)) | |
| 328 | ). | |
| 329 | ||
| 330 | contains_solver_name_with_prefix(Prefix, SelectedSolvers) :- | |
| 331 | member(Name, SelectedSolvers), | |
| 332 | atom_prefix(Prefix, Name), | |
| 333 | !. | |
| 334 | ||
| 335 | %% remove_solvers_with_prefix(+Prefix, +SelectedSolvers, -NewSelectedSolvers). | |
| 336 | % Remove solvers for specific translation, e.g., if all operators are unsupported. | |
| 337 | remove_solvers_with_prefix(_, [], []). | |
| 338 | remove_solvers_with_prefix(Prefix, [SelectedSolver|T], NT) :- | |
| 339 | atom_prefix(Prefix, SelectedSolver), | |
| 340 | !, | |
| 341 | remove_solvers_with_prefix(Prefix, T, NT). | |
| 342 | remove_solvers_with_prefix(Prefix, [SelectedSolver|T], [SelectedSolver|NT]) :- | |
| 343 | remove_solvers_with_prefix(Prefix, T, NT). | |
| 344 | ||
| 345 | combine_satisfiable_component_results([], SatComponentResult, NResultAcc) :- | |
| 346 | !, | |
| 347 | NResultAcc = SatComponentResult. | |
| 348 | combine_satisfiable_component_results(solution(AccBindings), solution(ComponentBindings), NResultAcc) :- | |
| 349 | append(AccBindings, ComponentBindings, NAccBindings), | |
| 350 | NResultAcc = solution(NAccBindings). | |
| 351 | ||
| 352 | create_term_size_pairs([], []). | |
| 353 | create_term_size_pairs([component(C,_)|T], [NTS-C|NT]) :- | |
| 354 | term_size(C, TS), | |
| 355 | NTS is TS * -1, % so that we can use keysort which sorts in ascending order | |
| 356 | create_term_size_pairs(T, NT). | |
| 357 | ||
| 358 | sort_components_descending_term_size(Components, SortedComponents) :- | |
| 359 | % term sizes are negative so that we can use keysort to derive a descending order | |
| 360 | % but we don't need the actual term sizes anyway | |
| 361 | create_term_size_pairs(Components, TermSizePairs), | |
| 362 | keysort(TermSizePairs, SortedComponents). | |
| 363 | ||
| 364 | %% solve_components_with_z3(+Components, +AvailableSolvers, +Options, +State, +ResultAcc, +UnknownOccurred, -Result). | |
| 365 | % Log unknown in +UnknownOccurred so that a contradiction can possibly be found in a specific component | |
| 366 | % although a prior component's satisfiability couldn't be decided. | |
| 367 | solve_components_with_z3([], _, _, _, _, true, no_solution_found(solver_answered_unknown)). | |
| 368 | solve_components_with_z3([], _, _, _, ResultAcc, false, ResultAcc). | |
| 369 | solve_components_with_z3([ComponentTerm|T], AvailableSolvers, Options, State, ResultAcc, UnknownOccurred, Result) :- | |
| 370 | ( ComponentTerm = component(Component,_) | |
| 371 | ; ComponentTerm = _TermSize-Component | |
| 372 | ), !, | |
| 373 | smt_solve_pre_cleaned_predicate(AvailableSolvers, z3, Options, Component, State, ComponentResult), | |
| 374 | constraint_uses_unfixed_deferred_set(Component, UsesDefSet), | |
| 375 | ( ( ComponentResult == contradiction_found, | |
| 376 | ( UsesDefSet == false | |
| 377 | ; get_preference(z3_solve_for_animation, false) % this is a genuine contradiction without considering DEFAULT_SETSIZE | |
| 378 | ) | |
| 379 | ) | |
| 380 | -> Result = contradiction_found | |
| 381 | ; ( ComponentResult = solution(_) | |
| 382 | -> combine_satisfiable_component_results(ResultAcc, ComponentResult, NResultAcc), | |
| 383 | solve_components_with_z3(T, AvailableSolvers, Options, State, NResultAcc, UnknownOccurred, Result) | |
| 384 | ; % unknown, unfixed deferred sets or translation failed | |
| 385 | solve_components_with_z3(T, AvailableSolvers, Options, State, ResultAcc, true, Result) | |
| 386 | ) | |
| 387 | ). | |
| 388 | ||
| 389 | %% sat_skeleton_is_contradictory(+Pred, +Solver). | |
| 390 | % Is true if a contradiction has been found for the predicate's SAT skeleton. Otherwise, the call fails. | |
| 391 | sat_skeleton_is_contradictory(Pred, Solver) :- | |
| 392 | start_ms_timer(T0), | |
| 393 | preprocess_predicate(false, false, Pred, LiftedPred, _, _), | |
| 394 | % abstract formula to SAT as is done by lazy SMT solvers | |
| 395 | predicate_to_sat(normal, LiftedPred, _, _TopLevelWDPOs, SmtBoolFormula, SatVars), | |
| 396 | findall(bind(IdName,_), member(b(identifier(IdName),_,_), SatVars), Bindings), | |
| 397 | stop_ms_timer_with_debug_msg(T0, preprocess_predicate_to_sat_predicate_to_find_contradiction(Solver)), | |
| 398 | start_ms_timer(T1), | |
| 399 | ( b_test_boolean_expression_cs(SmtBoolFormula, [], Bindings, 'SMT Boolean abstraction', Solver) | |
| 400 | -> stop_ms_timer_with_debug_msg(T1, no_contradiction_found), | |
| 401 | fail | |
| 402 | ; stop_ms_timer_with_debug_msg(T1, contradiction_found) | |
| 403 | ). | |
| 404 | ||
| 405 | %% smt_solve_predicate_aux(+SelectedSolvers, +Solver, +OptionsList, +CPred, +ProBState, -Result). | |
| 406 | % smt_clean_up_pre/4 has been called on +CPred. | |
| 407 | smt_solve_predicate_aux(_, Solver, Options, CPred, _, Result) :- | |
| 408 | member(check_sat_skeleton(TimeOut), Options), | |
| 409 | TimeOut > 0, | |
| 410 | % don't translate to SMT-LIB if formula has static contradiction, e.g., a:INT & a/:INT | |
| 411 | safe_time_out(sat_skeleton_is_contradictory(CPred, Solver), TimeOut, TimeOutRes), | |
| 412 | TimeOutRes \== time_out, | |
| 413 | !, | |
| 414 | Result = contradiction_found, | |
| 415 | clear_state. | |
| 416 | smt_solve_predicate_aux(SelectedSolvers, Solver, Options, CPred, ProBState, Result) :- | |
| 417 | member(decompose_into_components, Options),!, | |
| 418 | % decompose predicate into components to be solved independently | |
| 419 | % important to not split among deferred sets since we need to know the cardinality if is set | |
| 420 | start_ms_timer(T0), | |
| 421 | findall(DeferredSetId, b_get_machine_set(DeferredSetId), DeferredSetIds), | |
| 422 | predicate_components_in_scope(CPred, DeferredSetIds, Components), | |
| 423 | stop_ms_timer_with_debug_msg(T0,predicate_components_in_scope(SelectedSolvers)), | |
| 424 | ( Components = [component(SingleComponent,_)] | |
| 425 | -> smt_solve_pre_cleaned_predicate(SelectedSolvers, Solver, Options, SingleComponent, ProBState, FreshResult) | |
| 426 | ; ( member(sort_components,Options) | |
| 427 | -> sort_components_descending_term_size(Components, SortedComponents) | |
| 428 | ; SortedComponents = Components | |
| 429 | ), | |
| 430 | solve_components_with_z3(SortedComponents, SelectedSolvers, Options, ProBState, solution([]), false, FreshResult) | |
| 431 | ), | |
| 432 | Result = FreshResult, | |
| 433 | clear_state. | |
| 434 | smt_solve_predicate_aux(SelectedSolvers, Solver, Options, CPred, ProBState, Result) :- | |
| 435 | smt_solve_pre_cleaned_predicate(SelectedSolvers, Solver, Options, CPred, ProBState, Result). | |
| 436 | ||
| 437 | %% smt_solve_pre_cleaned_predicate(+SelectedSolvers, +Solver, +CPred, +ProBState, -Result). | |
| 438 | % smt_clean_up_pre/4 has been called on +CPred. | |
| 439 | smt_solve_pre_cleaned_predicate(SelectedSolvers, Solver, Options, CPred, ProBState, Result) :- | |
| 440 | validate_selected_solvers(Solver, SelectedSolvers), | |
| 441 | ( init_interface(Solver) | |
| 442 | -> % one translation for each type, contexts are copied in the C++ interface | |
| 443 | % if more than one solver uses a specific translation | |
| 444 | ( (contains_solver_name_with_prefix(axm, SelectedSolvers), | |
| 445 | add_translation_for_solver(axiomatic, Solver, ProBState, CPred, Options, [], TranslationsAcc1, AxmIsUnfilteredTruth, AxmResult)) | |
| 446 | -> SelectedSolvers2 = SelectedSolvers | |
| 447 | ; TranslationsAcc1 = [], | |
| 448 | AxmIsUnfilteredTruth = false, | |
| 449 | remove_solvers_with_prefix(axm, SelectedSolvers, SelectedSolvers2) | |
| 450 | ), | |
| 451 | ( ground(AxmResult) | |
| 452 | -> Result = AxmResult | |
| 453 | ; ( (contains_solver_name_with_prefix(cns, SelectedSolvers), | |
| 454 | add_translation_for_solver(constructive, Solver, ProBState, CPred, Options, TranslationsAcc1, TranslationsAcc2, CnsIsUnfilteredTruth, CnsResult)) | |
| 455 | -> RestSelectedSolvers = SelectedSolvers2 | |
| 456 | ; TranslationsAcc2 = TranslationsAcc1, | |
| 457 | CnsIsUnfilteredTruth = false, | |
| 458 | remove_solvers_with_prefix(cns, SelectedSolvers2, RestSelectedSolvers) | |
| 459 | ), | |
| 460 | ( ground(CnsResult) | |
| 461 | -> Result = CnsResult | |
| 462 | ; ( (contains_solver_name_with_prefix(sat, SelectedSolvers), | |
| 463 | add_translation_for_solver(sat, Solver, ProBState, CPred, Options, TranslationsAcc2, Translations, SatIsUnfilteredTruth, SatResult)) | |
| 464 | -> RestSelectedSolvers2 = RestSelectedSolvers | |
| 465 | ; Translations = TranslationsAcc2, | |
| 466 | SatIsUnfilteredTruth = false, | |
| 467 | remove_solvers_with_prefix(sat, RestSelectedSolvers, RestSelectedSolvers2) | |
| 468 | ), | |
| 469 | ( ground(SatResult) | |
| 470 | -> Result = SatResult | |
| 471 | ; Translations \== [], | |
| 472 | RestSelectedSolvers2 \== [], | |
| 473 | constraint_uses_unfixed_deferred_set(CPred, UsesDefSet), | |
| 474 | !, | |
| 475 | ( (AxmIsUnfilteredTruth; CnsIsUnfilteredTruth; SatIsUnfilteredTruth) | |
| 476 | -> Result = solution([]) | |
| 477 | ; catch(check_sat(RestSelectedSolvers2, Solver, UsesDefSet, Translations, Options, SolverResult, SolvedTranslation), | |
| 478 | model_translation_failed, Result = no_solution_found(model_translation_failed)), | |
| 479 | member((SolvedTranslation,_,_,_,_,_,Filtered,SkippedVars), Translations), | |
| 480 | ( (SolverResult=solution(_), nonvar(SkippedVars), is_list(SkippedVars)) % is_list grounds list | |
| 481 | -> Result = no_solution_found(complex_state_values(SkippedVars)), | |
| 482 | add_message(smt_solve_predicate,'Some variable values were discarded as they are not supported: ',SkippedVars) | |
| 483 | ; SolverResult = solution(_), Filtered == true | |
| 484 | -> Result = no_solution_found(unsupported_predicates) | |
| 485 | ; Result = SolverResult | |
| 486 | ) | |
| 487 | ) | |
| 488 | ) | |
| 489 | ), | |
| 490 | !, % not backtrackable | |
| 491 | clear_state | |
| 492 | ) | |
| 493 | ; Result = no_solution_found(solver_not_available) | |
| 494 | ). | |
| 495 | smt_solve_pre_cleaned_predicate(_,_,_,_Pred,_,no_solution_found(translation_or_setup_failed)) :- | |
| 496 | clear_state. | |
| 497 | ||
| 498 | mk_expr_skip(TranslationType, Solver, Pred, [], GlobalState, Expr) :- | |
| 499 | smt_clean_up(TranslationType, Pred, AxmCPred), | |
| 500 | !, | |
| 501 | conjunction_to_list(AxmCPred, List), | |
| 502 | exclude(contains_unsupported_type_or_expression(TranslationType, Solver), List, NList), | |
| 503 | conjunct_predicates(NList, NewCPred), | |
| 504 | mk_expr(NewCPred, TranslationType, Solver, [], GlobalState, Expr). | |
| 505 | mk_expr_skip(_, _, Pred, _, _, _) :- !, | |
| 506 | add_error_fail(smt_solvers_interface, 'mk_expr_skip failed', Pred). | |
| 507 | ||
| 508 | %% check_sat(+SelectedSolvers, +Solver, +UsesDefSet, +Translations, -Result, -SolvedTranslation). | |
| 509 | % SolvedTranslation is either axiomatic or constructive. | |
| 510 | check_sat(SelectedSolvers, Solver, UsesDefSet, Translations, Options, Result, SolvedTranslation) :- | |
| 511 | start_ms_timer(T1), | |
| 512 | catch(check_sat_aux(SelectedSolvers, Solver, UsesDefSet, Translations, Options, Result, SolvedTranslation), | |
| 513 | SolverException, | |
| 514 | treat_exception(Solver, SolverException, Result)), | |
| 515 | stop_ms_timer_with_debug_msg(T1,check_sat(SelectedSolvers,Solver, Options)). | |
| 516 | ||
| 517 | treat_exception(Solver, Exc, Result) :- | |
| 518 | known_solver_exception(Exc, Reason), | |
| 519 | add_internal_error('Exception occurred during SMT solving: ', Reason), | |
| 520 | !, | |
| 521 | reset_interface(Solver), | |
| 522 | Result = no_solution_found(solver_answered_unknown). | |
| 523 | treat_exception(Solver, Exc, _) :- | |
| 524 | format('Unknown exception in solver ~w: ~w~n', [Solver, Exc]), | |
| 525 | throw(Exc). | |
| 526 | ||
| 527 | known_solver_exception(model_translation_failed, model_translation_failed). | |
| 528 | known_solver_exception(z3_exception(Reason), Reason). | |
| 529 | known_solver_exception(logic_exception(Reason), Reason). | |
| 530 | known_solver_exception(error(representation_error(nofit(integer)),representation_error(_,_,nofit(integer))), integer_overflow). | |
| 531 | ||
| 532 | constraint_uses_unfixed_deferred_set(Constraint, UsesDefSet) :- | |
| 533 | find_typed_identifier_uses(Constraint, [], UsedIds), | |
| 534 | ( list_contains_unfixed_deferred_set_id(UsedIds) | |
| 535 | -> UsesDefSet = true | |
| 536 | ; UsesDefSet = false | |
| 537 | ). | |
| 538 | ||
| 539 | check_sat_aux(_, cvc4, UsesDefSet, Translations, Options, Result, SolvedTranslation) :- | |
| 540 | memberchk((axiomatic,AxmPExpr,_,_,_,_,_,_,_), Translations), | |
| 541 | get_smt_time_out(Options,TO), | |
| 542 | smt_solver_interface_call(cvc4, cvc4interface:smt_solve_query(AxmPExpr, TO, SMTResult)), | |
| 543 | get_model_or_return_result(SMTResult, UsesDefSet, TO, axiomatic, Translations, cvc4, Result, SolvedTranslation), | |
| 544 | SolvedTranslation == axiomatic. | |
| 545 | check_sat_aux(SelectedSolvers, z3, UsesDefSet, Translations, Options, Result, SolvedTranslation) :- | |
| 546 | ( memberchk((axiomatic,AxmPExpr,_,_,_,_,_,_,_), Translations), | |
| 547 | ! | |
| 548 | ; AxmPExpr = -1 % do not solve any Z3 formula with axiomatic solver | |
| 549 | ), | |
| 550 | ( memberchk((constructive,CnsPExpr,_,_,_,_,_,_,_), Translations), | |
| 551 | ! | |
| 552 | ; CnsPExpr = -1 % do not solve any Z3 formula with constructive solver | |
| 553 | ), | |
| 554 | ( memberchk((sat,SatPExpr,_,_,_,_,_,_,_), Translations), | |
| 555 | ! | |
| 556 | ; SatPExpr = -1 | |
| 557 | ), | |
| 558 | get_smt_time_out(Options,TO), | |
| 559 | % format('Calling Z3 with time-out ~w, solvers:~w (~w:~w)~n',[TO,SelectedSolvers,AxmPExpr,CnsPExpr]), | |
| 560 | % Selected Solvers can be axm_inc, axm_ninc, sat or cns_ninc | |
| 561 | smt_solver_interface_call(z3, z3interface:smt_solve_query(SelectedSolvers, AxmPExpr, CnsPExpr, SatPExpr, TO, SMTResultData)), | |
| 562 | ( debug_level_active_for(9) | |
| 563 | -> write('; SMT TRANSLATION: '), nl, pretty_print_smt(z3), nl | |
| 564 | ; true | |
| 565 | ), | |
| 566 | SMTResultData = result_tuple(TempSolvedTranslation,SMTResult), | |
| 567 | %format('Calling get_model_or_return_result ~w~n',[SMTResult]), | |
| 568 | get_model_or_return_result(SMTResult, UsesDefSet, TO, TempSolvedTranslation, Translations, z3, Result, SolvedTranslation). | |
| 569 | ||
| 570 | get_smt_time_out(Options,TO) :- | |
| 571 | member(smt_time_out_factor(TOFactor),Options),!, | |
| 572 | get_time_out_with_factor(TOFactor,TO). | |
| 573 | get_smt_time_out(_,TO) :- get_preference(time_out, TO). | |
| 574 | ||
| 575 | add_state_to_bindings([], FullBindings, FullBindings). | |
| 576 | add_state_to_bindings([bind(IdName,Value)|T], Bindings, FullBindings) :- | |
| 577 | ( member(binding(IdName,ModelValue,_), Bindings) | |
| 578 | -> equal_object(Value, ModelValue), | |
| 579 | NewAcc = Bindings | |
| 580 | ; infer_value_type(Value, Type), | |
| 581 | translate_bexpression(b(value(Value),Type,[]), PrettyValue), | |
| 582 | NewAcc = [binding(IdName,Value,PrettyValue)|Bindings] | |
| 583 | ), | |
| 584 | !, | |
| 585 | add_state_to_bindings(T, NewAcc, FullBindings). | |
| 586 | add_state_to_bindings([bind(IdName,_)|_], _, _) :- | |
| 587 | add_error_fail(add_state_to_bindings, 'The synchronisation of the model found by Z3 with the global state bindings failed.', [IdName]). | |
| 588 | ||
| 589 | get_model_or_return_result(unsat, UsesDefSet, _, SolvedTranslation, _, _, Solution, SolvedTranslationOut) :- | |
| 590 | get_preference(z3_solve_for_animation, true), % behave such as ProB by considering DEFAULT_SETSIZE | |
| 591 | !, | |
| 592 | SolvedTranslation = SolvedTranslationOut, | |
| 593 | ( (UsesDefSet == true, \+ solve_in_state) | |
| 594 | -> Solution = no_solution_found(unfixed_deferred_sets) | |
| 595 | ; Solution = contradiction_found | |
| 596 | ). | |
| 597 | get_model_or_return_result(unsat, _, _, SolvedTranslation, _, _, contradiction_found, SolvedTranslation). | |
| 598 | get_model_or_return_result(unknown, _, _, SolvedTranslation, _, _, no_solution_found(solver_answered_unknown), SolvedTranslation). | |
| 599 | get_model_or_return_result(time_out, _, _, SolvedTranslation, _, _, time_out, SolvedTranslation). | |
| 600 | get_model_or_return_result(sat, _, TO, SolvedTranslation, Translations, Solver, Solution, SolvedTranslation) :- | |
| 601 | memberchk((SolvedTranslation,_,ProBState,_,Ids,GlobalState,_,_,UnsupportedLPs), Translations), | |
| 602 | ( UnsupportedLPs \== [] | |
| 603 | -> add_message(get_model_or_return_result, 'A solution has been found but some predicates are not supported and were not considered: ', UnsupportedLPs), | |
| 604 | Solution = no_solution_found(solver_answered_unknown) | |
| 605 | ; exclude(is_smt_temp_var, Ids, FilteredIDs), | |
| 606 | % we replaced ProBState ids with values in ast_cleanup_for_smt so we add them to the solution here | |
| 607 | ( catch( | |
| 608 | translate_smt_model_to_b_values_with_timeout(TO,Solver, GlobalState, FilteredIDs, Bindings), | |
| 609 | E, | |
| 610 | (add_error(smt_solvers_interface,'Exception in model translation: ',E), | |
| 611 | throw(model_translation_failed))) | |
| 612 | -> ( ( | |
| 613 | get_preference(z3_solve_for_animation, true), | |
| 614 | % Z3 behaves as ProB by considering its deferred set size preference | |
| 615 | \+ consistent_deferred_set_sizes | |
| 616 | ) | |
| 617 | -> Solution = no_solution_found(unfixed_deferred_sets) | |
| 618 | ; add_state_to_bindings(ProBState, Bindings, FullBindings), | |
| 619 | maplist(bind_in_prob_state(FullBindings), ProBState) | |
| 620 | -> % for this solution, Z3 possibly considered a smaller deferred set size than ProB | |
| 621 | % if Z3 considered a larger deferred set size, an error would have been thrown by model_translation:handle_globalsets_fdrange_contradiction/2 | |
| 622 | ( \+ consistent_deferred_set_sizes | |
| 623 | -> add_message(get_model_or_return_result, 'Deferred set size considered by Z3 is smaller than the one of ProB (DEFAULT_SETSIZE)') | |
| 624 | ; true | |
| 625 | ), | |
| 626 | Solution = solution(FullBindings) | |
| 627 | ; throw(model_solution_extraction_failed) | |
| 628 | ) | |
| 629 | ; add_warning(smt_solvers_interface,'Failure in model translation: ',Solver), | |
| 630 | throw(model_translation_failed) | |
| 631 | ) | |
| 632 | ). | |
| 633 | %get_model_or_return_result(sat, _, TO, PreSolvedTranslation, Translations, Solver, Result, SolvedTranslation) :- | |
| 634 | % memberchk((PreSolvedTranslation,_,_,Ids,_,_,_), Translations), | |
| 635 | % next_result(Solver, PreSolvedTranslation, Translations, Ids, Result, SolvedTranslation). | |
| 636 | ||
| 637 | translate_smt_model_to_b_values_with_timeout(TO,Solver, GlobalState, FilteredIDs, Bindings) :- | |
| 638 | safe_time_out(translate_smt_model_to_b_values(Solver, GlobalState, FilteredIDs, Bindings),TO,TORes), | |
| 639 | ( TORes = time_out | |
| 640 | -> add_warning(smt_solvers_interface,'Time-out in model translation: ',Solver), | |
| 641 | throw(model_translation_failed) | |
| 642 | ; true | |
| 643 | ). | |
| 644 | ||
| 645 | bind_in_prob_state(Bindings,bind(Id,Val)) :- | |
| 646 | member(binding(Id,Z3Val,_),Bindings), %format('~w: ~w = ~w~n',[Id,Z3Val,Val]),nl, | |
| 647 | % Z3 may return solution in list form, ProB had it in AVL form: hence use equal_object | |
| 648 | equal_object(Z3Val,Val). | |
| 649 | ||
| 650 | /*next_result(_,PreSolvedTranslation,_,[],Result,SolvedTranslation) :- !, | |
| 651 | % no global identifiers -> no other solution | |
| 652 | Result = contradiction_found, | |
| 653 | SolvedTranslation = PreSolvedTranslation. | |
| 654 | next_result(Solver,_,Translations,_,Result,SolvedTranslation) :- | |
| 655 | memberchk((axiomatic,AxmPExpr,AxmProBState,AxmIds,AxmGlobalState,AxmFiltered,AxmSkippedVars), Translations), | |
| 656 | memberchk((constructive,CnsPExpr,CnsProBState,CnsIds,CnsGlobalState,CnsFiltered,CnsSkippedVars), Translations), | |
| 657 | findall(Id,member(id(_,Id),AxmGlobalState),AxmExprIds), | |
| 658 | findall(Id,member(id(_,Id),CnsGlobalState),CnsExprIds), | |
| 659 | smt_solver_interface_call(Solver,conjoin_negated_state(axiomatic,AxmExprIds,AxmPExpr,NewAxmPExpr)), | |
| 660 | smt_solver_interface_call(Solver,conjoin_negated_state(constructive,CnsExprIds,CnsPExpr,NewCnsPExpr)), | |
| 661 | NewTranslations = [ | |
| 662 | (axiomatic,NewAxmPExpr,AxmProBState,AxmIds,AxmGlobalState,AxmFiltered,AxmSkippedVars), | |
| 663 | (constructive,NewCnsPExpr,CnsProBState,CnsIds,CnsGlobalState,CnsFiltered,CnsSkippedVars)], | |
| 664 | check_sat(Solver,NewTranslations,Result,SolvedTranslation). | |
| 665 | */ | |
| 666 | ||
| 667 | % Unary and binary operators that have a direct counterpart in SMT-LIB. | |
| 668 | unary_operator(negation). | |
| 669 | unary_operator(unary_minus). | |
| 670 | unary_operator(unary_minus_real). | |
| 671 | unary_operator(convert_real). | |
| 672 | binary_operator(floored_div). | |
| 673 | binary_operator(equivalence). | |
| 674 | binary_operator(implication). | |
| 675 | binary_operator(less). | |
| 676 | binary_operator(less_equal). | |
| 677 | binary_operator(less_real). | |
| 678 | binary_operator(less_equal_real). | |
| 679 | binary_operator(greater). | |
| 680 | binary_operator(greater_equal). | |
| 681 | binary_operator(add). | |
| 682 | binary_operator(modulo). | |
| 683 | binary_operator(minus). | |
| 684 | binary_operator(multiplication). | |
| 685 | binary_operator(div). | |
| 686 | binary_operator(power_of). | |
| 687 | binary_operator(member). | |
| 688 | binary_operator(subset). | |
| 689 | binary_operator(union). | |
| 690 | binary_operator(intersection). | |
| 691 | binary_operator(set_subtraction). | |
| 692 | binary_operator(add_real). | |
| 693 | binary_operator(minus_real). | |
| 694 | binary_operator(multiplication_real). | |
| 695 | binary_operator(div_real). | |
| 696 | ||
| 697 | % Collect couple types from a list of identifiers to reduce the list to a single couple afterwards (left-associative). | |
| 698 | % We need the couple types for the constructors in SMT-Lib. | |
| 699 | get_couple_types_comp_args([Arg1,Arg2|T], CoupleTypes) :- | |
| 700 | Arg1 = b(identifier(_),Type1,_), | |
| 701 | Arg2 = b(identifier(_),Type2,_), | |
| 702 | get_couple_types_comp_args(T, couple(Type1,Type2), [couple(Type1,Type2)|D]-D, CoupleTypes). | |
| 703 | ||
| 704 | get_couple_types_comp_args([], _, CoupleTypes-D, CoupleTypes) :- | |
| 705 | D = []. | |
| 706 | get_couple_types_comp_args([Arg|T], LastCoupleType, Acc-D, CoupleTypes) :- | |
| 707 | Arg = b(identifier(_),Type,_), | |
| 708 | D = [couple(LastCoupleType,Type)|ND], | |
| 709 | get_couple_types_comp_args(T, couple(LastCoupleType,Type), Acc-ND, CoupleTypes). | |
| 710 | ||
| 711 | mk_expr_maplist(TranslationType,Solver,LS,GS,Op,Expr) :- | |
| 712 | mk_expr(Op,TranslationType,Solver,LS,GS,Expr). | |
| 713 | ||
| 714 | mk_expr(b(Op,Type,_Infos),TranslationType,Solver,LS,GS,Expr) :- | |
| 715 | mk_expr_aux(Op,Type,TranslationType,Solver,LS,GS,Expr). | |
| 716 | ||
| 717 | % unary operators | |
| 718 | mk_expr_aux(first_of_pair(Couple), _, TranslationType, Solver, LS, GS, Expr) :- | |
| 719 | get_texpr_type(Couple, CoupleType), | |
| 720 | mk_expr(Couple, TranslationType, Solver, LS, GS, AE), | |
| 721 | smt_solver_interface_call(Solver, mk_op_couple_prj(TranslationType, first, AE, CoupleType, Expr)). | |
| 722 | mk_expr_aux(second_of_pair(Couple), _, TranslationType, Solver, LS, GS, Expr) :- | |
| 723 | get_texpr_type(Couple, CoupleType), | |
| 724 | mk_expr(Couple, TranslationType, Solver, LS, GS, AE), | |
| 725 | smt_solver_interface_call(Solver, mk_op_couple_prj(TranslationType, second, AE, CoupleType, Expr)). | |
| 726 | /* | |
| 727 | % change in Z3: lambda inside recursive functions was declared unsupported until proper support is provided (see https://github.com/Z3Prover/z3/issues/5813) | |
| 728 | % see mk_op_iteration_func_decl in /extensions/z3interface/src/cpp/main.cpp | |
| 729 | mk_expr_aux(Op, Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 730 | functor(Op, Functor, 1), | |
| 731 | ( (Functor == closure, IsReflexive = 0) | |
| 732 | ; (Functor == reflexive_closure, IsReflexive = 1) | |
| 733 | ), | |
| 734 | !, | |
| 735 | arg(1, Op, A), | |
| 736 | Type = set(CoupleType), | |
| 737 | CoupleType = couple(_,ExistsVarType), | |
| 738 | mk_expr(A, TranslationType, Solver, LS, GS, AE), | |
| 739 | smt_solver_interface_call(Solver, mk_op_closure(TranslationType, IsReflexive, AE, Type, CoupleType, ExistsVarType, Expr)). | |
| 740 | mk_expr_aux(iteration(A1,A2), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 741 | !, | |
| 742 | Type = set(CoupleType), | |
| 743 | CoupleType = couple(_,ExistsVarType), | |
| 744 | mk_expr(A1, TranslationType, Solver, LS, GS, AE1), | |
| 745 | mk_expr(A2, TranslationType, Solver, LS, GS, AE2), | |
| 746 | smt_solver_interface_call(Solver, mk_op_iteration(TranslationType, AE1, AE2, Type, CoupleType, ExistsVarType, Expr)).*/ | |
| 747 | mk_expr_aux(interval(A1,A2), _, TranslationType, Solver, LS, GS, Expr) :- | |
| 748 | !, | |
| 749 | mk_expr(A1, TranslationType, Solver, LS, GS, AE1), | |
| 750 | mk_expr(A2, TranslationType, Solver, LS, GS, AE2), | |
| 751 | smt_solver_interface_call(Solver, mk_op_interval(TranslationType, AE1, AE2, Expr)). | |
| 752 | mk_expr_aux(direct_product(Arg1,Arg2), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 753 | !, | |
| 754 | Type = set(CoupleOutType), | |
| 755 | CoupleOutType = couple(_,Couple2Type), | |
| 756 | mk_expr(Arg1, TranslationType, Solver, LS, GS, Arg1E), | |
| 757 | mk_expr(Arg2, TranslationType, Solver, LS, GS, Arg2E), | |
| 758 | Arg1 = b(_,set(CoupleType1),_), | |
| 759 | Arg2 = b(_,set(CoupleType2),_), | |
| 760 | smt_solver_interface_call(Solver, mk_op_direct_product(TranslationType, Arg1E, Arg2E, Couple2Type, CoupleType1, CoupleType2, CoupleOutType, Expr)). | |
| 761 | mk_expr_aux(parallel_product(Arg1,Arg2), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 762 | !, | |
| 763 | Type = set(CoupleOutType), | |
| 764 | mk_expr(Arg1, TranslationType, Solver, LS, GS, Arg1E), | |
| 765 | mk_expr(Arg2, TranslationType, Solver, LS, GS, Arg2E), | |
| 766 | Arg1 = b(_,set(CoupleType1),_), | |
| 767 | Arg2 = b(_,set(CoupleType2),_), | |
| 768 | CoupleOutType = couple(ExistsCoupleType1,ExistsCoupleType2), | |
| 769 | smt_solver_interface_call(Solver, mk_op_parallel_product(TranslationType, Arg1E, Arg2E, CoupleType1, CoupleType2, ExistsCoupleType1, ExistsCoupleType2, CoupleOutType, Expr)). | |
| 770 | mk_expr_aux(composition(Arg1,Arg2), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 771 | !, | |
| 772 | Type = set(CoupleOutType), | |
| 773 | Arg1 = b(_,set(CoupleType1),_), | |
| 774 | CoupleType1 = couple(A,B), | |
| 775 | Arg2 = b(_,set(CoupleType2),_), | |
| 776 | CoupleType2 = couple(B,C), | |
| 777 | CoupleOutType = couple(A,C), | |
| 778 | mk_expr(Arg1, TranslationType, Solver, LS, GS, Arg1E), | |
| 779 | mk_expr(Arg2, TranslationType, Solver, LS, GS, Arg2E), | |
| 780 | smt_solver_interface_call(Solver, mk_op_composition(TranslationType, Arg1E, Arg2E, B, CoupleType1, CoupleType2, CoupleOutType, Expr)). | |
| 781 | mk_expr_aux(cartesian_product(A1,A2), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 782 | !, | |
| 783 | Type = set(CoupleType), | |
| 784 | mk_expr(A1, TranslationType, Solver, LS, GS, AE1), | |
| 785 | mk_expr(A2, TranslationType, Solver, LS, GS, AE2), | |
| 786 | smt_solver_interface_call(Solver, mk_op_cartesian(TranslationType, AE1, AE2, CoupleType, Expr)). | |
| 787 | mk_expr_aux(identity(A), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 788 | !, | |
| 789 | Type = set(CoupleType), | |
| 790 | CoupleType = couple(InnerSetType,_), | |
| 791 | mk_expr(A, TranslationType, Solver, LS, GS, AE), | |
| 792 | smt_solver_interface_call(Solver, mk_op_identity(TranslationType, AE, InnerSetType, CoupleType, Expr)). | |
| 793 | mk_expr_aux(reverse(A), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 794 | !, | |
| 795 | Type = set(CoupleType), | |
| 796 | mk_expr(A, TranslationType, Solver, LS, GS, AE), | |
| 797 | smt_solver_interface_call(Solver, mk_op_reverse(TranslationType, AE, CoupleType, Expr)). | |
| 798 | % binary operators | |
| 799 | mk_expr_aux(comprehension_set(Args,Body), Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 800 | LambdaId = b(identifier('_lambda_result_'),_,_), | |
| 801 | select(LambdaId, Args, LambdaArgs), | |
| 802 | create_bounded_smt_state(TranslationType, Solver, LambdaArgs, State, ArgsE), | |
| 803 | ArgsE = [Arg], | |
| 804 | append(State, LS, NLS), | |
| 805 | conjunction_to_list(Body, ConjList), | |
| 806 | select(b(equal(LambdaId,BodyExpr),pred,Info), ConjList, RestConjList), | |
| 807 | member(prob_annotation('LAMBDA-EQUALITY'), Info), | |
| 808 | conjunct_predicates(RestConjList, BodyPred), | |
| 809 | Type = set(CoupleType), | |
| 810 | !, | |
| 811 | mk_expr(BodyExpr, TranslationType, Solver, NLS, GS, BodyE), | |
| 812 | mk_expr(BodyPred, TranslationType, Solver, NLS, GS, BodyP), | |
| 813 | smt_solver_interface_call(Solver, mk_op_lambda(TranslationType, Arg, BodyP, BodyE, CoupleType, Expr)). | |
| 814 | mk_expr_aux(comprehension_set(Args,Body), _, TranslationType, Solver, LS, GS, Expr) :- | |
| 815 | !, | |
| 816 | create_bounded_smt_state(TranslationType, Solver, Args, State, ArgsE), | |
| 817 | append(State, LS, NLS), | |
| 818 | mk_expr(Body, TranslationType, Solver, NLS, GS, BodyE), | |
| 819 | length(ArgsE, ArgAmount), | |
| 820 | ( ArgAmount == 1 | |
| 821 | -> ArgsE = [Arg], | |
| 822 | smt_solver_interface_call(Solver, mk_op_comprehension_set_singleton(TranslationType, Arg, BodyE, Expr)) | |
| 823 | ; get_couple_types_comp_args(Args, CoupleTypes), | |
| 824 | smt_solver_interface_call(Solver, mk_op_comprehension_set_multi(TranslationType, ArgsE, CoupleTypes, BodyE, Expr)) | |
| 825 | ). | |
| 826 | mk_expr_aux(image(A,B), _, TranslationType, Solver, LS, GS, Expr) :- | |
| 827 | !, | |
| 828 | A = b(_,set(couple(Prj1Type,Prj2Type)),_), | |
| 829 | mk_expr(A, TranslationType, Solver, LS, GS, AE), | |
| 830 | mk_expr(B, TranslationType, Solver, LS, GS, BE), | |
| 831 | smt_solver_interface_call(Solver, mk_op_image(TranslationType, AE,BE,couple(Prj1Type,Prj2Type),Prj1Type,Prj2Type,Expr)). | |
| 832 | % conjunct and disjunct are deconstructed to lists | |
| 833 | mk_expr_aux(conjunct(A,B),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 834 | !, | |
| 835 | conjunction_to_list(b(conjunct(A,B),pred,[]),List), | |
| 836 | maplist(mk_expr_maplist(TranslationType, Solver,LS,GS),List,ExprList), % apply mk_expr on List | |
| 837 | % truth/0 are removed from the conjunction during list / from list | |
| 838 | % the list might be empty now! | |
| 839 | ( ExprList = [] | |
| 840 | -> smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)) | |
| 841 | ; ( ExprList = [X] | |
| 842 | -> Expr = X | |
| 843 | ; smt_solver_interface_call(Solver,mk_op_arglist(TranslationType, conjunct,ExprList,Expr)) | |
| 844 | ) | |
| 845 | ). | |
| 846 | mk_expr_aux(disjunct(A,B),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 847 | !, | |
| 848 | disjunction_to_list(b(disjunct(A,B),pred,[]),List), | |
| 849 | maplist(mk_expr_maplist(TranslationType, Solver,LS,GS),List,ExprList), | |
| 850 | smt_solver_interface_call(Solver,mk_op_arglist(TranslationType, disjunct,ExprList,Expr)). | |
| 851 | % special case for if then else | |
| 852 | mk_expr_aux(if_then_else(Pred,A,B),_,TranslationType, Solver,LS,GS,Expr) :- | |
| 853 | !, | |
| 854 | maplist(mk_expr_maplist(TranslationType, Solver,LS,GS),[Pred,A,B],ArgList), | |
| 855 | smt_solver_interface_call(Solver,mk_op_arglist(TranslationType, if_then_else,ArgList,Expr)). | |
| 856 | % special case for partition | |
| 857 | mk_expr_aux(partition(S,Sets),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 858 | !, | |
| 859 | % definition: sets are disjoint and S is the union | |
| 860 | maplist(mk_expr_maplist(TranslationType, Solver,LS,GS),Sets,SetExprs), | |
| 861 | pairwise_union(TranslationType,SetExprs,Solver,UnionOfSets), | |
| 862 | mk_expr(S,TranslationType, Solver,LS,GS,SExpr), | |
| 863 | smt_solver_interface_call(Solver,mk_op(TranslationType, equal,SExpr,UnionOfSets,EqualToUnion)), % S = Union(Sets) | |
| 864 | % enforce sets pairwise disjoint (= intersection is empty) | |
| 865 | get_texpr_type(S,Type), | |
| 866 | smt_solver_interface_call(Solver,mk_empty_set(TranslationType, Type,EmptySet)), | |
| 867 | pairwise_disjoint(TranslationType,SetExprs,Solver,EmptySet,PWConstraint), | |
| 868 | smt_solver_interface_call(Solver,mk_op_arglist(TranslationType, conjunct,[EqualToUnion,PWConstraint],Expr)). | |
| 869 | % quantifiers | |
| 870 | mk_expr_aux(forall(IDs,b(truth,pred,_),B),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 871 | !, | |
| 872 | create_bounded_smt_state(TranslationType, Solver,IDs,State,SMTExprs), | |
| 873 | append(State,LS,NLS), | |
| 874 | mk_expr(B,TranslationType, Solver,NLS,GS,BE), | |
| 875 | smt_solver_interface_call(Solver,mk_quantifier(TranslationType, forall,SMTExprs,BE,Expr)). | |
| 876 | mk_expr_aux(forall(IDs,A,B),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 877 | !, | |
| 878 | create_bounded_smt_state(TranslationType, Solver,IDs,State,SMTExprs), | |
| 879 | append(State,LS,NLS), | |
| 880 | mk_expr(A,TranslationType, Solver,NLS,GS,AE), mk_expr(B,TranslationType, Solver,NLS,GS,BE), | |
| 881 | smt_solver_interface_call(Solver,mk_op(TranslationType, implication,AE,BE,InnerExpr)), | |
| 882 | smt_solver_interface_call(Solver,mk_quantifier(TranslationType, forall,SMTExprs,InnerExpr,Expr)). | |
| 883 | mk_expr_aux(exists(IDs,B),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 884 | !, | |
| 885 | create_bounded_smt_state(TranslationType, Solver,IDs,State,SMTExprs), | |
| 886 | append(State,LS,NLS), | |
| 887 | mk_expr(B,TranslationType, Solver,NLS,GS,InnerExpr), | |
| 888 | smt_solver_interface_call(Solver,mk_quantifier(TranslationType, exists,SMTExprs,InnerExpr,Expr)). | |
| 889 | % equality is a special case as it needs to distinguish between booleans and other types | |
| 890 | mk_expr_aux(equal(A,B),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 891 | !, | |
| 892 | mk_expr(A,TranslationType, Solver,LS,GS,AE), | |
| 893 | mk_expr(B,TranslationType, Solver,LS,GS,BE), | |
| 894 | get_texpr_type(A,Type), | |
| 895 | ( Type = boolean | |
| 896 | -> smt_solver_interface_call(Solver, mk_op(TranslationType, equivalence, AE, BE, Expr)) | |
| 897 | ; smt_solver_interface_call(Solver, mk_op(TranslationType, equal, AE, BE, Expr)) | |
| 898 | ). | |
| 899 | mk_expr_aux(convert_int_floor(Real),integer,TranslationType, Solver,LS,GS,Expr) :- | |
| 900 | mk_expr(Real, TranslationType, Solver, LS, GS, RealExpr), | |
| 901 | !, | |
| 902 | number_codes(RealExpr, ECodes), | |
| 903 | append([102,108,111,111,114], ECodes, EECodes), | |
| 904 | atom_codes(EAtom, EECodes), | |
| 905 | ( is_ground_real(Real) | |
| 906 | -> IsGroundArg = 1 | |
| 907 | ; IsGroundArg = 0 | |
| 908 | ), | |
| 909 | smt_solver_interface_call(Solver,mk_op_floor(TranslationType,IsGroundArg,EAtom,RealExpr,Expr)). | |
| 910 | mk_expr_aux(convert_int_ceiling(Real),integer,TranslationType, Solver,LS,GS,Expr) :- | |
| 911 | mk_expr(Real, TranslationType, Solver, LS, GS, RealExpr), | |
| 912 | !, | |
| 913 | number_codes(RealExpr, ECodes), | |
| 914 | append([99,101,105,108,105,110,103], ECodes, EECodes), | |
| 915 | atom_codes(EAtom, EECodes), | |
| 916 | ( is_ground_real(Real) | |
| 917 | -> IsGroundArg = 1 | |
| 918 | ; IsGroundArg = 0 | |
| 919 | ), | |
| 920 | smt_solver_interface_call(Solver,mk_op_ceiling(TranslationType,IsGroundArg,EAtom,RealExpr,Expr)). | |
| 921 | % records | |
| 922 | mk_expr_aux(rec(ListOfFields),Type,TranslationType, Solver,LS,GS,Expr) :- | |
| 923 | !, | |
| 924 | findall(FieldExpr, member(field(_,FieldExpr),ListOfFields), FieldExprs), | |
| 925 | maplist(mk_expr_maplist(TranslationType, Solver,LS,GS),FieldExprs,SMTFieldExprs), | |
| 926 | smt_solver_interface_call(Solver,mk_record_const(TranslationType, Type,SMTFieldExprs,Expr)). | |
| 927 | mk_expr_aux(record_field(Record,FieldName),Type,TranslationType, Solver,LS,GS,Expr) :- | |
| 928 | !, | |
| 929 | get_texpr_type(Record,record(RFields)), | |
| 930 | nth0(FieldNr,RFields,field(FieldName,Type)), | |
| 931 | % debug_format(9,'Field: ~w Type: ~w~n-> FieldNr: ~w~n',[FieldName,RFields,FieldNr]), | |
| 932 | mk_expr(Record,TranslationType, Solver,LS,GS,SMTRecordExpr), | |
| 933 | smt_solver_interface_call(Solver,mk_record_field(TranslationType, SMTRecordExpr,FieldNr,Expr)). | |
| 934 | % couple construction | |
| 935 | mk_expr_aux(couple(A,B),Type,TranslationType, Solver,LS,GS,Expr) :- | |
| 936 | !, | |
| 937 | mk_expr(A,TranslationType, Solver,LS,GS,AE), | |
| 938 | mk_expr(B,TranslationType, Solver,LS,GS,BE), | |
| 939 | smt_solver_interface_call(Solver,mk_couple(TranslationType, Type,AE,BE,Expr)). | |
| 940 | % constants and identifiers | |
| 941 | mk_expr_aux(identifier(Id),_,_,_Solver,LS,GS,Expr) :- | |
| 942 | !, | |
| 943 | lookup(Id,LS,GS,Expr). | |
| 944 | mk_expr_aux(real(RealAtom),real,TranslationType, Solver,_LS,_GS,Expr) :- | |
| 945 | !, | |
| 946 | smt_solver_interface_call(Solver,mk_real_const(TranslationType, RealAtom,Expr)). | |
| 947 | mk_expr_aux(integer(Int),integer,TranslationType, Solver,_LS,_GS,Expr) :- | |
| 948 | !, | |
| 949 | smt_solver_interface_call(Solver,mk_int_const(TranslationType, Int,Expr)). | |
| 950 | mk_expr_aux(min_int,integer,TranslationType, Solver,_LS,_GS,Expr) :- | |
| 951 | !, | |
| 952 | get_preference(minint,MinInt), | |
| 953 | smt_solver_interface_call(Solver,mk_int_const(TranslationType, MinInt,Expr)). | |
| 954 | mk_expr_aux(max_int,integer,TranslationType, Solver,_LS,_GS,Expr) :- | |
| 955 | !, | |
| 956 | get_preference(maxint,MaxInt), | |
| 957 | smt_solver_interface_call(Solver,mk_int_const(TranslationType, MaxInt,Expr)). | |
| 958 | mk_expr_aux(boolean_true,boolean,_,Solver,_LS,_GS,Expr) :- | |
| 959 | !, | |
| 960 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)). | |
| 961 | mk_expr_aux(boolean_false,boolean,_,Solver,_LS,_GS,Expr) :- | |
| 962 | !, | |
| 963 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,Expr)). | |
| 964 | mk_expr_aux(string(S),string,TranslationType,Solver,_LS,_GS,Expr) :- | |
| 965 | !, | |
| 966 | smt_solver_interface_call(Solver,mk_string_const(TranslationType, S,Expr)). | |
| 967 | mk_expr_aux(truth,pred,_,Solver,_LS,_GS,Expr) :- | |
| 968 | !, | |
| 969 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)). | |
| 970 | mk_expr_aux(falsity,pred,_,Solver,_LS,_GS,Expr) :- | |
| 971 | !, | |
| 972 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,Expr)). | |
| 973 | mk_expr_aux(bool_set,set(boolean),TranslationType, Solver,_LS,_GS,Expr) :- | |
| 974 | !, | |
| 975 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,True)), | |
| 976 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,False)), | |
| 977 | smt_solver_interface_call(Solver,mk_set(TranslationType, [True,False],Expr)). | |
| 978 | mk_expr_aux(set_extension(List),set(T),TranslationType, Solver,LS,GS,Expr) :- | |
| 979 | !, | |
| 980 | maplist(mk_expr_maplist(TranslationType, Solver,LS,GS),List,SubExprs), | |
| 981 | ( SubExprs = [] | |
| 982 | -> smt_solver_interface_call(Solver,mk_empty_set(TranslationType, set(T),Expr)) | |
| 983 | ; smt_solver_interface_call(Solver,mk_set(TranslationType, SubExprs,Expr)) | |
| 984 | ). | |
| 985 | mk_expr_aux(empty_set,Type,TranslationType, Solver,_LS,_GS,Expr) :- | |
| 986 | !, | |
| 987 | smt_solver_interface_call(Solver,mk_empty_set(TranslationType, Type,Expr)). | |
| 988 | % given values | |
| 989 | mk_expr_aux(value(V),Type,TranslationType, Solver,LS,GS,Expr) :- | |
| 990 | !, | |
| 991 | mk_value(Type,V,TranslationType, Solver,LS,GS,Expr). | |
| 992 | % ast nodes that can be ignored | |
| 993 | mk_expr_aux(convert_bool(P),boolean,TranslationType, Solver,LS,GS,Expr) :- | |
| 994 | !, | |
| 995 | mk_expr(P,TranslationType, Solver,LS,GS,Expr). | |
| 996 | % lets | |
| 997 | mk_expr_aux(let_expression(ListOfIDs,ListOfDefinitions,LetExpression),_Type,TranslationType, Solver,LS,GS,Expr) :- | |
| 998 | create_let_state(ListOfIDs,ListOfDefinitions,TranslationType, Solver,LS,GS,NewLS), | |
| 999 | !, | |
| 1000 | mk_expr(LetExpression,TranslationType, Solver,NewLS,GS,Expr). | |
| 1001 | mk_expr_aux(let_predicate(ListOfIDs,ListOfDefinitions,LetExpression),pred,TranslationType, Solver,LS,GS,Expr) :- | |
| 1002 | create_let_state(ListOfIDs,ListOfDefinitions,TranslationType, Solver,LS,GS,NewLS), | |
| 1003 | !, | |
| 1004 | mk_expr(LetExpression,TranslationType, Solver,NewLS,GS,Expr). | |
| 1005 | % -- cases with functor: | |
| 1006 | mk_expr_aux(Op, Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 1007 | functor(Op, Functor, 1), | |
| 1008 | (Functor == pow_subset; Functor == pow1_subset; Functor == fin_subset; Functor == fin1_subset), | |
| 1009 | !, | |
| 1010 | arg(1, Op, A), | |
| 1011 | Type = set(set(InnerSetType)), | |
| 1012 | mk_expr(A, TranslationType, Solver, LS, GS, AE), | |
| 1013 | ( Functor == pow_subset | |
| 1014 | -> smt_solver_interface_call(Solver, mk_op_pow_subset(TranslationType, AE, set(InnerSetType), Expr)) | |
| 1015 | ; Functor == pow1_subset | |
| 1016 | -> smt_solver_interface_call(Solver, mk_op_pow1_subset(TranslationType, AE, set(InnerSetType), InnerSetType, Expr)) | |
| 1017 | ; Functor == fin_subset | |
| 1018 | -> smt_solver_interface_call(Solver, mk_op_fin_subset(TranslationType, AE, set(InnerSetType), Expr)) | |
| 1019 | ; smt_solver_interface_call(Solver, mk_op_fin1_subset(TranslationType, AE, set(InnerSetType), InnerSetType, Expr)) | |
| 1020 | ). | |
| 1021 | mk_expr_aux(Op, _, TranslationType, Solver, LS, GS, Expr) :- | |
| 1022 | functor(Op, Functor, 1), | |
| 1023 | (Functor == domain; Functor == range), | |
| 1024 | !, | |
| 1025 | arg(1, Op, A), | |
| 1026 | mk_expr(A, TranslationType, Solver, LS, GS, AE), | |
| 1027 | A = b(_,set(CoupleType),_), | |
| 1028 | CoupleType = couple(Prj1Type,Prj2Type), | |
| 1029 | ( Functor == domain | |
| 1030 | -> smt_solver_interface_call(Solver, mk_op_domain(TranslationType, AE, CoupleType, Prj1Type, Prj2Type, Expr)) | |
| 1031 | ; smt_solver_interface_call(Solver, mk_op_range(TranslationType, AE, CoupleType, Prj1Type, Prj2Type, Expr)) | |
| 1032 | ). | |
| 1033 | mk_expr_aux(Op, Type, TranslationType, Solver, LS, GS, Expr) :- | |
| 1034 | functor(Op, Functor, 2), | |
| 1035 | (Functor == domain_restriction; Functor == domain_subtraction; Functor == range_restriction; Functor == range_subtraction), | |
| 1036 | !, | |
| 1037 | Type = set(CoupleType), | |
| 1038 | arg(1, Op, A1), | |
| 1039 | arg(2, Op, A2), | |
| 1040 | mk_expr(A1, TranslationType, Solver, LS, GS, AE1), | |
| 1041 | mk_expr(A2, TranslationType, Solver, LS, GS, AE2), | |
| 1042 | ( Functor == domain_restriction | |
| 1043 | -> smt_solver_interface_call(Solver, mk_op_dom_res(TranslationType, AE1, AE2, CoupleType, Expr)) | |
| 1044 | ; Functor == domain_subtraction | |
| 1045 | -> smt_solver_interface_call(Solver, mk_op_dom_sub(TranslationType, AE1, AE2, CoupleType, Expr)) | |
| 1046 | ; Functor == range_restriction | |
| 1047 | -> smt_solver_interface_call(Solver, mk_op_ran_res(TranslationType, AE1, AE2, CoupleType, Expr)) | |
| 1048 | ; smt_solver_interface_call(Solver, mk_op_ran_sub(TranslationType, AE1, AE2, CoupleType, Expr)) | |
| 1049 | ). | |
| 1050 | mk_expr_aux(Op,_,TranslationType, Solver,LS,GS,Expr) :- | |
| 1051 | functor(Op,Functor,1), | |
| 1052 | unary_operator(Functor), | |
| 1053 | !, | |
| 1054 | arg(1,Op,A), | |
| 1055 | mk_expr(A,TranslationType, Solver,LS,GS,AE), | |
| 1056 | smt_solver_interface_call(Solver,mk_op_arglist(TranslationType, Functor, [AE], Expr)). | |
| 1057 | mk_expr_aux(Op, _, TranslationType, Solver, LS, GS, Expr) :- | |
| 1058 | functor(Op, Functor, 1), | |
| 1059 | ( Functor == general_union; Functor == general_intersection), | |
| 1060 | !, | |
| 1061 | arg(1, Op, A), | |
| 1062 | A = b(_,set(set(InnerType)),_), | |
| 1063 | mk_expr(A, TranslationType, Solver, LS, GS, AE), | |
| 1064 | ( Functor == general_union | |
| 1065 | -> smt_solver_interface_call(Solver, mk_op_general_union(TranslationType, AE, set(InnerType), InnerType, Expr)) | |
| 1066 | ; store_explicit_set_unique_id(A, UniqueIdName), | |
| 1067 | smt_solver_interface_call(Solver, mk_op_general_intersection(TranslationType, UniqueIdName, AE, set(InnerType), InnerType, Expr)) | |
| 1068 | ). | |
| 1069 | mk_expr_aux(Op,_,TranslationType, Solver,LS,GS,Expr) :- | |
| 1070 | functor(Op,Functor,2), | |
| 1071 | binary_operator(Functor), | |
| 1072 | !, | |
| 1073 | arg(1,Op,A), | |
| 1074 | mk_expr(A,TranslationType, Solver,LS,GS,AE), | |
| 1075 | arg(2,Op,B), | |
| 1076 | mk_expr(B,TranslationType, Solver,LS,GS,BE), | |
| 1077 | smt_solver_interface_call(Solver,mk_op(TranslationType, Functor,AE,BE,Expr)). | |
| 1078 | % error case | |
| 1079 | mk_expr_aux(Expr,_,_,_,_,_,_) :- !, | |
| 1080 | add_error_fail(smt_solvers_interface,'mk_expr failed',Expr). | |
| 1081 | ||
| 1082 | create_let_state([],[],_,_,S,_,S). | |
| 1083 | create_let_state([ID|IDs],[Def|Defs],TranslationType, Solver,StateSoFar,GS,State) :- | |
| 1084 | get_texpr_id(ID,UnwrappedId), | |
| 1085 | mk_expr(Def,TranslationType, Solver,StateSoFar,GS,Expr), | |
| 1086 | create_let_state(IDs,Defs,TranslationType, Solver,[id(UnwrappedId,Expr)|StateSoFar],GS,State). | |
| 1087 | ||
| 1088 | mk_value_maplist(Type,TranslationType, Solver,LS,GS,Val,Expr) :- | |
| 1089 | mk_value(Type,Val,TranslationType, Solver,LS,GS,Expr). | |
| 1090 | ||
| 1091 | mk_value(Type,Val,TranslationType, Solver,LS,GS,Expr) :- | |
| 1092 | (mk_value_aux(Type,Val,TranslationType, Solver,LS,GS,Expr) -> true). % avoid spurious error messages upon backtrack | |
| 1093 | ||
| 1094 | mk_value_aux(real,RealTerm,TranslationType, Solver,_LS,_GS,Expr) :- | |
| 1095 | ( RealTerm = term(floating(Real)) | |
| 1096 | ; RealTerm = real(Real) | |
| 1097 | ), | |
| 1098 | float(Real), | |
| 1099 | !, | |
| 1100 | number_codes(Real, RealCodes), | |
| 1101 | atom_codes(RealAtom, RealCodes), | |
| 1102 | smt_solver_interface_call(Solver,mk_real_const(TranslationType,RealAtom,Expr)). | |
| 1103 | mk_value_aux(real,real(RealAtom),TranslationType, Solver,_LS,_GS,Expr) :- | |
| 1104 | !, | |
| 1105 | smt_solver_interface_call(Solver,mk_real_const(TranslationType,RealAtom,Expr)). | |
| 1106 | mk_value_aux(string,string(Atom),TranslationType, Solver,_LS,_GS,Expr) :- | |
| 1107 | !, | |
| 1108 | smt_solver_interface_call(Solver,mk_string_const(TranslationType,Atom,Expr)). | |
| 1109 | mk_value_aux(integer,int(Int),TranslationType, Solver,_LS,_GS,Expr) :- | |
| 1110 | !, | |
| 1111 | smt_solver_interface_call(Solver,mk_int_const(TranslationType,Int,Expr)). | |
| 1112 | mk_value_aux(boolean,pred_false,_,Solver,_LS,_GS,Expr) :- | |
| 1113 | !, | |
| 1114 | smt_solver_interface_call(Solver,mk_bool_const(boolean_false,Expr)). | |
| 1115 | mk_value_aux(boolean,pred_true,_,Solver,_LS,_GS,Expr) :- | |
| 1116 | !, | |
| 1117 | smt_solver_interface_call(Solver,mk_bool_const(boolean_true,Expr)). | |
| 1118 | % only supported thanks to z3 full sets | |
| 1119 | mk_value_aux(set(integer),global_set('INTEGER'),TranslationType, z3,_LS,_GS,Expr) :- | |
| 1120 | !, | |
| 1121 | smt_solver_interface_call(z3,mk_full_set(TranslationType,set(integer),Expr)). | |
| 1122 | mk_value_aux(set(string),global_set('STRING'),TranslationType, z3,_LS,_GS,Expr) :- | |
| 1123 | !, | |
| 1124 | smt_solver_interface_call(z3,mk_full_set(TranslationType,set(string),Expr)). | |
| 1125 | mk_value_aux(set(global(X)),global_set(X),_,_Solver,LS,GS,Expr) :- | |
| 1126 | lookup(X,LS,GS,Expr). | |
| 1127 | mk_value_aux(set(X),avl_set(Val),TranslationType, Solver,LS,GS,Expr) :- | |
| 1128 | expand_custom_set_to_list_now(avl_set(Val),Values), | |
| 1129 | !, | |
| 1130 | mk_value(set(X),Values,TranslationType, Solver,LS,GS,Expr). | |
| 1131 | mk_value_aux(set(X),List,TranslationType, Solver,LS,GS,Expr) :- | |
| 1132 | maplist(mk_value_maplist(X,TranslationType, Solver,LS,GS),List,SubExprs), | |
| 1133 | !, | |
| 1134 | ( SubExprs = [] | |
| 1135 | -> smt_solver_interface_call(Solver,mk_empty_set(TranslationType,set(X),Expr)) | |
| 1136 | ; smt_solver_interface_call(Solver,mk_set(TranslationType,SubExprs,Expr)) | |
| 1137 | ). | |
| 1138 | mk_value_aux(couple(AT,BT),(A,B), TranslationType, Solver,LS,GS,Expr) :- | |
| 1139 | mk_value(AT,A,TranslationType, Solver,LS,GS,AE),!, | |
| 1140 | mk_value(BT,B,TranslationType, Solver,LS,GS,BE), | |
| 1141 | !, | |
| 1142 | smt_solver_interface_call(Solver,mk_couple(TranslationType, couple(AT,BT),AE,BE,Expr)). | |
| 1143 | mk_value_aux(record(FieldTypes), rec(Fields), TranslationType, Solver, LS, GS, Expr) :- | |
| 1144 | create_exprs_for_rec_value_fields(FieldTypes, Fields, TranslationType, Solver, LS, GS, SMTFieldExprs), | |
| 1145 | !, | |
| 1146 | smt_solver_interface_call(Solver, mk_record_const(TranslationType,record(FieldTypes),SMTFieldExprs,Expr)). | |
| 1147 | mk_value_aux(global(Name),fd(Num,Name),_,_Solver,LS,GS,Expr) :- | |
| 1148 | is_b_global_constant(Name,Num,Constant), | |
| 1149 | !, | |
| 1150 | lookup(Constant,LS,GS,Expr). | |
| 1151 | % error case | |
| 1152 | mk_value_aux(Type,Value,_,_,_,_,_) :- !, | |
| 1153 | add_error_fail(smt_solvers_interface,'mk_value failed',[Type,Value]). | |
| 1154 | ||
| 1155 | is_ground_real(b(unary_minus_real(Real),real,_)) :- | |
| 1156 | is_ground_real(Real). | |
| 1157 | is_ground_real(b(real(_),real,_)). | |
| 1158 | is_ground_real(b(value(_),real,_)). | |
| 1159 | ||
| 1160 | %% create_exprs_for_rec_value_fields(+FieldTypes, +Fields, +TranslationType, +Solver, +LS, +GS, -FieldExprs). | |
| 1161 | create_exprs_for_rec_value_fields([], [], _, _, _, _, []). | |
| 1162 | create_exprs_for_rec_value_fields([field(Name,Type)|TT], [field(Name,Value)|FT], TranslationType, Solver, LS, GS, [Expr|NT]) :- | |
| 1163 | mk_value(Type, Value, TranslationType, Solver, LS, GS, Expr), | |
| 1164 | create_exprs_for_rec_value_fields(TT, FT, TranslationType, Solver, LS, GS, NT). | |
| 1165 | ||
| 1166 | pairwise_union(_, [S],_Solver,Out) :- | |
| 1167 | !, | |
| 1168 | Out = S. | |
| 1169 | pairwise_union(TranslationType, [S|Sets],Solver,Expr) :- | |
| 1170 | pairwise_union(TranslationType, Sets,Solver,SS), | |
| 1171 | smt_solver_interface_call(Solver,mk_op(TranslationType,union,S,SS,Expr)). | |
| 1172 | ||
| 1173 | pairwise_disjoint(TranslationType, [H,T],Solver,EmptySet,Constraint) :- !, | |
| 1174 | pairwise_disjoint_mk_expr(TranslationType, Solver,H,T,EmptySet,Constraint). | |
| 1175 | pairwise_disjoint(TranslationType, [H|T],Solver,EmptySet,Constraint) :- | |
| 1176 | pairwise_disjoint(TranslationType, H,T,Solver,EmptySet,SubConstraints), | |
| 1177 | pairwise_disjoint(TranslationType, T,Solver,EmptySet,SubConstraint), | |
| 1178 | smt_solver_interface_call(Solver,mk_op_arglist(TranslationType,conjunct,[SubConstraint|SubConstraints],Constraint)). | |
| 1179 | ||
| 1180 | pairwise_disjoint(TranslationType, E,[Last],Solver,EmptySet,[C]) :- !, | |
| 1181 | pairwise_disjoint_mk_expr(TranslationType, Solver,E,Last,EmptySet,C). | |
| 1182 | pairwise_disjoint(TranslationType, E,[H|T],Solver,EmptySet,[C|Cs]) :- | |
| 1183 | pairwise_disjoint_mk_expr(TranslationType, Solver,E,H,EmptySet,C), | |
| 1184 | pairwise_disjoint(TranslationType, E,T,Solver,EmptySet,Cs). | |
| 1185 | ||
| 1186 | pairwise_disjoint_mk_expr(TranslationType, Solver,A,B,EmptySet,PWConstraint) :- | |
| 1187 | smt_solver_interface_call(Solver,mk_op(TranslationType,intersection,A,B,Inter)), | |
| 1188 | smt_solver_interface_call(Solver,mk_op(TranslationType,equal,Inter,EmptySet,PWConstraint)). | |
| 1189 | ||
| 1190 | mk_sort(TranslationType,Solver,Set) :- | |
| 1191 | smt_solver_interface_call(Solver,mk_sort(TranslationType,Set)). | |
| 1192 | ||
| 1193 | setup_deferred_sets(_, _, [], DefSetIdentifiers) :- | |
| 1194 | !, | |
| 1195 | DefSetIdentifiers = []. | |
| 1196 | setup_deferred_sets(TranslationType, Solver, DeferredSets, DefSetIdentifiers) :- | |
| 1197 | % deferred sets and which are either not unfixed or ProB's default set size preference is not considered -> only create a sort | |
| 1198 | maplist(mk_sort(TranslationType, Solver), DeferredSets), | |
| 1199 | mk_deferred_set_identifiers(TranslationType, Solver, DeferredSets, DefSetIdentifiers). | |
| 1200 | ||
| 1201 | %% create_virtual_enum_elms(+DefaultSetSize, +DefSet, -DefElms). | |
| 1202 | % For a deferred set D and preference DEFAULT_SETSIZE of 3 we create 'D1', 'D2', and 'D3'. | |
| 1203 | create_virtual_enum_elms(DefaultSetSize, DefSet, DefElms) :- | |
| 1204 | create_virtual_enum_elms(1, DefaultSetSize, DefSet, DefElms). | |
| 1205 | ||
| 1206 | create_virtual_enum_elms(Counter, DefaultSetSize, _, Out) :- | |
| 1207 | Counter > DefaultSetSize, | |
| 1208 | !, | |
| 1209 | Out = []. | |
| 1210 | create_virtual_enum_elms(Counter, DefaultSetSize, DefSet, [EnumElm|NT]) :- | |
| 1211 | number_codes(Counter, NC), | |
| 1212 | atom_codes(AC, NC), | |
| 1213 | atom_concat(DefSet, AC, EnumElm), | |
| 1214 | Counter1 is Counter + 1, | |
| 1215 | assert_virtual_deferred_set_id(EnumElm, fd(Counter,DefSet)), | |
| 1216 | create_virtual_enum_elms(Counter1, DefaultSetSize, DefSet, NT). | |
| 1217 | ||
| 1218 | prepare_unfixed_deferred_sets_with_virtual_elms(_, [], []). | |
| 1219 | prepare_unfixed_deferred_sets_with_virtual_elms(DefaultSetSize, [DefSet|T], [(DefSet,DefElms)|NT]) :- | |
| 1220 | ( get_user_defined_scope(DefSet,Low,Up,_Span) | |
| 1221 | -> % a specific deferred set's size might be user defined in the definitions | |
| 1222 | DeferredSetSize is 1+Up-Low | |
| 1223 | ; DeferredSetSize = DefaultSetSize | |
| 1224 | ), | |
| 1225 | create_virtual_enum_elms(DeferredSetSize, DefSet, DefElms), | |
| 1226 | prepare_unfixed_deferred_sets_with_virtual_elms(DefaultSetSize, T, NT). | |
| 1227 | ||
| 1228 | prepare_enumerated_sets_with_elms([], []). | |
| 1229 | prepare_enumerated_sets_with_elms([EnumSet|T], [(EnumSet,EnumElms)|NT]) :- | |
| 1230 | % find all global constants belonging to the given set | |
| 1231 | findall(Cst, is_b_global_constant(EnumSet, _, Cst), EnumElms), | |
| 1232 | prepare_enumerated_sets_with_elms(T, NT). | |
| 1233 | ||
| 1234 | setup_sets(TranslationType, Solver, GlobalIdentifiers) :- | |
| 1235 | ( get_preference(z3_solve_for_animation, true) | |
| 1236 | -> % Z3 behaves as ProB by considering DEFAULT_SETSIZE preference | |
| 1237 | findall(DS, (b_global_deferred_set(DS), unfixed_deferred_set(DS)), UnfixedDefSets), | |
| 1238 | get_preference(globalsets_fdrange, DefaultSetSize), | |
| 1239 | prepare_unfixed_deferred_sets_with_virtual_elms(DefaultSetSize, UnfixedDefSets, EnumDefSetPairs), | |
| 1240 | findall(DS, (b_global_deferred_set(DS), \+ unfixed_deferred_set(DS)), DeferredSets), | |
| 1241 | setup_deferred_sets(TranslationType, Solver, DeferredSets, DefSetIdentifiers) | |
| 1242 | ; % Z3 behaves differently compared to ProB if deferred sets are used | |
| 1243 | findall(X, b_global_deferred_set(X), DeferredSets), | |
| 1244 | setup_deferred_sets(TranslationType, Solver, DeferredSets, DefSetIdentifiers), | |
| 1245 | EnumDefSetPairs = [] | |
| 1246 | ), | |
| 1247 | % enumerated sets -> create a dedicated datatype in SMT-LIB | |
| 1248 | b_get_global_enumerated_sets(EnumeratedSets), | |
| 1249 | % can not use setof / bagof for some reason | |
| 1250 | list_to_set(EnumeratedSets, EnumeratedSetsNoDuplicates), | |
| 1251 | prepare_enumerated_sets_with_elms(EnumeratedSetsNoDuplicates, EnumSetPairs), | |
| 1252 | append(EnumSetPairs, EnumDefSetPairs, GlobalSetPairs), | |
| 1253 | maplist(setup_enumerated_set(TranslationType, Solver), GlobalSetPairs, IdentifierLists), | |
| 1254 | append([DefSetIdentifiers|IdentifierLists], GlobalIdentifiers). | |
| 1255 | ||
| 1256 | % currently only functional for z3 | |
| 1257 | mk_deferred_set_identifiers(_, cvc4, _, []). | |
| 1258 | mk_deferred_set_identifiers(TranslationType, z3, DeferredSets, DefSetIdentifiers) :- | |
| 1259 | maplist(mk_deferred_set_identifiers2(TranslationType), DeferredSets, DefSetIdentifiers). | |
| 1260 | ||
| 1261 | mk_deferred_set_identifiers2(TranslationType, SetName, id(SetName, SetExpression)) :- | |
| 1262 | smt_solver_interface_call(z3, mk_full_set(TranslationType, set(global(SetName)), SetExpression)). | |
| 1263 | ||
| 1264 | setup_enumerated_set(TranslationType, Solver, (SetName,SetElements), [SetIdentifier|Identifiers]) :- | |
| 1265 | %b_global_set_cardinality(SetName, Cardinality), % don't use b_global_set_cardinality/2 here since it can be different than the actual cardinality due to the preference globalsets_fdrange | |
| 1266 | length(SetElements, Cardinality), | |
| 1267 | % make a new sort and create identifiers | |
| 1268 | smt_solver_interface_call(Solver, mk_sort_with_cardinality(TranslationType, SetName, Cardinality, SetElements, EnumExprs)), | |
| 1269 | SetIdentifier = id(SetName, SetExpression), | |
| 1270 | create_enum_element_smt_state(SetElements, EnumExprs, Identifiers), | |
| 1271 | smt_solver_interface_call(Solver, mk_set(TranslationType, EnumExprs, SetExpression)). | |
| 1272 | ||
| 1273 | create_enum_element_smt_state([], [], []). | |
| 1274 | create_enum_element_smt_state([IdName|TIds], [EnumExpr|TExprs], [id(IdName,EnumExpr)|T]) :- | |
| 1275 | create_enum_element_smt_state(TIds, TExprs, T). | |
| 1276 | ||
| 1277 | create_smt_state(TranslationType, Solver,Identifiers,State,Exprs) :- | |
| 1278 | exclude(is_external_function_identifier,Identifiers,LessIdentifiers), | |
| 1279 | maplist(create_smt_identifier(TranslationType, Solver),LessIdentifiers,State,Exprs). | |
| 1280 | ||
| 1281 | create_bounded_smt_state(TranslationType, Solver,Identifiers,State,Exprs) :- | |
| 1282 | maplist(create_bounded_smt_identifier(TranslationType, Solver),Identifiers,State,Exprs). | |
| 1283 | ||
| 1284 | create_smt_identifier(TranslationType, Solver,b(identifier(Id),Type,_Infos),id(Id,Expr),Expr) :- | |
| 1285 | ground(Id), | |
| 1286 | !, | |
| 1287 | smt_solver_interface_call(Solver,mk_var(TranslationType, Type,Id,Expr)). | |
| 1288 | create_smt_identifier(_, _, b(identifier(_),Type,_Infos), _, _) :- | |
| 1289 | add_error_fail(create_smt_identifier, 'Identifier name is not ground for type ~w~n', [Type]). | |
| 1290 | ||
| 1291 | create_bounded_smt_identifier(TranslationType, Solver, b(identifier(Id),Type,_Infos), id(Id,Expr), Expr) :- | |
| 1292 | ground(Id), | |
| 1293 | !, | |
| 1294 | smt_solver_interface_call(Solver,mk_bounded_var(TranslationType, Type,Id,Expr)). | |
| 1295 | create_bounded_smt_identifier(_, _, b(identifier(_),Type,_Infos), _, _) :- | |
| 1296 | add_error_fail(create_bounded_smt_identifier, 'Identifier name is not ground for type ~w~n', [Type]). | |
| 1297 | ||
| 1298 | is_external_function_identifier(Id) :- | |
| 1299 | get_texpr_id(Id,Name), | |
| 1300 | is_external_function_name(Name). | |
| 1301 | ||
| 1302 | lookup(Id,LS,GS,Expr) :- | |
| 1303 | ( member(id(Id,Expr),LS) % id defined in local store | |
| 1304 | ; member(id(Id,Expr),GS) % id defined in global store | |
| 1305 | ). | |
| 1306 | ||
| 1307 | contains_unsupported_type_or_expression(TranslationType, Solver, TExpr) :- | |
| 1308 | contains_unsupported_type_or_expression(TranslationType, Solver, TExpr, _). | |
| 1309 | contains_unsupported_type_or_expression(TranslationType, Solver, TExpr, Unsupported) :- | |
| 1310 | map_over_typed_bexpr(smt_solvers_interface:contains_unsupported_aux(TranslationType, Solver), TExpr, Unsupported). | |
| 1311 | ||
| 1312 | :- public contains_unsupported_aux/4. | |
| 1313 | contains_unsupported_aux(TranslationType, Solver, TExpr, Expr) :- | |
| 1314 | get_texpr_expr(TExpr, Expr), | |
| 1315 | get_texpr_type(TExpr, Type), | |
| 1316 | ( unsupported_type(TranslationType, Type, Solver) | |
| 1317 | -> debug:debug_println(9,unsupported_type(TranslationType,Type,Solver)) | |
| 1318 | ; ( unsupported_expr(TranslationType, Expr, Type, Solver) | |
| 1319 | -> functor(Expr,F,A), | |
| 1320 | debug:debug_println(9,unsupported_expr(TranslationType,F/A)) | |
| 1321 | ) | |
| 1322 | ). | |
| 1323 | ||
| 1324 | % these expressions are not supported by one or more translation types | |
| 1325 | %% change in Z3: lambda inside recursive functions was declared unsupported until proper support is provided (see https://github.com/Z3Prover/z3/issues/5813) | |
| 1326 | %% see mk_op_iteration_func_decl in /extensions/z3interface/src/cpp/main.cpp | |
| 1327 | unsupported_expr(sat, Expr, _, _) :- | |
| 1328 | !, | |
| 1329 | \+ (Expr = conjunct(_,_); Expr = disjunct(_,_); Expr = identifier(_); Expr = equal(_,_); Expr = implication(_,_); Expr = equivalence(_,_); | |
| 1330 | Expr = negation(_); Expr = boolean_true; Expr = boolean_false; Expr = value(pred_true); Expr = value(pred_false)). | |
| 1331 | unsupported_expr(_, power_of_real(_,_),_,_). | |
| 1332 | unsupported_expr(_, struct(_),_,_). | |
| 1333 | unsupported_expr(constructive, closure(_),_,_). | |
| 1334 | unsupported_expr(constructive, iteration(_,_),_,_). | |
| 1335 | %% | |
| 1336 | unsupported_expr(axiomatic, general_union(_),_,_). | |
| 1337 | unsupported_expr(axiomatic, general_intersection(_),_,_). | |
| 1338 | unsupported_expr(_,general_product(_,_,_),_,_). | |
| 1339 | unsupported_expr(_,general_sum(_,_,_),_,_). | |
| 1340 | unsupported_expr(axiomatic, iteration(_,_),_,_). | |
| 1341 | unsupported_expr(axiomatic, closure(_),_,_). | |
| 1342 | unsupported_expr(_,external_pred_call(Pred,_),_,_) :- | |
| 1343 | Pred \= 'LEQ_SYM'. % introduced by symmetry breaking; we could also try and turn this off in ast_cleanup | |
| 1344 | unsupported_expr(_,external_function_call(_,_),_,_). | |
| 1345 | unsupported_expr(_,function(Name,_),_,_) :- | |
| 1346 | is_external_function_name(Name). | |
| 1347 | unsupported_expr(_, general_concat(_),_,_). | |
| 1348 | % the following exprs should have been removed by a rewrite rule | |
| 1349 | unsupported_expr(axiomatic, pow_subset(_),_,_). | |
| 1350 | unsupported_expr(axiomatic, pow1_subset(_),_,_). | |
| 1351 | unsupported_expr(axiomatic, fin_subset(_),_,_). | |
| 1352 | unsupported_expr(axiomatic, fin1_subset(_),_,_). | |
| 1353 | unsupported_expr(axiomatic, composition(_,_),_,_). | |
| 1354 | unsupported_expr(axiomatic, comprehension_set(_,_),_,_). | |
| 1355 | unsupported_expr(axiomatic, image(_,_),_,_). | |
| 1356 | unsupported_expr(axiomatic, reverse(_),_,_). | |
| 1357 | unsupported_expr(axiomatic, range(_),_,_). | |
| 1358 | unsupported_expr(axiomatic, domain(_),_,_). | |
| 1359 | unsupported_expr(_,min(_),_,_). | |
| 1360 | unsupported_expr(_,max(_),_,_). | |
| 1361 | unsupported_expr(_,card(_),_,_). | |
| 1362 | unsupported_expr(_,finite(_),_,_). | |
| 1363 | unsupported_expr(axiomatic, interval(_,_),_,_). | |
| 1364 | unsupported_expr(_,integer_set(_),_,_). | |
| 1365 | unsupported_expr(_,real_set(_),_,_). | |
| 1366 | unsupported_expr(_,float_set(_),_,_). | |
| 1367 | unsupported_expr(axiomatic,parallel_product(_,_),_,_). | |
| 1368 | unsupported_expr(axiomatic,direct_product(_,_),_,_). | |
| 1369 | unsupported_expr(axiomatic, domain_restriction(_,_),_,_). | |
| 1370 | unsupported_expr(axiomatic, range_restriction(_,_),_,_). | |
| 1371 | unsupported_expr(axiomatic, domain_subtraction(_,_),_,_). | |
| 1372 | unsupported_expr(axiomatic, range_subtraction(_,_),_,_). | |
| 1373 | unsupported_expr(_,overwrite(_,_),_,_). | |
| 1374 | unsupported_expr(axiomatic, cartesian_product(_,_),_,_). | |
| 1375 | unsupported_expr(_,function(_,_),_,_). | |
| 1376 | unsupported_expr(_,not_equal(_,_),_,_). | |
| 1377 | unsupported_expr(_,not_member(_,_),_,_). | |
| 1378 | unsupported_expr(_,relations(_,_),_,_). | |
| 1379 | unsupported_expr(_,partial_function(_,_),_,_). | |
| 1380 | unsupported_expr(_,total_function(_,_),_,_). | |
| 1381 | unsupported_expr(_,partial_injection(_,_),_,_). | |
| 1382 | unsupported_expr(_,total_injection(_,_),_,_). | |
| 1383 | unsupported_expr(_,partial_surjection(_,_),_,_). | |
| 1384 | unsupported_expr(_,total_surjection(_,_),_,_). | |
| 1385 | unsupported_expr(_,total_relation(_,_),_,_). | |
| 1386 | unsupported_expr(_,surjection_relation(_,_),_,_). | |
| 1387 | unsupported_expr(_,total_surjection_relation(_,_),_,_). | |
| 1388 | % certain values are not supported yet | |
| 1389 | unsupported_expr(_,value(X),_,_) :- \+ ground(X). % can not translate unknown values | |
| 1390 | unsupported_expr(TranslationType,value(couple(A,B)),couple(AT,BT),Solver) :- | |
| 1391 | unsupported_expr(TranslationType,value(A),AT,Solver) ; | |
| 1392 | unsupported_expr(TranslationType,value(B),BT,Solver). | |
| 1393 | unsupported_expr(_,value(global_set('INTEGER')),_,cvc4). | |
| 1394 | unsupported_expr(_,value(V),Type,_) :- | |
| 1395 | V \= [], % empty set can be translated | |
| 1396 | unsupported_value_type(Type). | |
| 1397 | unsupported_expr(_,value(fd(Num,SetName)),global(SetName),_) :- | |
| 1398 | \+ is_b_global_constant(SetName,Num,_). % has been invented by prob but is unnamed | |
| 1399 | % cvc4 does not support generating a full set of a sort, thus there | |
| 1400 | % is currently no way of expressing a complete deferred set | |
| 1401 | unsupported_expr(_,identifier(SetName),set(global(SetName)),cvc4). | |
| 1402 | ||
| 1403 | % some types are not supported / can not be translated at the moment | |
| 1404 | unsupported_type(sat,Type,_) :- | |
| 1405 | !, | |
| 1406 | \+ (Type == pred; Type == boolean). | |
| 1407 | unsupported_type(_,freetype,_). | |
| 1408 | unsupported_type(_,any,_). | |
| 1409 | unsupported_type(_,seq(_),_). % seq(S) is set(couple(integer,S)) and has been rewritten by seq_rewriter.pl | |
| 1410 | unsupported_type(TranslationType,set(X),S) :- | |
| 1411 | unsupported_type(TranslationType,X,S). | |
| 1412 | unsupported_type(TranslationType,couple(A,B),S) :- | |
| 1413 | unsupported_type(TranslationType,A,S) ; unsupported_type(TranslationType,B,S). | |
| 1414 | ||
| 1415 | % currently unsupported values | |
| 1416 | unsupported_value_type(set(T)) :- | |
| 1417 | unsupported_value_type(T). | |
| 1418 | unsupported_value_type(couple(A,B)) :- | |
| 1419 | unsupported_value_type(A) ; unsupported_value_type(B). | |
| 1420 | unsupported_value_type(global(S)) :- | |
| 1421 | unfixed_deferred_set(S). | |
| 1422 | ||
| 1423 | ||
| 1424 | % -------------------------------- | |
| 1425 | ||
| 1426 | % use_module(smt_solvers_interface(smt_solvers_interface)),smt_solvers_interface:smt_add_cnf([1,2,3],[[1],[2,3]]). | |
| 1427 | ||
| 1428 | smt_add_cnf(Literals,Clauses) :- | |
| 1429 | smt_add_cnf(z3sat,Literals,Clauses). | |
| 1430 | ||
| 1431 | :- dynamic stored_solver_cnf_reference/1, stored_literal_avl_map/1. | |
| 1432 | ||
| 1433 | :- use_module(library(avl),[list_to_avl/2, avl_fetch/3]). | |
| 1434 | smt_add_cnf(Solver,Literals,Clauses) :- | |
| 1435 | retractall(stored_solver_cnf_reference(_)), | |
| 1436 | retractall(stored_literal_avl_map(_)), | |
| 1437 | init_interface(Solver), | |
| 1438 | smt_reset_cnf(Solver), | |
| 1439 | format('Sending CNF to solver ~w~n',[Solver]), | |
| 1440 | start_ms_timer(T0), | |
| 1441 | maplist(add_literal(Solver),Literals,LitMap), | |
| 1442 | list_to_avl([pred_true-1,pred_false-2|LitMap],LitAvl), % not sure we need pred_true-1 and pred_false-2 map | |
| 1443 | assert(stored_literal_avl_map(LitAvl)),nl, | |
| 1444 | debug_format(9,'Registered literals: ~w~n',[LitMap]), | |
| 1445 | maplist(add_clause(Solver,LitAvl),Clauses,ClauseRefs), | |
| 1446 | smt_solver_interface_call(Solver,mk_op_arglist(sat,conjunct,ClauseRefs,CNFRef)), | |
| 1447 | tools:stop_ms_timer_with_msg(T0,sending_cnf_to_smt_solver(Solver)), | |
| 1448 | assert(stored_solver_cnf_reference(CNFRef)). | |
| 1449 | ||
| 1450 | add_clause(Solver,LitAvl,Clause,ClauseRef) :- | |
| 1451 | maplist(translate_literal(Solver,LitAvl),Clause,ExprList), | |
| 1452 | debug_format(9,'Sending clause to solver ~w~n',[ExprList]), | |
| 1453 | smt_solver_interface_call(Solver,mk_op_arglist(sat,disjunct,ExprList,ClauseRef)). | |
| 1454 | ||
| 1455 | smt_add_extra_clause_cnf(Solver,Clause) :- | |
| 1456 | retract(stored_solver_cnf_reference(CNFRef)), | |
| 1457 | stored_literal_avl_map(LitAvl),!, | |
| 1458 | add_clause(Solver,LitAvl,Clause,NewClauseRef), | |
| 1459 | smt_solver_interface_call(Solver,mk_op_arglist(sat,conjunct,[CNFRef,NewClauseRef],NewCNFRef)), | |
| 1460 | debug:debug_println(19,stored_new_clause(Clause)), | |
| 1461 | assert(stored_solver_cnf_reference(NewCNFRef)). | |
| 1462 | smt_add_extra_clause_cnf(Solver,Clause) :- | |
| 1463 | add_internal_error('No CNF stored for adding clause:',smt_add_extra_clause_cnf(Solver,Clause)),fail. | |
| 1464 | ||
| 1465 | ||
| 1466 | smt_solve_cnf(Solver,Model) :- | |
| 1467 | \+ stored_solver_cnf_reference(_),!, | |
| 1468 | add_internal_error('No CNF stored for solving:',smt_solve_cnf(Solver,Model)),fail. | |
| 1469 | smt_solve_cnf(Solver,Model) :- | |
| 1470 | stored_solver_cnf_reference(CNFRef), | |
| 1471 | start_ms_timer(T1), | |
| 1472 | get_preference(time_out, TO), | |
| 1473 | SelectedSolvers = [sat,sat_cdcl], | |
| 1474 | AxmRef = -1, % do not solve anything with axiomatic and constructive z3 solver | |
| 1475 | CnsRef = -1, | |
| 1476 | smt_solver_interface_call(z3, z3interface:smt_solve_query(SelectedSolvers,AxmRef,CnsRef,CNFRef,TO,SMTResultData)), | |
| 1477 | tools:stop_ms_timer_with_msg(T1,solving_cnf_with_smt_solver(Solver)), | |
| 1478 | (debug_mode(off) -> true | |
| 1479 | ; write('; SMT TRANSLATION: '), nl, pretty_print_smt(z3), nl | |
| 1480 | ), | |
| 1481 | write(result_data(SMTResultData)),nl, | |
| 1482 | SMTResultData = result_tuple(_,SMTResult), | |
| 1483 | ( SMTResult=sat | |
| 1484 | -> %smt_solver_interface_call(z3,get_full_model_string(FullModel)), | |
| 1485 | model_translation:get_full_model_as_avl(Solver,AVL), | |
| 1486 | %avl:portray_avl(AVL),nl, | |
| 1487 | avl:avl_to_list(AVL,List), | |
| 1488 | convert_to_cnf_model(List,1,Model) | |
| 1489 | ; write('UNSAT'),nl,flush_output, | |
| 1490 | fail | |
| 1491 | ). | |
| 1492 | ||
| 1493 | ||
| 1494 | smt_reset_cnf(_Solver) :- clear_state. | |
| 1495 | ||
| 1496 | convert_to_cnf_model([],_,R) :- !, R=[]. | |
| 1497 | convert_to_cnf_model([_-X|T],Nr,[Lit|TM]) :- | |
| 1498 | is_bool(X,Val),!, | |
| 1499 | (Val=true -> Lit=Nr ; Lit is -Nr), | |
| 1500 | N1 is Nr+1, | |
| 1501 | convert_to_cnf_model(T,N1,TM). | |
| 1502 | convert_to_cnf_model(L,_,R) :- add_error(smt_solvers_interface,'Invalid model value:',L),R=[]. | |
| 1503 | ||
| 1504 | is_bool('z3-define-fun'([],'Bool',Val),Val). | |
| 1505 | ||
| 1506 | ||
| 1507 | %:- use_module(probsrc(tools_meta), [translate_term_into_atom/2]). | |
| 1508 | add_literal(Solver,Number,Number-Z3Ref) :- | |
| 1509 | number_to_atom(Number,Atom), | |
| 1510 | smt_solver_interface_call(Solver,mk_bounded_var(sat,boolean,Atom,Z3Ref)). | |
| 1511 | ||
| 1512 | lookup_literal(Literal,LitAvl,Z3Expr) :- | |
| 1513 | avl_fetch(Literal,LitAvl,Z3Expr). | |
| 1514 | ||
| 1515 | % we need to ensure that atoms have same order as numbers; otherwise we need to sort model | |
| 1516 | number_to_atom(Nr,Atom) :- number_codes(Nr,C), | |
| 1517 | gen_leading_zeros(Nr,9999999,C0s,C), | |
| 1518 | (10*Nr>=9999999 -> add_warning(smt_solvers_interface,'Too many SAT variables:',Nr) ; true), | |
| 1519 | atom_codes(Atom,[0'x|C0s]). | |
| 1520 | ||
| 1521 | gen_leading_zeros(Nr,Lim) --> {Nr>Lim},!. | |
| 1522 | gen_leading_zeros(Nr,Lim) --> [0'0], {N1 is Nr*10}, gen_leading_zeros(N1,Lim). | |
| 1523 | ||
| 1524 | ||
| 1525 | translate_literal(Solver,LitAvl,neg(PLiteral),LitRef) :- !, | |
| 1526 | lookup_literal(PLiteral,LitAvl,Z3Expr) , | |
| 1527 | smt_solver_interface_call(Solver,mk_op_arglist(sat,negation,[Z3Expr],LitRef)). | |
| 1528 | translate_literal(_Solver,LitAvl,Literal,Z3Expr) :- | |
| 1529 | (prob_pred_literal(Literal) ; Literal > 0), | |
| 1530 | !, | |
| 1531 | lookup_literal(Literal,LitAvl,Z3Expr). | |
| 1532 | translate_literal(Solver,LitAvl,Literal,LitRef) :- | |
| 1533 | Literal < 0, | |
| 1534 | PLiteral is Literal * -1, | |
| 1535 | translate_literal(Solver,LitAvl,neg(PLiteral),LitRef). | |
| 1536 | ||
| 1537 | prob_pred_literal(pred_true). | |
| 1538 | prob_pred_literal(pred_false). | |
| 1539 | ||
| 1540 |