diff --git a/examples/interp/iz3.cpp b/examples/interp/iz3.cpp deleted file mode 100755 index 21ea518a6..000000000 --- a/examples/interp/iz3.cpp +++ /dev/null @@ -1,458 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -#include -#include -#include -#include -#include -#include "z3.h" - - - -int usage(const char **argv){ - std::cerr << "usage: " << argv[0] << " [options] file.smt" << std::endl; - std::cerr << std::endl; - std::cerr << "options:" << std::endl; - std::cerr << " -t,--tree tree interpolation" << std::endl; - std::cerr << " -c,--check check result" << std::endl; - std::cerr << " -p,--profile profile execution" << std::endl; - std::cerr << " -w,--weak weak interpolants" << std::endl; - std::cerr << " -f,--flat ouput flat formulas" << std::endl; - std::cerr << " -o ouput to SMT-LIB file" << std::endl; - std::cerr << " -a,--anon anonymize" << std::endl; - std::cerr << " -s,--simple simple proof mode" << std::endl; - std::cerr << std::endl; - return 1; -} - -int main(int argc, const char **argv) { - - bool tree_mode = false; - bool check_mode = false; - bool profile_mode = false; - bool incremental_mode = false; - std::string output_file; - bool flat_mode = false; - bool anonymize = false; - bool write = false; - - Z3_config cfg = Z3_mk_config(); - // Z3_interpolation_options options = Z3_mk_interpolation_options(); - // Z3_params options = 0; - - /* Parse the command line */ - int argn = 1; - while(argn < argc-1){ - std::string flag = argv[argn]; - if(flag[0] == '-'){ - if(flag == "-t" || flag == "--tree") - tree_mode = true; - else if(flag == "-c" || flag == "--check") - check_mode = true; - else if(flag == "-p" || flag == "--profile") - profile_mode = true; -#if 0 - else if(flag == "-w" || flag == "--weak") - Z3_set_interpolation_option(options,"weak","1"); - else if(flag == "--secondary") - Z3_set_interpolation_option(options,"secondary","1"); -#endif - else if(flag == "-i" || flag == "--incremental") - incremental_mode = true; - else if(flag == "-o"){ - argn++; - if(argn >= argc) return usage(argv); - output_file = argv[argn]; - } - else if(flag == "-f" || flag == "--flat") - flat_mode = true; - else if(flag == "-a" || flag == "--anon") - anonymize = true; - else if(flag == "-w" || flag == "--write") - write = true; - else if(flag == "-s" || flag == "--simple") - Z3_set_param_value(cfg,"PREPROCESS","false"); - else - return usage(argv); - } - argn++; - } - if(argn != argc-1) - return usage(argv); - const char *filename = argv[argn]; - - - /* Create a Z3 context to contain formulas */ - Z3_context ctx = Z3_mk_interpolation_context(cfg); - - if(write || anonymize) - Z3_set_ast_print_mode(ctx,Z3_PRINT_SMTLIB2_COMPLIANT); - else if(!flat_mode) - Z3_set_ast_print_mode(ctx,Z3_PRINT_SMTLIB_COMPLIANT); - - /* Read an interpolation problem */ - - unsigned num; - Z3_ast *constraints; - unsigned *parents = 0; - const char *error; - bool ok; - unsigned num_theory; - Z3_ast *theory; - - ok = Z3_read_interpolation_problem(ctx, &num, &constraints, tree_mode ? &parents : 0, filename, &error, &num_theory, &theory) != 0; - - /* If parse failed, print the error message */ - - if(!ok){ - std::cerr << error << "\n"; - return 1; - } - - /* if we get only one formula, and it is a conjunction, split it into conjuncts. */ - if(!tree_mode && num == 1){ - Z3_app app = Z3_to_app(ctx,constraints[0]); - Z3_func_decl func = Z3_get_app_decl(ctx,app); - Z3_decl_kind dk = Z3_get_decl_kind(ctx,func); - if(dk == Z3_OP_AND){ - int nconjs = Z3_get_app_num_args(ctx,app); - if(nconjs > 1){ - std::cout << "Splitting formula into " << nconjs << " conjuncts...\n"; - num = nconjs; - constraints = new Z3_ast[num]; - for(unsigned k = 0; k < num; k++) - constraints[k] = Z3_get_app_arg(ctx,app,k); - } - } - } - - /* Write out anonymized version. */ - - if(write || anonymize){ -#if 0 - Z3_anonymize_ast_vector(ctx,num,constraints); -#endif - std::string ofn = output_file.empty() ? "iz3out.smt2" : output_file; - Z3_write_interpolation_problem(ctx, num, constraints, parents, ofn.c_str(), num_theory, theory); - std::cout << "anonymized problem written to " << ofn << "\n"; - exit(0); - } - - /* Compute an interpolant, or get a model. */ - - Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast)); - Z3_model model = 0; - Z3_lbool result; - - if(!incremental_mode){ - /* In non-incremental mode, we just pass the constraints. */ - result = Z3_L_UNDEF; // FIXME: Z3_interpolate(ctx, num, constraints, parents, options, interpolants, &model, 0, false, num_theory, theory); - } - else { - - /* This is a somewhat useless demonstration of incremental mode. - Here, we assert the constraints in the context, then pass them to - iZ3 in an array, so iZ3 knows the sequence. Note it's safe to pass - "true", even though we haven't techically asserted if. */ - - Z3_push(ctx); - std::vector asserted(num); - - /* We start with nothing asserted. */ - for(unsigned i = 0; i < num; i++) - asserted[i] = Z3_mk_true(ctx); - - /* Now we assert the constrints one at a time until UNSAT. */ - - for(unsigned i = 0; i < num; i++){ - asserted[i] = constraints[i]; - Z3_assert_cnstr(ctx,constraints[i]); // assert one constraint - result = Z3_L_UNDEF; // FIXME: Z3_interpolate(ctx, num, &asserted[0], parents, options, interpolants, &model, 0, true, 0, 0); - if(result == Z3_L_FALSE){ - for(unsigned j = 0; j < num-1; j++) - /* Since we want the interpolant formulas to survive a "pop", we - "persist" them here. */ - Z3_persist_ast(ctx,interpolants[j],1); - break; - } - } - Z3_pop(ctx,1); - } - - switch (result) { - - /* If UNSAT, print the interpolants */ - case Z3_L_FALSE: - printf("unsat\n"); - if(output_file.empty()){ - printf("interpolant:\n"); - for(unsigned i = 0; i < num-1; i++) - printf("%s\n", Z3_ast_to_string(ctx, interpolants[i])); - } - else { -#if 0 - Z3_write_interpolation_problem(ctx,num-1,interpolants,0,output_file.c_str()); - printf("interpolant written to %s\n",output_file.c_str()); -#endif - } -#if 1 - if(check_mode){ - std::cout << "Checking interpolant...\n"; - bool chk; - chk = Z3_check_interpolant(ctx,num,constraints,parents,interpolants,&error,num_theory,theory) != 0; - if(chk) - std::cout << "Interpolant is correct\n"; - else { - std::cout << "Interpolant is incorrect\n"; - std::cout << error; - return 1; - } - } -#endif - break; - case Z3_L_UNDEF: - printf("fail\n"); - break; - case Z3_L_TRUE: - printf("sat\n"); - printf("model:\n%s\n", Z3_model_to_string(ctx, model)); - break; - } - - if(profile_mode) - std::cout << Z3_interpolation_profile(ctx); - - /* Delete the model if there is one */ - - if (model) - Z3_del_model(ctx, model); - - /* Delete logical context. */ - - Z3_del_context(ctx); - free(interpolants); - - return 0; -} - - -#if 0 - - - -int test(){ - int i; - - /* Create a Z3 context to contain formulas */ - - Z3_config cfg = Z3_mk_config(); - Z3_context ctx = iz3_mk_context(cfg); - - int num = 2; - - Z3_ast *constraints = (Z3_ast *)malloc(num * sizeof(Z3_ast)); - -#if 1 - Z3_sort arr = Z3_mk_array_sort(ctx,Z3_mk_int_sort(ctx),Z3_mk_bool_sort(ctx)); - Z3_symbol as = Z3_mk_string_symbol(ctx, "a"); - Z3_symbol bs = Z3_mk_string_symbol(ctx, "b"); - Z3_symbol xs = Z3_mk_string_symbol(ctx, "x"); - - Z3_ast a = Z3_mk_const(ctx,as,arr); - Z3_ast b = Z3_mk_const(ctx,bs,arr); - Z3_ast x = Z3_mk_const(ctx,xs,Z3_mk_int_sort(ctx)); - - Z3_ast c1 = Z3_mk_eq(ctx,a,Z3_mk_store(ctx,b,x,Z3_mk_true(ctx))); - Z3_ast c2 = Z3_mk_not(ctx,Z3_mk_select(ctx,a,x)); -#else - Z3_symbol xs = Z3_mk_string_symbol(ctx, "x"); - Z3_ast x = Z3_mk_const(ctx,xs,Z3_mk_bool_sort(ctx)); - Z3_ast c1 = Z3_mk_eq(ctx,x,Z3_mk_true(ctx)); - Z3_ast c2 = Z3_mk_eq(ctx,x,Z3_mk_false(ctx)); - -#endif - - constraints[0] = c1; - constraints[1] = c2; - - /* print out the result for grins. */ - - // Z3_string smtout = Z3_benchmark_to_smtlib_string (ctx, "foo", "QFLIA", "sat", "", num, constraints, Z3_mk_true(ctx)); - - // Z3_string smtout = Z3_ast_to_string(ctx,constraints[0]); - // Z3_string smtout = Z3_context_to_string(ctx); - // puts(smtout); - - iz3_print(ctx,num,constraints,"iZ3temp.smt"); - - /* Make room for interpolants. */ - - Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast)); - - /* Make room for the model. */ - - Z3_model model = 0; - - /* Call the prover */ - - Z3_lbool result = iz3_interpolate(ctx, num, constraints, interpolants, &model); - - switch (result) { - - /* If UNSAT, print the interpolants */ - case Z3_L_FALSE: - printf("unsat, interpolants:\n"); - for(i = 0; i < num-1; i++) - printf("%s\n", Z3_ast_to_string(ctx, interpolants[i])); - break; - case Z3_L_UNDEF: - printf("fail\n"); - break; - case Z3_L_TRUE: - printf("sat\n"); - printf("model:\n%s\n", Z3_model_to_string(ctx, model)); - break; - } - - /* Delete the model if there is one */ - - if (model) - Z3_del_model(ctx, model); - - /* Delete logical context (note, we call iz3_del_context, not - Z3_del_context */ - - iz3_del_context(ctx); - - return 1; -} - -struct z3_error { - Z3_error_code c; - z3_error(Z3_error_code _c) : c(_c) {} -}; - -extern "C" { - static void throw_z3_error(Z3_error_code c){ - throw z3_error(c); - } -} - -int main(int argc, const char **argv) { - - /* Create a Z3 context to contain formulas */ - - Z3_config cfg = Z3_mk_config(); - Z3_context ctx = iz3_mk_context(cfg); - Z3_set_error_handler(ctx, throw_z3_error); - - /* Make some constraints, by parsing an smtlib formatted file given as arg 1 */ - - try { - Z3_parse_smtlib_file(ctx, argv[1], 0, 0, 0, 0, 0, 0); - } - catch(const z3_error &err){ - std::cerr << "Z3 error: " << Z3_get_error_msg(err.c) << "\n"; - std::cerr << Z3_get_smtlib_error(ctx) << "\n"; - return(1); - } - - /* Get the constraints from the parser. */ - - int num = Z3_get_smtlib_num_formulas(ctx); - - if(num == 0){ - std::cerr << "iZ3 error: File contains no formulas.\n"; - return 1; - } - - - Z3_ast *constraints = (Z3_ast *)malloc(num * sizeof(Z3_ast)); - - int i; - for (i = 0; i < num; i++) - constraints[i] = Z3_get_smtlib_formula(ctx, i); - - /* if we get only one formula, and it is a conjunction, split it into conjuncts. */ - if(num == 1){ - Z3_app app = Z3_to_app(ctx,constraints[0]); - Z3_func_decl func = Z3_get_app_decl(ctx,app); - Z3_decl_kind dk = Z3_get_decl_kind(ctx,func); - if(dk == Z3_OP_AND){ - int nconjs = Z3_get_app_num_args(ctx,app); - if(nconjs > 1){ - std::cout << "Splitting formula into " << nconjs << " conjuncts...\n"; - num = nconjs; - constraints = new Z3_ast[num]; - for(int k = 0; k < num; k++) - constraints[k] = Z3_get_app_arg(ctx,app,k); - } - } - } - - - /* print out the result for grins. */ - - // Z3_string smtout = Z3_benchmark_to_smtlib_string (ctx, "foo", "QFLIA", "sat", "", num, constraints, Z3_mk_true(ctx)); - - // Z3_string smtout = Z3_ast_to_string(ctx,constraints[0]); - // Z3_string smtout = Z3_context_to_string(ctx); - // puts(smtout); - - // iz3_print(ctx,num,constraints,"iZ3temp.smt"); - - /* Make room for interpolants. */ - - Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast)); - - /* Make room for the model. */ - - Z3_model model = 0; - - /* Call the prover */ - - Z3_lbool result = iz3_interpolate(ctx, num, constraints, interpolants, &model); - - switch (result) { - - /* If UNSAT, print the interpolants */ - case Z3_L_FALSE: - printf("unsat, interpolants:\n"); - for(i = 0; i < num-1; i++) - printf("%s\n", Z3_ast_to_string(ctx, interpolants[i])); - std::cout << "Checking interpolants...\n"; - const char *error; - if(iZ3_check_interpolant(ctx, num, constraints, 0, interpolants, &error)) - std::cout << "Interpolant is correct\n"; - else { - std::cout << "Interpolant is incorrect\n"; - std::cout << error << "\n"; - } - break; - case Z3_L_UNDEF: - printf("fail\n"); - break; - case Z3_L_TRUE: - printf("sat\n"); - printf("model:\n%s\n", Z3_model_to_string(ctx, model)); - break; - } - - /* Delete the model if there is one */ - - if (model) - Z3_del_model(ctx, model); - - /* Delete logical context (note, we call iz3_del_context, not - Z3_del_context */ - - iz3_del_context(ctx); - - return 0; -} - -#endif diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 2863de628..dfe801bdd 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -94,7 +94,6 @@ def init_project_def(): set_z3py_dir('api/python') # Examples add_cpp_example('cpp_example', 'c++') - add_cpp_example('iz3', 'interp') add_cpp_example('z3_tptp', 'tptp') add_c_example('c_example', 'c') add_c_example('maxsat') diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 0baed2968..67b60cbaf 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -90,7 +90,13 @@ FPMATH="Default" FPMATH_FLAGS="-mfpmath=sse -msse -msse2" def check_output(cmd): - return (subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0]).decode("utf-8").rstrip('\r\n') + out = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] + if out != None: + enc = sys.stdout.encoding + if enc != None: return out.decode(enc).rstrip('\r\n') + else: return out.rstrip('\r\n') + else: + return "" def git_hash(): try: @@ -2586,7 +2592,7 @@ def mk_z3consts_py(api_files): if Z3PY_SRC_DIR is None: raise MKException("You must invoke set_z3py_dir(path):") - blank_pat = re.compile("^ *$") + blank_pat = re.compile("^ *\r?$") comment_pat = re.compile("^ *//.*$") typedef_pat = re.compile("typedef enum *") typedef2_pat = re.compile("typedef enum { *") @@ -2647,6 +2653,8 @@ def mk_z3consts_py(api_files): z3consts.write('%s = %s\n' % (k, i)) z3consts.write('\n') mode = SEARCHING + elif len(words) <= 2: + assert False, "Invalid %s, line: %s" % (api_file, linenum) else: if words[2] != '': if len(words[2]) > 1 and words[2][1] == 'x': @@ -2664,7 +2672,7 @@ def mk_z3consts_py(api_files): # Extract enumeration types from z3_api.h, and add .Net definitions def mk_z3consts_dotnet(api_files): - blank_pat = re.compile("^ *$") + blank_pat = re.compile("^ *\r?$") comment_pat = re.compile("^ *//.*$") typedef_pat = re.compile("typedef enum *") typedef2_pat = re.compile("typedef enum { *") @@ -2734,6 +2742,8 @@ def mk_z3consts_dotnet(api_files): z3consts.write(' %s = %s,\n' % (k, i)) z3consts.write(' }\n\n') mode = SEARCHING + elif len(words) <= 2: + assert False, "Invalid %s, line: %s" % (api_file, linenum) else: if words[2] != '': if len(words[2]) > 1 and words[2][1] == 'x': diff --git a/scripts/update_api.py b/scripts/update_api.py index 0b6ddfb32..6e7b6d5f7 100644 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -96,7 +96,12 @@ if sys.version < '3': return s else: def _to_pystr(s): - return s.decode('utf-8') + if s != None: + enc = sys.stdout.encoding + if enc != None: return s.decode(enc) + else: return s.decode('ascii') + else: + return "" def init(PATH): global _lib diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index de4d6f4e6..d3dda5d9d 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -187,7 +187,8 @@ extern "C" { MK_BINARY(Z3_mk_set_difference, mk_c(c)->get_array_fid(), OP_SET_DIFFERENCE, SKIP); MK_UNARY(Z3_mk_set_complement, mk_c(c)->get_array_fid(), OP_SET_COMPLEMENT, SKIP); MK_BINARY(Z3_mk_set_subset, mk_c(c)->get_array_fid(), OP_SET_SUBSET, SKIP); - + MK_BINARY(Z3_mk_array_ext, mk_c(c)->get_array_fid(), OP_ARRAY_EXT, SKIP); + Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) { return Z3_mk_select(c, set, elem); } diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 15a9f5bae..200b483cf 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1012,6 +1012,7 @@ extern "C" { case OP_SET_COMPLEMENT: return Z3_OP_SET_COMPLEMENT; case OP_SET_SUBSET: return Z3_OP_SET_SUBSET; case OP_AS_ARRAY: return Z3_OP_AS_ARRAY; + case OP_ARRAY_EXT: return Z3_OP_ARRAY_EXT; default: UNREACHABLE(); return Z3_OP_UNINTERPRETED; diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index f17a296fa..6749f1525 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -103,9 +103,7 @@ namespace api { m_smtlib_parser = 0; m_smtlib_parser_has_decls = false; - - z3_bound_num_procs(); - + m_error_handler = &default_error_handler; m_basic_fid = m().get_basic_family_id(); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 4daf3956f..6112a8cd2 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -97,6 +97,20 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_solver Z3_API Z3_solver_translate(Z3_context c, Z3_solver s, Z3_context target) { + Z3_TRY; + LOG_Z3_solver_translate(c, s, target); + RESET_ERROR_CODE(); + params_ref const& p = to_solver(s)->m_params; + Z3_solver_ref * sr = alloc(Z3_solver_ref, 0); + init_solver(c, s); + sr->m_solver = to_solver(s)->m_solver->translate(mk_c(target)->m(), p); + mk_c(target)->save_object(sr); + Z3_solver r = of_solver(sr); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + Z3_string Z3_API Z3_solver_get_help(Z3_context c, Z3_solver s) { Z3_TRY; LOG_Z3_solver_get_help(c, s); diff --git a/src/api/api_solver_old.cpp b/src/api/api_solver_old.cpp index 7e994a0e2..fbd57ad97 100644 --- a/src/api/api_solver_old.cpp +++ b/src/api/api_solver_old.cpp @@ -23,6 +23,8 @@ Revision History: #include"api_context.h" #include"api_model.h" #include"cancel_eh.h" +#include"scoped_timer.h" +#include"rlimit.h" extern "C" { @@ -34,7 +36,7 @@ extern "C" { mk_c(c)->push(); Z3_CATCH; } - + void Z3_API Z3_pop(Z3_context c, unsigned num_scopes) { Z3_TRY; LOG_Z3_pop(c, num_scopes); @@ -62,7 +64,7 @@ extern "C" { Z3_TRY; LOG_Z3_assert_cnstr(c, a); RESET_ERROR_CODE(); - CHECK_FORMULA(a,); + CHECK_FORMULA(a,); mk_c(c)->assert_cnstr(to_expr(a)); Z3_CATCH; } @@ -75,17 +77,22 @@ extern "C" { cancel_eh eh(mk_c(c)->get_smt_kernel()); api::context::set_interruptable si(*(mk_c(c)), eh); flet _model(mk_c(c)->fparams().m_model, true); + unsigned timeout = mk_c(c)->params().m_timeout; + unsigned rlimit = mk_c(c)->params().m_rlimit; lbool result; try { + scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); + model_ref _m; result = mk_c(c)->check(_m); if (m) { if (_m) { - Z3_model_ref * m_ref = alloc(Z3_model_ref); + Z3_model_ref * m_ref = alloc(Z3_model_ref); m_ref->m_model = _m; // Must bump reference counter for backward compatibility reasons. // Don't need to invoke save_object, since the counter was bumped - m_ref->inc_ref(); + m_ref->inc_ref(); *m = of_model(m_ref); } else { @@ -100,21 +107,21 @@ extern "C" { RETURN_Z3_check_and_get_model static_cast(result); Z3_CATCH_RETURN(Z3_L_UNDEF); } - + Z3_lbool Z3_API Z3_check(Z3_context c) { Z3_TRY; - // This is just syntax sugar... - RESET_ERROR_CODE(); + // This is just syntax sugar... + RESET_ERROR_CODE(); CHECK_SEARCHING(c); Z3_lbool r = Z3_check_and_get_model(c, 0); return r; Z3_CATCH_RETURN(Z3_L_UNDEF); } - - Z3_lbool Z3_API Z3_check_assumptions(Z3_context c, - unsigned num_assumptions, Z3_ast const assumptions[], - Z3_model * m, Z3_ast* proof, + + Z3_lbool Z3_API Z3_check_assumptions(Z3_context c, + unsigned num_assumptions, Z3_ast const assumptions[], + Z3_model * m, Z3_ast* proof, unsigned* core_size, Z3_ast core[]) { Z3_TRY; LOG_Z3_check_assumptions(c, num_assumptions, assumptions, m, proof, core_size, core); @@ -130,11 +137,11 @@ extern "C" { model_ref _m; mk_c(c)->get_smt_kernel().get_model(_m); if (_m) { - Z3_model_ref * m_ref = alloc(Z3_model_ref); + Z3_model_ref * m_ref = alloc(Z3_model_ref); m_ref->m_model = _m; // Must bump reference counter for backward compatibility reasons. // Don't need to invoke save_object, since the counter was bumped - m_ref->inc_ref(); + m_ref->inc_ref(); *m = of_model(m_ref); } else { @@ -159,7 +166,7 @@ extern "C" { else if (proof) { *proof = 0; // breaks abstraction. } - RETURN_Z3_check_assumptions static_cast(result); + RETURN_Z3_check_assumptions static_cast(result); Z3_CATCH_RETURN(Z3_L_UNDEF); } @@ -185,7 +192,7 @@ extern "C" { symbol const& get_label() const { return m_label; } expr* get_literal() { return m_literal.get(); } }; - + typedef vector labels; Z3_literals Z3_API Z3_get_relevant_labels(Z3_context c) { @@ -196,7 +203,7 @@ extern "C" { ast_manager& m = mk_c(c)->m(); expr_ref_vector lits(m); mk_c(c)->get_smt_kernel().get_relevant_labels(0, labl_syms); - mk_c(c)->get_smt_kernel().get_relevant_labeled_literals(mk_c(c)->fparams().m_at_labels_cex, lits); + mk_c(c)->get_smt_kernel().get_relevant_labeled_literals(mk_c(c)->fparams().m_at_labels_cex, lits); labels* lbls = alloc(labels); SASSERT(labl_syms.size() == lits.size()); for (unsigned i = 0; i < lits.size(); ++i) { @@ -212,12 +219,12 @@ extern "C" { RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); expr_ref_vector lits(m); - mk_c(c)->get_smt_kernel().get_relevant_literals(lits); + mk_c(c)->get_smt_kernel().get_relevant_literals(lits); labels* lbls = alloc(labels); for (unsigned i = 0; i < lits.size(); ++i) { lbls->push_back(labeled_literal(m,lits[i].get())); } - RETURN_Z3(reinterpret_cast(lbls)); + RETURN_Z3(reinterpret_cast(lbls)); Z3_CATCH_RETURN(0); } @@ -227,12 +234,12 @@ extern "C" { RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); expr_ref_vector lits(m); - mk_c(c)->get_smt_kernel().get_guessed_literals(lits); + mk_c(c)->get_smt_kernel().get_guessed_literals(lits); labels* lbls = alloc(labels); for (unsigned i = 0; i < lits.size(); ++i) { lbls->push_back(labeled_literal(m,lits[i].get())); } - RETURN_Z3(reinterpret_cast(lbls)); + RETURN_Z3(reinterpret_cast(lbls)); Z3_CATCH_RETURN(0); } @@ -248,7 +255,7 @@ extern "C" { Z3_TRY; LOG_Z3_get_num_literals(c, lbls); RESET_ERROR_CODE(); - return reinterpret_cast(lbls)->size(); + return reinterpret_cast(lbls)->size(); Z3_CATCH_RETURN(0); } @@ -256,7 +263,7 @@ extern "C" { Z3_TRY; LOG_Z3_get_label_symbol(c, lbls, idx); RESET_ERROR_CODE(); - return of_symbol((*reinterpret_cast(lbls))[idx].get_label()); + return of_symbol((*reinterpret_cast(lbls))[idx].get_label()); Z3_CATCH_RETURN(0); } @@ -274,7 +281,7 @@ extern "C" { Z3_TRY; LOG_Z3_disable_literal(c, lbls, idx); RESET_ERROR_CODE(); - (*reinterpret_cast(lbls))[idx].disable(); + (*reinterpret_cast(lbls))[idx].disable(); Z3_CATCH; } @@ -348,4 +355,4 @@ void Z3_display_statistics(Z3_context c, std::ostream& s) { void Z3_display_istatistics(Z3_context c, std::ostream& s) { mk_c(c)->get_smt_kernel().display_istatistics(s); } - + diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 9c04ee98a..9cfad3415 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1359,9 +1359,13 @@ namespace z3 { Z3_solver_inc_ref(ctx(), s); } public: + struct simple {}; + struct translate {}; solver(context & c):object(c) { init(Z3_mk_solver(c)); } + solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); } solver(context & c, Z3_solver s):object(c) { init(s); } solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); } + solver(context & c, solver const& src, translate): object(c) { init(Z3_solver_translate(src.ctx(), src, c)); } solver(solver const & s):object(s) { init(s.m_solver); } ~solver() { Z3_solver_dec_ref(ctx(), m_solver); } operator Z3_solver() const { return m_solver; } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index b179d44a5..d56ba4af1 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2122,6 +2122,21 @@ namespace Microsoft.Z3 CheckContextMatch(array); return Expr.Create(this, Native.Z3_mk_array_default(nCtx, array.NativeObject)); } + + /// + /// Create Extentionality index. Two arrays are equal if and only if they are equal on the index returned by MkArrayExt. + /// + public Expr MkArrayExt(ArrayExpr arg1, ArrayExpr arg2) + { + Contract.Requires(arg1 != null); + Contract.Requires(arg2 != null); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(arg1); + CheckContextMatch(arg2); + return Expr.Create(this, Native.Z3_mk_array_ext(nCtx, arg1.NativeObject, arg2.NativeObject)); + } + #endregion #region Sets @@ -2268,6 +2283,7 @@ namespace Microsoft.Z3 CheckContextMatch(arg2); return (BoolExpr) Expr.Create(this, Native.Z3_mk_set_subset(nCtx, arg1.NativeObject, arg2.NativeObject)); } + #endregion #region Pseudo-Boolean constraints @@ -2597,8 +2613,13 @@ namespace Microsoft.Z3 /// is an array of patterns, is an array /// with the sorts of the bound variables, is an array with the /// 'names' of the bound variables, and is the body of the - /// quantifier. Quantifiers are associated with weights indicating - /// the importance of using the quantifier during instantiation. + /// quantifier. Quantifiers are associated with weights indicating the importance of + /// using the quantifier during instantiation. + /// Note that the bound variables are de-Bruijn indices created using . + /// Z3 applies the convention that the last element in and + /// refers to the variable with index 0, the second to last element + /// of and refers to the variable + /// with index 1, etc. /// /// the sorts of the bound variables. /// names of the bound variables @@ -2628,6 +2649,11 @@ namespace Microsoft.Z3 /// /// Create a universal Quantifier. /// + /// + /// Creates a universal quantifier using a list of constants that will + /// form the set of bound variables. + /// + /// public Quantifier MkForall(Expr[] boundConstants, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { Contract.Requires(body != null); @@ -2643,7 +2669,10 @@ namespace Microsoft.Z3 /// /// Create an existential Quantifier. /// - /// + /// + /// Creates an existential quantifier using de-Brujin indexed variables. + /// (). + /// public Quantifier MkExists(Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { Contract.Requires(sorts != null); @@ -2662,6 +2691,11 @@ namespace Microsoft.Z3 /// /// Create an existential Quantifier. /// + /// + /// Creates an existential quantifier using a list of constants that will + /// form the set of bound variables. + /// + /// public Quantifier MkExists(Expr[] boundConstants, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { Contract.Requires(body != null); @@ -2677,6 +2711,7 @@ namespace Microsoft.Z3 /// /// Create a Quantifier. /// + /// public Quantifier MkQuantifier(bool universal, Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { Contract.Requires(body != null); @@ -2700,6 +2735,7 @@ namespace Microsoft.Z3 /// /// Create a Quantifier. /// + /// public Quantifier MkQuantifier(bool universal, Expr[] boundConstants, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) { Contract.Requires(body != null); diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 80ca7a0cd..c9e76e68e 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -290,6 +290,17 @@ namespace Microsoft.Z3 } } + /// + /// Create a clone of the current solver with respect to ctx. + /// + public Solver Translate(Context ctx) + { + Contract.Requires(ctx != null); + Contract.Ensures(Contract.Result() != null); + return new Solver(ctx, Native.Z3_solver_translate(Context.nCtx, NativeObject, ctx.nCtx)); + } + + /// /// Solver statistics. /// diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 4497e6970..4d8484ced 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -433,8 +433,8 @@ public class Context extends IDisposable /** * Creates a fresh function declaration with a name prefixed with * {@code prefix}. - * @see mkFuncDecl(String,Sort,Sort) - * @see mkFuncDecl(String,Sort[],Sort) + * @see #mkFuncDecl(String,Sort,Sort) + * @see #mkFuncDecl(String,Sort[],Sort) **/ public FuncDecl mkFreshFuncDecl(String prefix, Sort[] domain, Sort range) @@ -1717,6 +1717,17 @@ public class Context extends IDisposable Native.mkArrayDefault(nCtx(), array.getNativeObject())); } + /** + * Create Extentionality index. Two arrays are equal if and only if they are equal on the index returned by MkArrayExt. + **/ + public Expr mkArrayExt(ArrayExpr arg1, ArrayExpr arg2) + { + checkContextMatch(arg1); + checkContextMatch(arg2); + return Expr.create(this, Native.mkArrayExt(nCtx(), arg1.getNativeObject(), arg2.getNativeObject())); + } + + /** * Create a set type. **/ @@ -2014,6 +2025,7 @@ public class Context extends IDisposable /** * Create a universal Quantifier. + * * @param sorts the sorts of the bound variables. * @param names names of the bound variables * @param body the body of the quantifier. @@ -2023,17 +2035,22 @@ public class Context extends IDisposable * @param quantifierID optional symbol to track quantifier. * @param skolemID optional symbol to track skolem constants. * - * Remarks: Creates a forall formula, where - * {@code weight"/> is the weight, >> c1 = Context() + >>> c2 = Context() + >>> s1 = Solver(ctx=c1) + >>> s2 = s1.translate(c2) + """ + if __debug__: + _z3_assert(isinstance(target, Context), "argument must be a Z3 context") + solver = Z3_solver_translate(self.ctx.ref(), self.solver, target.ref()) + return Solver(solver, target) + def sexpr(self): """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index e8a6b992f..2a242865e 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -31,7 +31,7 @@ _z3_op_to_str = { Z3_OP_BASHR : '>>', Z3_OP_BSHL : '<<', Z3_OP_BLSHR : 'LShR', Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int', Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store', - Z3_OP_CONST_ARRAY : 'K', + Z3_OP_CONST_ARRAY : 'K', Z3_OP_ARRAY_EXT : 'Ext', Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe' } @@ -1157,7 +1157,13 @@ def set_pp_option(k, v): def obj_to_string(a): out = io.StringIO() _PP(out, _Formatter(a)) - return out.getvalue() + r = out.getvalue() + if sys.version < '3': + return r + else: + enc = sys.stdout.encoding + if enc != None: return r.decode(enc) + return r _html_out = None diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d0bf20188..927aad930 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -322,6 +322,9 @@ typedef enum - Z3_OP_AS_ARRAY An array value that behaves as the function graph of the function passed as parameter. + - Z3_OP_ARRAY_EXT Array extensionality function. It takes two arrays as arguments and produces an index, such that the arrays + are different if they are different on the index. + - Z3_OP_BNUM Bit-vector numeral. - Z3_OP_BIT1 One bit bit-vector. @@ -1033,6 +1036,7 @@ typedef enum { Z3_OP_SET_COMPLEMENT, Z3_OP_SET_SUBSET, Z3_OP_AS_ARRAY, + Z3_OP_ARRAY_EXT, // Bit-vectors Z3_OP_BNUM = 0x400, @@ -3260,6 +3264,17 @@ END_MLAPI_EXCLUDE Z3_ast Z3_API Z3_mk_set_subset(Z3_context c, Z3_ast arg1, Z3_ast arg2); /*@}*/ + /** + \brief Create array extensionality index given two arrays with the same sort. + The meaning is given by the axiom: + (=> (= (select A (array-ext A B)) (select B (array-ext A B))) (= A B)) + + def_API('Z3_mk_array_ext', AST, (_in(CONTEXT), _in(AST), _in(AST))) + */ + + Z3_ast Z3_API Z3_mk_array_ext(Z3_context c, Z3_ast arg1, Z3_ast arg2); + /*@}*/ + /** @name Numerals */ @@ -7062,6 +7077,14 @@ END_MLAPI_EXCLUDE */ Z3_solver Z3_API Z3_mk_solver_from_tactic(Z3_context c, Z3_tactic t); + /** + \brief Copy a solver \c s from the context \c source to a the context \c target. + + def_API('Z3_solver_translate', SOLVER, (_in(CONTEXT), _in(SOLVER), _in(CONTEXT))) + */ + Z3_solver Z3_API Z3_solver_translate(Z3_context source, Z3_solver s, Z3_context target); + + /** \brief Return a string describing all solver available parameters. diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 47842ae90..49b1b18c5 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -293,7 +293,7 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { func_decl_info(m_family_id, OP_STORE)); } -func_decl * array_decl_plugin::mk_array_ext_skolem(unsigned arity, sort * const * domain, unsigned i) { +func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domain, unsigned i) { if (arity != 2 || domain[0] != domain[1]) { UNREACHABLE(); return 0; @@ -306,7 +306,7 @@ func_decl * array_decl_plugin::mk_array_ext_skolem(unsigned arity, sort * const } sort * r = to_sort(s->get_parameter(i).get_ast()); parameter param(s); - return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT_SKOLEM, 1, ¶m)); + return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT, 1, ¶m)); } @@ -463,12 +463,15 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters func_decl * f = to_func_decl(parameters[0].get_ast()); return mk_map(f, arity, domain); } - case OP_ARRAY_EXT_SKOLEM: + case OP_ARRAY_EXT: + if (num_parameters == 0) { + return mk_array_ext(arity, domain, 0); + } if (num_parameters != 1 || !parameters[0].is_int()) { UNREACHABLE(); return 0; } - return mk_array_ext_skolem(arity, domain, parameters[0].get_int()); + return mk_array_ext(arity, domain, parameters[0].get_int()); case OP_ARRAY_DEFAULT: return mk_default(arity, domain); case OP_SET_UNION: @@ -519,6 +522,7 @@ void array_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("complement",OP_SET_COMPLEMENT)); op_names.push_back(builtin_name("subset",OP_SET_SUBSET)); op_names.push_back(builtin_name("as-array", OP_AS_ARRAY)); + op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT)); } } diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 98fd563f0..60adc3ae6 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -22,7 +22,7 @@ Revision History: #include"ast.h" -inline sort* get_array_range(sort const * s) { +inline sort* get_array_range(sort const * s) { return to_sort(s->get_parameter(s->get_num_parameters() - 1).get_ast()); } @@ -42,7 +42,7 @@ enum array_op_kind { OP_STORE, OP_SELECT, OP_CONST_ARRAY, - OP_ARRAY_EXT_SKOLEM, + OP_ARRAY_EXT, OP_ARRAY_DEFAULT, OP_ARRAY_MAP, OP_SET_UNION, @@ -80,7 +80,7 @@ class array_decl_plugin : public decl_plugin { func_decl * mk_store(unsigned arity, sort * const * domain); - func_decl * mk_array_ext_skolem(unsigned arity, sort * const * domain, unsigned i); + func_decl * mk_array_ext(unsigned arity, sort * const * domain, unsigned i); func_decl * mk_set_union(unsigned arity, sort * const * domain); @@ -104,20 +104,20 @@ class array_decl_plugin : public decl_plugin { } // - // Contract for sort: - // parameters[0] - 1st dimension + // Contract for sort: + // parameters[0] - 1st dimension // ... // parameters[n-1] - nth dimension // parameters[n] - range // virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - + // // Contract for func_decl: // parameters[0] - array sort // Contract for others: // no parameters - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); virtual void get_op_names(svector & op_names, symbol const & logic); @@ -184,6 +184,11 @@ public: sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); } sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range); + + app * mk_as_array(sort * s, func_decl * f) { + parameter param(f); + return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, 0, s); + } }; diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index e49edb7ab..4b1a80908 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -184,6 +184,7 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) { } ast * ast_translation::process(ast const * _n) { + if (!_n) return 0; SASSERT(m_result_stack.empty()); SASSERT(m_frame_stack.empty()); SASSERT(m_extra_children_stack.empty()); diff --git a/src/ast/ast_translation.h b/src/ast/ast_translation.h index b1b12c1c6..ec187110b 100644 --- a/src/ast/ast_translation.h +++ b/src/ast/ast_translation.h @@ -58,9 +58,9 @@ public: template T * operator()(T const * n) { - SASSERT(from().contains(const_cast(n))); + SASSERT(!n || from().contains(const_cast(n))); ast * r = process(n); - SASSERT(to().contains(const_cast(r))); + SASSERT((!n && !r) || to().contains(const_cast(r))); return static_cast(r); } diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 94e7b642c..eba4d526b 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -166,6 +166,11 @@ expr * mk_and(ast_manager & m, unsigned num_args, expr * const * args) { return m.mk_and(num_args, args); } +app* mk_and(ast_manager & m, unsigned num_args, app * const * args) { + return to_app(mk_and(m, num_args, (expr* const*) args)); +} + + expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) { if (num_args == 0) return m.mk_false(); @@ -175,6 +180,10 @@ expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) { return m.mk_or(num_args, args); } +app* mk_or(ast_manager & m, unsigned num_args, app * const * args) { + return to_app(mk_or(m, num_args, (expr* const*) args)); +} + expr * mk_not(ast_manager & m, expr * arg) { expr * atom; if (m.is_not(arg, atom)) diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index 87a3a90d9..311001a19 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -107,6 +107,9 @@ expr * get_clause_literal(ast_manager & m, expr * cls, unsigned idx); Return true if num_args == 0 */ expr * mk_and(ast_manager & m, unsigned num_args, expr * const * args); +app * mk_and(ast_manager & m, unsigned num_args, app * const * args); +inline app_ref mk_and(app_ref_vector const& args) { return app_ref(mk_and(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } +inline expr_ref mk_and(expr_ref_vector const& args) { return expr_ref(mk_and(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } /** Return (or args[0] ... args[num_args-1]) if num_args >= 2 @@ -114,6 +117,10 @@ expr * mk_and(ast_manager & m, unsigned num_args, expr * const * args); Return false if num_args == 0 */ expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args); +app * mk_or(ast_manager & m, unsigned num_args, app * const * args); +inline app_ref mk_or(app_ref_vector const& args) { return app_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } +inline expr_ref mk_or(expr_ref_vector const& args) { return expr_ref(mk_or(args.get_manager(), args.size(), args.c_ptr()), args.get_manager()); } + /** Return a if arg = (not a) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 4ee6366f0..19b07035f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2648,9 +2648,8 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); - SASSERT(m_bv_util.is_bv(args[0])); - SASSERT(m_bv_util.is_bv(args[1])); SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_bv_util.is_bv(args[1])); expr_ref bv_rm(m), x(m); bv_rm = to_app(args[0])->get_arg(0); diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 5b0c38616..0b8a51fb4 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -84,7 +84,7 @@ br_status bool_rewriter::mk_nflat_and_core(unsigned num_args, expr * const * arg ptr_buffer buffer; expr_fast_mark1 neg_lits; expr_fast_mark2 pos_lits; - + for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; if (m().is_true(arg)) { @@ -120,9 +120,9 @@ br_status bool_rewriter::mk_nflat_and_core(unsigned num_args, expr * const * arg } buffer.push_back(arg); } - + unsigned sz = buffer.size(); - + switch(sz) { case 0: result = m().mk_true(); @@ -208,9 +208,9 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args } buffer.push_back(arg); } - + unsigned sz = buffer.size(); - + switch(sz) { case 0: result = m().mk_false(); @@ -222,7 +222,7 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args if (m_local_ctx && m_local_ctx_cost <= m_local_ctx_limit) { neg_lits.reset(); pos_lits.reset(); - if (local_ctx_simp(sz, buffer.c_ptr(), result)) + if (local_ctx_simp(sz, buffer.c_ptr(), result)) return BR_DONE; } if (s) { @@ -273,11 +273,11 @@ expr * bool_rewriter::mk_or_app(unsigned num_args, expr * const * args) { /** \brief Auxiliary method for local_ctx_simp. - + Replace args[i] by true if marked in neg_lits. Replace args[i] by false if marked in pos_lits. */ -bool bool_rewriter::simp_nested_not_or(unsigned num_args, expr * const * args, +bool bool_rewriter::simp_nested_not_or(unsigned num_args, expr * const * args, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result) { ptr_buffer new_args; bool simp = false; @@ -307,13 +307,13 @@ bool bool_rewriter::simp_nested_not_or(unsigned num_args, expr * const * args, } if (simp) { switch(new_args.size()) { - case 0: - result = m().mk_true(); + case 0: + result = m().mk_true(); return true; - case 1: - mk_not(new_args[0], result); + case 1: + mk_not(new_args[0], result); return true; - default: + default: result = m().mk_not(m().mk_or(new_args.size(), new_args.c_ptr())); return true; } @@ -358,7 +358,7 @@ void bool_rewriter::mk_nested_ite(expr * c, expr * t, expr * e, expr_ref & resul result = t; return; } - + if (m().is_false(c)) { result = e; return; @@ -368,7 +368,7 @@ void bool_rewriter::mk_nested_ite(expr * c, expr * t, expr * e, expr_ref & resul result = t; return; } - + if (m().is_bool(t)) { if (m().is_true(t)) { if (m().is_false(e)) { @@ -384,13 +384,13 @@ void bool_rewriter::mk_nested_ite(expr * c, expr * t, expr * e, expr_ref & resul return; } expr_ref tmp(m()); - mk_not(e, tmp); + mk_not(e, tmp); result = m().mk_not(m().mk_or(c, tmp)); return; } if (m().is_true(e)) { expr_ref tmp(m()); - mk_not(c, tmp); + mk_not(c, tmp); result = m().mk_or(tmp, t); return; } @@ -406,7 +406,7 @@ void bool_rewriter::mk_nested_ite(expr * c, expr * t, expr * e, expr_ref & resul result = m().mk_or(c, e); return; } - if (m().is_complement_core(t, e)) { // t = not(e) + if (m().is_complement_core(t, e)) { // t = not(e) mk_eq(c, t, result); return; } @@ -443,8 +443,8 @@ bool bool_rewriter::simp_nested_eq_ite(expr * t, expr_fast_mark1 & neg_lits, exp expr * new_e = simp_arg(to_app(t)->get_arg(2), neg_lits, pos_lits, modified); if (!modified) return false; - // It is not safe to invoke mk_ite here, since it can recursively call - // local_ctx_simp by + // It is not safe to invoke mk_ite here, since it can recursively call + // local_ctx_simp by // - transforming the ITE into an OR // - and invoked mk_or, that will invoke local_ctx_simp // mk_ite(new_c, new_t, new_e, result); @@ -522,7 +522,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ PUSH_NEW_ARG(arg); \ } \ } - + m_local_ctx_cost += 2*num_args; #if 0 static unsigned counter = 0; @@ -567,9 +567,9 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ /** \brief Apply simplification if ite is an if-then-else tree where every leaf is a value. - - This is an efficient way to - + + This is an efficient way to + */ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) { SASSERT(m().is_ite(ite)); @@ -585,7 +585,7 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) tout << t << " " << e << " " << val << "\n";); result = m().mk_false(); return BR_DONE; - } + } if (t == val && e == val) { result = m().mk_true(); @@ -598,7 +598,7 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) } SASSERT(e == val); - + mk_not(ite->get_arg(0), result); return BR_DONE; } @@ -642,14 +642,14 @@ static bool is_ite_value_tree_neq_value(ast_manager & m, app * ite, app * val) { return true; } -#endif +#endif br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (lhs == rhs) { result = m().mk_true(); return BR_DONE; } - + if (m().are_distinct(lhs, rhs)) { result = m().mk_false(); return BR_DONE; @@ -662,7 +662,7 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { // return BR_DONE; // } r = try_ite_value(to_app(lhs), to_app(rhs), result); - CTRACE("try_ite_value", r != BR_FAILED, + CTRACE("try_ite_value", r != BR_FAILED, tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";); } else if (m().is_ite(rhs) && m().is_value(lhs)) { @@ -671,7 +671,7 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { // return BR_DONE; // } r = try_ite_value(to_app(rhs), to_app(lhs), result); - CTRACE("try_ite_value", r != BR_FAILED, + CTRACE("try_ite_value", r != BR_FAILED, tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";); } if (r != BR_FAILED) @@ -708,6 +708,19 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { result = m().mk_eq(lhs, rhs); return BR_DONE; } + + expr *la, *lb, *ra, *rb; + // fold (iff (iff a b) (iff (not a) b)) to false + if (m().is_iff(lhs, la, lb) && m().is_iff(rhs, ra, rb)) { + expr *n; + if ((la == ra && ((m().is_not(rb, n) && n == lb) || + (m().is_not(lb, n) && n == rb))) || + (lb == rb && ((m().is_not(ra, n) && n == la) || + (m().is_not(la, n) && n == ra)))) { + result = m().mk_false(); + return BR_DONE; + } + } } return BR_FAILED; } @@ -756,13 +769,13 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args result = m().mk_and(new_diseqs.size(), new_diseqs.c_ptr()); return BR_REWRITE3; } - + return BR_FAILED; } br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result) { bool s = false; - + // (ite (not c) a b) ==> (ite c b a) if (m().is_not(c)) { c = to_app(c)->get_arg(0); @@ -788,7 +801,7 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re result = t; return BR_DONE; } - + if (m().is_false(c)) { result = e; return BR_DONE; @@ -814,18 +827,18 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re return BR_DONE; } expr_ref tmp(m()); - mk_not(c, tmp); + mk_not(c, tmp); mk_and(tmp, e, result); return BR_DONE; } if (m().is_true(e)) { expr_ref tmp(m()); - mk_not(c, tmp); + mk_not(c, tmp); mk_or(tmp, t, result); return BR_DONE; } if (m().is_false(e)) { - mk_and(c, t, result); + mk_and(c, t, result); return BR_DONE; } if (c == e) { @@ -833,10 +846,10 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re return BR_DONE; } if (c == t) { - mk_or(c, e, result); + mk_or(c, e, result); return BR_DONE; } - if (m().is_complement_core(t, e)) { // t = not(e) + if (m().is_complement_core(t, e)) { // t = not(e) mk_eq(c, t, result); return BR_DONE; } @@ -863,10 +876,10 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re result = m().mk_ite(new_c, to_app(t)->get_arg(1), e); return BR_REWRITE1; } - + if (m().is_ite(e)) { // (ite c1 (ite c2 t1 t2) (ite c3 t1 t2)) ==> (ite (or (and c1 c2) (and (not c1) c3)) t1 t2) - if (to_app(t)->get_arg(1) == to_app(e)->get_arg(1) && + if (to_app(t)->get_arg(1) == to_app(e)->get_arg(1) && to_app(t)->get_arg(2) == to_app(e)->get_arg(2)) { expr_ref and1(m()); expr_ref and2(m()); @@ -879,9 +892,9 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re result = m().mk_ite(new_c, to_app(t)->get_arg(1), to_app(t)->get_arg(2)); return BR_REWRITE1; } - + // (ite c1 (ite c2 t1 t2) (ite c3 t2 t1)) ==> (ite (or (and c1 c2) (and (not c1) (not c3))) t1 t2) - if (to_app(t)->get_arg(1) == to_app(e)->get_arg(2) && + if (to_app(t)->get_arg(1) == to_app(e)->get_arg(2) && to_app(t)->get_arg(2) == to_app(e)->get_arg(1)) { expr_ref and1(m()); expr_ref and2(m()); @@ -922,10 +935,10 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re result = m().mk_ite(c, t, e); return BR_DONE; } - + return BR_FAILED; } - + br_status bool_rewriter::mk_not_core(expr * t, expr_ref & result) { if (m().is_not(t)) { result = to_app(t)->get_arg(0); diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index 1d01ef85c..37b335a9d 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -27,7 +27,7 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp SASSERT(is_well_sorted(result.m(), n)); m_reducer.reset(); if (m_std_order) - m_reducer.set_inv_bindings(num_args, args); + m_reducer.set_inv_bindings(num_args, args); else m_reducer.set_bindings(num_args, args); m_reducer(n, result); @@ -66,7 +66,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { return; } - ptr_buffer used_decl_sorts; + ptr_buffer used_decl_sorts; buffer used_decl_names; for (unsigned i = 0; i < num_decls; ++i) { if (m_used.contains(num_decls - i - 1)) { @@ -74,7 +74,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { used_decl_names.push_back(q->get_decl_name(i)); } } - + unsigned num_removed = 0; expr_ref_buffer var_mapping(m); int next_idx = 0; @@ -100,18 +100,18 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { else var_mapping.push_back(0); } - - - // Remark: + + + // Remark: // (VAR 0) should be in the last position of var_mapping. // ... // (VAR (var_mapping.size() - 1)) should be in the first position. std::reverse(var_mapping.c_ptr(), var_mapping.c_ptr() + var_mapping.size()); expr_ref new_expr(m); - + m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr); - + if (num_removed == num_decls) { result = new_expr; return; @@ -120,7 +120,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { expr_ref tmp(m); expr_ref_buffer new_patterns(m); expr_ref_buffer new_no_patterns(m); - + for (unsigned i = 0; i < num_patterns; i++) { m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp); new_patterns.push_back(tmp); @@ -129,7 +129,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp); new_no_patterns.push_back(tmp); } - + result = m.mk_quantifier(q->is_forall(), used_decl_sorts.size(), used_decl_sorts.c_ptr(), @@ -143,7 +143,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { num_no_patterns, new_no_patterns.c_ptr()); to_quantifier(result)->set_no_unused_vars(); - SASSERT(is_well_sorted(m, result)); + SASSERT(is_well_sorted(m, result)); } void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) { diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index b018d62c5..6e443d476 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1401,9 +1401,10 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions unsigned rlimit = m_params.m_rlimit; scoped_watch sw(*this); lbool r; + bool was_pareto = false, was_opt = false; if (m_opt && !m_opt->empty()) { - bool was_pareto = false; + was_opt = true; m_check_sat_result = get_opt(); cancel_eh eh(*get_opt()); scoped_ctrl_c ctrlc(eh); @@ -1436,9 +1437,6 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions r = l_true; } get_opt()->set_status(r); - if (r != l_false && !was_pareto) { - get_opt()->display_assignment(regular_stream()); - } } else if (m_solver) { m_check_sat_result = m_solver.get(); // solver itself stores the result. @@ -1465,6 +1463,10 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions } display_sat_result(r); validate_check_sat_result(r); + if (was_opt && r != l_false && !was_pareto) { + get_opt()->display_assignment(regular_stream()); + } + if (r == l_true) { validate_model(); if (m_params.m_dump_models) { diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index 30b5a7c4b..091207a93 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -48,7 +48,26 @@ void context_params::set_bool(bool & opt, char const * param, char const * value } else { std::stringstream strm; - strm << "invalid value '" << value << "' for Boolean parameter '" << param; + strm << "invalid value '" << value << "' for Boolean parameter '" << param << "'"; + throw default_exception(strm.str()); + } +} + +void context_params::set_uint(unsigned & opt, char const * param, char const * value) { + bool is_uint = true; + size_t sz = strlen(value); + for (unsigned i = 0; i < sz; i++) { + if (!(value[i] >= '0' && value[i] <= '9')) + is_uint = false; + } + + if (is_uint) { + long val = strtol(value, 0, 10); + opt = static_cast(val); + } + else { + std::stringstream strm; + strm << "invalid value '" << value << "' for unsigned int parameter '" << param << "'"; throw default_exception(strm.str()); } } @@ -63,12 +82,10 @@ void context_params::set(char const * param, char const * value) { p[i] = '_'; } if (p == "timeout") { - long val = strtol(value, 0, 10); - m_timeout = static_cast(val); + set_uint(m_timeout, param, value); } else if (p == "rlimit") { - long val = strtol(value, 0, 10); - m_rlimit = static_cast(val); + set_uint(m_rlimit, param, value); } else if (p == "type_check" || p == "well_sorted_check") { set_bool(m_well_sorted_check, param, value); @@ -110,7 +127,7 @@ void context_params::set(char const * param, char const * value) { strm << "unknown parameter '" << p << "'\n"; strm << "Legal parameters are:\n"; d.display(strm, 2, false, false); - throw default_exception(strm.str()); + throw default_exception(strm.str()); } } @@ -174,8 +191,8 @@ void context_params::get_solver_params(ast_manager const & m, params_ref & p, bo } ast_manager * context_params::mk_ast_manager() { - ast_manager * r = alloc(ast_manager, - m_proof ? PGM_FINE : PGM_DISABLED, + ast_manager * r = alloc(ast_manager, + m_proof ? PGM_FINE : PGM_DISABLED, m_trace ? m_trace_file_name.c_str() : 0); if (m_smtlib2_compliant) r->enable_int_real_coercions(false); diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h index 2c75b5743..40b6c9482 100644 --- a/src/cmd_context/context_params.h +++ b/src/cmd_context/context_params.h @@ -25,7 +25,8 @@ class ast_manager; class context_params { void set_bool(bool & opt, char const * param, char const * value); - + void set_uint(unsigned & opt, char const * param, char const * value); + public: bool m_auto_config; bool m_proof; @@ -50,7 +51,7 @@ public: /* REG_PARAMS('context_params::collect_param_descrs') */ - + /** \brief Goodies for extracting parameters for creating a solver object. */ @@ -64,7 +65,7 @@ public: Example: auto_config */ params_ref merge_default_params(params_ref const & p); - + /** \brief Create an AST manager using this configuration. */ diff --git a/src/muz/dataflow/dataflow.h b/src/muz/dataflow/dataflow.h index 9e100121a..1e52c5f93 100644 --- a/src/muz/dataflow/dataflow.h +++ b/src/muz/dataflow/dataflow.h @@ -87,6 +87,7 @@ namespace datalog { for (func_decl_set::iterator I = output_preds.begin(), E = output_preds.end(); I != E; ++I) { func_decl* sym = *I; + TRACE("dl", tout << sym->get_name() << "\n";); const rule_vector& output_rules = m_rules.get_predicate_rules(sym); for (unsigned i = 0; i < output_rules.size(); ++i) { m_facts.insert_if_not_there2(sym, Fact())->get_data().m_value.init_down(m_context, output_rules[i]); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index d349da4ec..5140c9eff 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -50,6 +50,7 @@ Notes: #include "blast_term_ite_tactic.h" #include "model_implicant.h" #include "expr_safe_replace.h" +#include "ast_util.h" namespace pdr { @@ -448,6 +449,7 @@ namespace pdr { else if (is_sat == l_false) { uses_level = m_solver.assumes_level(); } + m_solver.set_model(0); return is_sat; } @@ -481,6 +483,7 @@ namespace pdr { prop_solver::scoped_level _sl(m_solver, level); m_solver.set_core(&core); m_solver.set_subset_based_core(true); + m_solver.set_model(0); lbool res = m_solver.check_assumptions_and_formula(lits, fml); if (res == l_false) { lits.reset(); @@ -738,6 +741,7 @@ namespace pdr { // model_node void model_node::set_closed() { + TRACE("pdr", tout << state() << "\n";); pt().close(state()); m_closed = true; } @@ -774,6 +778,13 @@ namespace pdr { } // only initial states are not set by the PDR search. SASSERT(m_model.get()); + if (!m_model.get()) { + std::stringstream msg; + msg << "no model for node " << state(); + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); + throw default_exception(msg.str()); + } + datalog::rule const& rl1 = pt().find_rule(*m_model); if (is_ini(rl1)) { set_rule(&rl1); @@ -792,15 +803,23 @@ namespace pdr { } } SASSERT(!tags.empty()); - ini_tags = m.mk_or(tags.size(), tags.c_ptr()); + ini_tags = ::mk_or(tags); ini_state = m.mk_and(ini_tags, pt().initial_state(), state()); model_ref mdl; pt().get_solver().set_model(&mdl); - TRACE("pdr", tout << mk_pp(ini_state, m) << "\n";); - VERIFY(l_true == pt().get_solver().check_conjunction_as_assumptions(ini_state)); + TRACE("pdr", tout << ini_state << "\n";); + if (l_true != pt().get_solver().check_conjunction_as_assumptions(ini_state)) { + std::stringstream msg; + msg << "Unsatisfiable initial state: " << ini_state << "\n"; + display(msg, 2); + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); + throw default_exception(msg.str()); + } + SASSERT(mdl.get()); datalog::rule const& rl2 = pt().find_rule(*mdl); SASSERT(is_ini(rl2)); set_rule(&rl2); + pt().get_solver().set_model(0); return const_cast(m_rule); } @@ -829,7 +848,7 @@ namespace pdr { } r0 = get_rule(); app_ref_vector& inst = pt().get_inst(r0); - TRACE("pdr", tout << mk_pp(state(), m) << " instance: " << inst.size() << "\n";); + TRACE("pdr", tout << state() << " instance: " << inst.size() << "\n";); for (unsigned i = 0; i < inst.size(); ++i) { expr* v; if (model.find(inst[i].get(), v)) { @@ -851,7 +870,7 @@ namespace pdr { for (unsigned i = 0; i < indent; ++i) out << " "; out << m_level << " " << m_pt.head()->get_name() << " " << (m_closed?"closed":"open") << "\n"; for (unsigned i = 0; i < indent; ++i) out << " "; - out << " " << mk_pp(m_state, m_state.get_manager(), indent) << "\n"; + out << " " << mk_pp(m_state, m_state.get_manager(), indent) << " " << m_state->get_id() << "\n"; for (unsigned i = 0; i < children().size(); ++i) { children()[i]->display(out, indent + 1); } @@ -924,17 +943,6 @@ namespace pdr { } } - bool model_search::is_repeated(model_node& n) const { - model_node* p = n.parent(); - while (p) { - if (p->state() == n.state()) { - TRACE("pdr", tout << "repeated\n";); - return true; - } - p = p->parent(); - } - return false; - } void model_search::add_leaf(model_node& n) { SASSERT(n.children().empty()); @@ -1011,13 +1019,18 @@ namespace pdr { nodes.erase(&n); bool is_goal = n.is_goal(); remove_goal(n); - if (!nodes.empty() && is_goal && backtrack) { + // TBD: siblings would also fail if n is not a goal. + if (!nodes.empty() && backtrack && nodes[0]->children().empty() && nodes[0]->is_closed()) { TRACE("pdr_verbose", for (unsigned i = 0; i < nodes.size(); ++i) n.display(tout << &n << "\n", 2);); model_node* n1 = nodes[0]; - n1->set_open(); - SASSERT(n1->children().empty()); + n1->set_open(); enqueue_leaf(n1); } + + if (!nodes.empty() && n.get_model_ptr() && backtrack) { + model_ref mr(n.get_model_ptr()); + nodes[0]->set_model(mr); + } if (nodes.empty()) { cache(n).remove(n.state()); } @@ -1149,17 +1162,21 @@ namespace pdr { ast_manager& m = n->pt().get_manager(); if (!n->get_model_ptr()) { if (models.find(n->state(), md)) { - TRACE("pdr", tout << mk_pp(n->state(), m) << "\n";); + TRACE("pdr", tout << n->state() << "\n";); model_ref mr(md); n->set_model(mr); datalog::rule const* rule = rules.find(n->state()); n->set_rule(rule); } else { + TRACE("pdr", tout << "no model for " << n->state() << "\n";); IF_VERBOSE(1, n->display(verbose_stream() << "no model:\n", 0); - verbose_stream() << mk_pp(n->state(), m) << "\n";); + verbose_stream() << n->state() << "\n";); } } + else { + TRACE("pdr", tout << n->state() << "\n";); + } todo.pop_back(); todo.append(n->children().size(), n->children().c_ptr()); } @@ -1692,7 +1709,15 @@ namespace pdr { void context::validate_search() { expr_ref tr = m_search.get_trace(*this); - // TBD: tr << "\n"; + smt::kernel solver(m, get_fparams()); + solver.assert_expr(tr); + lbool res = solver.check(); + if (res != l_true) { + std::stringstream msg; + msg << "rule validation failed when checking: " << tr; + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); + throw default_exception(msg.str()); + } } void context::validate_model() { @@ -1928,11 +1953,11 @@ namespace pdr { proof_ref proof(m); SASSERT(m_last_result == l_true); proof = m_search.get_proof_trace(*this); - TRACE("pdr", tout << "PDR trace: " << mk_pp(proof, m) << "\n";); + TRACE("pdr", tout << "PDR trace: " << proof << "\n";); apply(m, m_pc.get(), proof); - TRACE("pdr", tout << "PDR trace: " << mk_pp(proof, m) << "\n";); + TRACE("pdr", tout << "PDR trace: " << proof << "\n";); // proof_utils::push_instantiations_up(proof); - // TRACE("pdr", tout << "PDR up: " << mk_pp(proof, m) << "\n";); + // TRACE("pdr", tout << "PDR up: " << proof << "\n";); return proof; } @@ -2027,11 +2052,11 @@ namespace pdr { switch (expand_state(n, cube, uses_level)) { case l_true: if (n.level() == 0) { - TRACE("pdr", tout << "reachable at level 0\n";); + TRACE("pdr", n.display(tout << "reachable at level 0\n", 0);); close_node(n); } else { - TRACE("pdr", tout << "node: " << &n << "\n";); + TRACE("pdr", n.display(tout, 0);); create_children(n); } break; diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index 7cba1e0c5..ad4b44d90 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -240,7 +240,7 @@ namespace pdr { void check_pre_closed(); void set_closed(); void set_open(); - void set_pre_closed() { m_closed = true; } + void set_pre_closed() { TRACE("pdr", tout << state() << "\n";); m_closed = true; } void reset() { m_children.reset(); } void set_rule(datalog::rule const* r) { m_rule = r; } @@ -268,7 +268,6 @@ namespace pdr { void enqueue_leaf(model_node* n); // add leaf to priority queue. void update_models(); void set_leaf(model_node& n); // Set node as leaf, remove children. - bool is_repeated(model_node& n) const; unsigned num_goals() const; public: diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 67b88724c..c452e2611 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -41,6 +41,9 @@ namespace datalog { bool new_tail = false; bool contained = true; for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) { + if (m_context.has_facts(r->get_decl(i))) { + return 0; + } if (r->is_neg_tail(i)) { if (!engine.get_fact(r->get_decl(i)).is_reachable()) { if (!new_tail) { diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 2d3a60ea8..cb598617c 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -154,7 +154,7 @@ namespace opt { m_soft_constraints(m), m_answer(m) {} lbool maxsmt::operator()() { - lbool is_sat; + lbool is_sat = l_undef; m_msolver = 0; symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); @@ -191,7 +191,7 @@ namespace opt { m_msolver->set_adjust_value(m_adjust_value); is_sat = (*m_msolver)(); if (is_sat != l_false) { - m_msolver->get_model(m_model); + m_msolver->get_model(m_model, m_labels); } } @@ -247,8 +247,9 @@ namespace opt { m_upper = r; } - void maxsmt::get_model(model_ref& mdl) { + void maxsmt::get_model(model_ref& mdl, svector& labels) { mdl = m_model.get(); + labels = m_labels; } void maxsmt::commit_assignment() { diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 8d290a640..7dbf763e2 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -46,7 +46,7 @@ namespace opt { virtual bool get_assignment(unsigned index) const = 0; virtual void set_cancel(bool f) = 0; virtual void collect_statistics(statistics& st) const = 0; - virtual void get_model(model_ref& mdl) = 0; + virtual void get_model(model_ref& mdl, svector& labels) = 0; virtual void updt_params(params_ref& p) = 0; void set_adjust_value(adjust_value& adj) { m_adjust_value = adj; } @@ -67,6 +67,7 @@ namespace opt { rational m_lower; rational m_upper; model_ref m_model; + svector m_labels; svector m_assignment; // truth assignment to soft constraints params_ref m_params; // config @@ -79,9 +80,9 @@ namespace opt { virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } virtual void set_cancel(bool f) { m_cancel = f; if (f) s().cancel(); else s().reset_cancel(); } virtual void collect_statistics(statistics& st) const { } - virtual void get_model(model_ref& mdl) { mdl = m_model.get(); } + virtual void get_model(model_ref& mdl, svector& labels) { mdl = m_model.get(); labels = m_labels;} virtual void commit_assignment(); - void set_model() { s().get_model(m_model); } + void set_model() { s().get_model(m_model); s().get_labels(m_labels); } virtual void updt_params(params_ref& p); solver& s(); void init(); @@ -122,6 +123,7 @@ namespace opt { rational m_upper; adjust_value m_adjust_value; model_ref m_model; + svector m_labels; params_ref m_params; public: maxsmt(maxsat_context& c); @@ -139,7 +141,7 @@ namespace opt { rational get_upper() const; void update_lower(rational const& r); void update_upper(rational const& r); - void get_model(model_ref& mdl); + void get_model(model_ref& mdl, svector& labels); bool get_assignment(unsigned index) const; void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 83d83fdb5..1b33c2cf1 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -167,6 +167,10 @@ namespace opt { m_hard_constraints.reset(); } + void context::get_labels(svector & r) { + r.append(m_labels); + } + void context::set_hard_constraints(ptr_vector& fmls) { if (m_scoped_state.set(fmls)) { clear_state(); @@ -228,6 +232,7 @@ namespace opt { TRACE("opt", tout << "initial search result: " << is_sat << "\n";); if (is_sat != l_false) { s.get_model(m_model); + s.get_labels(m_labels); } if (is_sat != l_true) { return is_sat; @@ -276,11 +281,6 @@ namespace opt { } } - void context::set_model(model_ref& mdl) { - m_model = mdl; - fix_model(mdl); - } - void context::get_model(model_ref& mdl) { mdl = m_model; fix_model(mdl); @@ -289,7 +289,7 @@ namespace opt { lbool context::execute_min_max(unsigned index, bool committed, bool scoped, bool is_max) { if (scoped) get_solver().push(); lbool result = m_optsmt.lex(index, is_max); - if (result == l_true) m_optsmt.get_model(m_model); + if (result == l_true) m_optsmt.get_model(m_model, m_labels); if (scoped) get_solver().pop(1); if (result == l_true && committed) m_optsmt.commit_assignment(index); return result; @@ -300,7 +300,7 @@ namespace opt { maxsmt& ms = *m_maxsmts.find(id); if (scoped) get_solver().push(); lbool result = ms(); - if (result != l_false && (ms.get_model(tmp), tmp.get())) ms.get_model(m_model); + if (result != l_false && (ms.get_model(tmp, m_labels), tmp.get())) ms.get_model(m_model, m_labels); if (scoped) get_solver().pop(1); if (result == l_true && committed) ms.commit_assignment(); return result; @@ -453,7 +453,7 @@ namespace opt { } void context::yield() { - m_pareto->get_model(m_model); + m_pareto->get_model(m_model, m_labels); update_bound(true); update_bound(false); } @@ -770,7 +770,7 @@ namespace opt { tout << "offset: " << offset << "\n"; ); std::ostringstream out; - out << mk_pp(orig_term, m); + out << mk_pp(orig_term, m) << ":" << index; id = symbol(out.str().c_str()); return true; } @@ -793,7 +793,7 @@ namespace opt { } neg = true; std::ostringstream out; - out << mk_pp(orig_term, m); + out << mk_pp(orig_term, m) << ":" << index; id = symbol(out.str().c_str()); return true; } @@ -812,7 +812,7 @@ namespace opt { } neg = is_max; std::ostringstream out; - out << mk_pp(orig_term, m); + out << mk_pp(orig_term, m) << ":" << index; id = symbol(out.str().c_str()); return true; } @@ -902,6 +902,21 @@ namespace opt { m_hard_constraints.push_back(fml); } } + // fix types of objectives: + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective & obj = m_objectives[i]; + expr* t = obj.m_term; + switch(obj.m_type) { + case O_MINIMIZE: + case O_MAXIMIZE: + if (!m_arith.is_int(t) && !m_arith.is_real(t)) { + obj.m_term = m_arith.mk_numeral(rational(0), true); + } + break; + default: + break; + } + } } void context::purify(app_ref& term) { @@ -1000,7 +1015,10 @@ namespace opt { switch(obj.m_type) { case O_MINIMIZE: { app_ref tmp(m); - tmp = m_arith.mk_uminus(obj.m_term); + tmp = obj.m_term; + if (m_arith.is_int(tmp) || m_arith.is_real(tmp)) { + tmp = m_arith.mk_uminus(obj.m_term); + } obj.m_index = m_optsmt.add(tmp); break; } @@ -1103,16 +1121,20 @@ namespace opt { } void context::display_assignment(std::ostream& out) { + out << "(objectives\n"; for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { objective const& obj = m_scoped_state.m_objectives[i]; + out << " ("; display_objective(out, obj); if (get_lower_as_num(i) != get_upper_as_num(i)) { - out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n"; + out << " (" << get_lower(i) << " " << get_upper(i) << ")"; } else { - out << " |-> " << get_lower(i) << "\n"; + out << " " << get_lower(i); } + out << ")\n"; } + out << ")\n"; } void context::display_objective(std::ostream& out, objective const& obj) const { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 735dc6905..dc180e8e6 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -162,6 +162,7 @@ namespace opt { bool m_pp_neat; symbol m_maxsat_engine; symbol m_logic; + svector m_labels; public: context(ast_manager& m); virtual ~context(); @@ -180,11 +181,10 @@ namespace opt { virtual lbool optimize(); virtual bool print_model() const; virtual void get_model(model_ref& _m); - virtual void set_model(model_ref& _m); virtual void fix_model(model_ref& _m); virtual void collect_statistics(statistics& stats) const; virtual proof* get_proof() { return 0; } - virtual void get_labels(svector & r) {} + virtual void get_labels(svector & r); virtual void get_unsat_core(ptr_vector & r) {} virtual std::string reason_unknown() const; diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index 5e1d4b269..dea744a72 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -38,6 +38,7 @@ namespace opt { return l_undef; } m_solver->get_model(m_model); + m_solver->get_labels(m_labels); IF_VERBOSE(1, model_ref mdl(m_model); cb.fix_model(mdl); @@ -96,6 +97,7 @@ namespace opt { } if (is_sat == l_true) { m_solver->get_model(m_model); + m_solver->get_labels(m_labels); mk_not_dominated_by(); } return is_sat; diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h index 88a3ce9c1..122f29c55 100644 --- a/src/opt/opt_pareto.h +++ b/src/opt/opt_pareto.h @@ -31,7 +31,6 @@ namespace opt { virtual expr_ref mk_gt(unsigned i, model_ref& model) = 0; virtual expr_ref mk_ge(unsigned i, model_ref& model) = 0; virtual expr_ref mk_le(unsigned i, model_ref& model) = 0; - virtual void set_model(model_ref& m) = 0; virtual void fix_model(model_ref& m) = 0; }; class pareto_base { @@ -42,6 +41,7 @@ namespace opt { ref m_solver; params_ref m_params; model_ref m_model; + svector m_labels; public: pareto_base( ast_manager & m, @@ -77,8 +77,9 @@ namespace opt { } virtual lbool operator()() = 0; - virtual void get_model(model_ref& mdl) { + virtual void get_model(model_ref& mdl, svector& labels) { mdl = m_model; + labels = m_labels; } protected: diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index bf7a39424..d7e3c8590 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -63,6 +63,11 @@ namespace opt { m_context.updt_params(_p); } + solver* opt_solver::translate(ast_manager& m, params_ref const& p) { + UNREACHABLE(); + return 0; + } + void opt_solver::collect_param_descrs(param_descrs & r) { m_context.collect_param_descrs(r); } @@ -277,6 +282,7 @@ namespace opt { } void opt_solver::get_labels(svector & r) { + r.reset(); buffer tmp; m_context.get_relevant_labels(0, tmp); r.append(tmp.size(), tmp.c_ptr()); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 9e74e9127..0e53e07c6 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -86,6 +86,7 @@ namespace opt { opt_solver(ast_manager & m, params_ref const & p, filter_model_converter& fm); virtual ~opt_solver(); + virtual solver* translate(ast_manager& m, params_ref const& p); virtual void updt_params(params_ref & p); virtual void collect_param_descrs(param_descrs & r); virtual void collect_statistics(statistics & st) const; diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 02effa337..c9ee61ebc 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -51,6 +51,7 @@ namespace opt { if (src[i] >= dst[i]) { dst[i] = src[i]; m_models.set(i, m_s->get_model(i)); + m_s->get_labels(m_labels); m_lower_fmls[i] = fmls[i].get(); if (dst[i].is_pos() && !dst[i].is_finite()) { // review: likely done already. m_lower_fmls[i] = m.mk_false(); @@ -156,7 +157,8 @@ namespace opt { if (is_sat == l_true) { disj.reset(); m_s->maximize_objectives(disj); - m_s->get_model(m_model); + m_s->get_model(m_model); + m_s->get_labels(m_labels); for (unsigned i = 0; i < ors.size(); ++i) { expr_ref tmp(m); m_model->eval(ors[i].get(), tmp); @@ -203,6 +205,7 @@ namespace opt { expr_ref optsmt::update_lower() { expr_ref_vector disj(m); m_s->get_model(m_model); + m_s->get_labels(m_labels); m_s->maximize_objectives(disj); set_max(m_lower, m_s->get_objective_values(), disj); TRACE("opt", @@ -331,6 +334,7 @@ namespace opt { m_s->maximize_objective(obj_index, block); m_s->get_model(m_model); + m_s->get_labels(m_labels); inf_eps obj = m_s->saved_objective_value(obj_index); if (obj > m_lower[obj_index]) { m_lower[obj_index] = obj; @@ -405,8 +409,9 @@ namespace opt { return m_upper[i]; } - void optsmt::get_model(model_ref& mdl) { + void optsmt::get_model(model_ref& mdl, svector & labels) { mdl = m_model.get(); + labels = m_labels; } // force lower_bound(i) <= objective_value(i) diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 10ea9f11c..f4efa25f9 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -38,6 +38,7 @@ namespace opt { svector m_vars; symbol m_optsmt_engine; model_ref m_model; + svector m_labels; sref_vector m_models; public: optsmt(ast_manager& m): @@ -60,7 +61,7 @@ namespace opt { inf_eps get_lower(unsigned index) const; inf_eps get_upper(unsigned index) const; bool objective_is_model_valid(unsigned index) const; - void get_model(model_ref& mdl); + void get_model(model_ref& mdl, svector& labels); model* get_model(unsigned index) const { return m_models[index]; } void update_lower(unsigned idx, inf_eps const& r); diff --git a/src/parsers/util/pattern_validation.cpp b/src/parsers/util/pattern_validation.cpp index fe3292312..3d59c2213 100644 --- a/src/parsers/util/pattern_validation.cpp +++ b/src/parsers/util/pattern_validation.cpp @@ -88,7 +88,7 @@ bool pattern_validator::process(uint_set & found_vars, unsigned num_bindings, un if (!f.m_result) return false; if (!f.m_found_a_var) { - warning_msg("pattern does contain any variable."); + warning_msg("pattern does not contain any variable."); return false; } return true; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index fd1f4cfd0..43b2c2e3f 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -32,6 +32,7 @@ Notes: #include "model_smt2_pp.h" #include "filter_model_converter.h" #include "bit_blaster_model_converter.h" +#include "ast_translation.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -93,7 +94,25 @@ public: } virtual ~inc_sat_solver() {} - + + virtual solver* translate(ast_manager& dst_m, params_ref const& p) { + ast_translation tr(m, dst_m); + if (m_num_scopes > 0) { + throw default_exception("Cannot translate sat solver at non-base level"); + } + inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p); + expr_ref fml(dst_m); + for (unsigned i = 0; i < m_fmls.size(); ++i) { + fml = tr(m_fmls[i].get()); + result->m_fmls.push_back(fml); + } + for (unsigned i = 0; i < m_asmsf.size(); ++i) { + fml = tr(m_asmsf[i].get()); + result->m_asmsf.push_back(fml); + } + return result; + } + virtual void set_progress_callback(progress_callback * callback) {} virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { @@ -231,7 +250,6 @@ public: return "no reason given"; } virtual void get_labels(svector & r) { - UNREACHABLE(); } virtual unsigned get_num_assertions() const { return m_fmls.size(); diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index d92eef5b8..d22ca88db 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -3646,6 +3646,9 @@ namespace smt { approx_set::iterator it1 = plbls1.begin(); approx_set::iterator end1 = plbls1.end(); for (; it1 != end1; ++it1) { + if (m_context.get_cancel_flag()) { + break; + } unsigned plbl1 = *it1; SASSERT(plbls1.may_contain(plbl1)); approx_set::iterator it2 = plbls2.begin(); @@ -3687,6 +3690,9 @@ namespace smt { approx_set::iterator it1 = plbls.begin(); approx_set::iterator end1 = plbls.end(); for (; it1 != end1; ++it1) { + if (m_context.get_cancel_flag()) { + break; + } unsigned plbl1 = *it1; SASSERT(plbls.may_contain(plbl1)); approx_set::iterator it2 = clbls.begin(); @@ -3706,6 +3712,9 @@ namespace smt { svector::iterator it1 = m_new_patterns.begin(); svector::iterator end1 = m_new_patterns.end(); for (; it1 != end1; ++it1) { + if (m_context.get_cancel_flag()) { + break; + } quantifier * qa = it1->first; app * mp = it1->second; SASSERT(m_ast_manager.is_pattern(mp)); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index e84f3654c..56d393d41 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -33,7 +33,7 @@ def_module_params(module_name='smt', ('qi.cost', STRING, '(+ weight generation)', 'expression specifying what is the cost of a given quantifier instantiation'), ('qi.max_multi_patterns', UINT, 0, 'specify the number of extra multi patterns'), ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), - ('bv.enable_int2bv', BOOL, False, 'enable support for int2bv and bv2int operators'), + ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), ('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'), diff --git a/src/smt/params/theory_bv_params.h b/src/smt/params/theory_bv_params.h index d7c9f903b..00565969e 100644 --- a/src/smt/params/theory_bv_params.h +++ b/src/smt/params/theory_bv_params.h @@ -39,7 +39,7 @@ struct theory_bv_params { m_bv_lazy_le(false), m_bv_cc(false), m_bv_blast_max_size(INT_MAX), - m_bv_enable_int2bv2int(false) { + m_bv_enable_int2bv2int(true) { updt_params(p); } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 6b3316809..39ccbdbb2 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -36,6 +36,7 @@ Revision History: #include"smt_model_finder.h" #include"model_pp.h" #include"ast_smt2_pp.h" +#include"ast_translation.h" namespace smt { @@ -98,38 +99,159 @@ namespace smt { m_model_generator->set_context(this); } + literal context::translate_literal( + literal lit, context& src_ctx, context& dst_ctx, + vector b2v, ast_translation& tr) { + ast_manager& dst_m = dst_ctx.get_manager(); + ast_manager& src_m = src_ctx.get_manager(); + expr_ref dst_f(dst_m); + + SASSERT(lit != false_literal && lit != true_literal); + bool_var v = b2v.get(lit.var(), null_bool_var); + if (v == null_bool_var) { + expr* e = src_ctx.m_bool_var2expr.get(lit.var(), 0); + SASSERT(e); + dst_f = tr(e); + v = dst_ctx.get_bool_var_of_id_option(dst_f->get_id()); + if (v != null_bool_var) { + } + else if (src_m.is_not(e) || src_m.is_and(e) || src_m.is_or(e) || + src_m.is_iff(e) || src_m.is_ite(e)) { + v = dst_ctx.mk_bool_var(dst_f); + } + else { + dst_ctx.internalize_formula(dst_f, false); + v = dst_ctx.get_bool_var(dst_f); + } + b2v.setx(lit.var(), v, null_bool_var); + } + return literal(v, lit.sign()); + } + + + void context::copy(context& src_ctx, context& dst_ctx) { + ast_manager& dst_m = dst_ctx.get_manager(); + ast_manager& src_m = src_ctx.get_manager(); + src_ctx.pop_to_base_lvl(); + + if (src_ctx.m_base_lvl > 0) { + throw default_exception("Cloning contexts within a user-scope is not allowed"); + } + SASSERT(src_ctx.m_base_lvl == 0); + + ast_translation tr(src_m, dst_m, false); + + dst_ctx.set_logic(src_ctx.m_setup.get_logic()); + dst_ctx.copy_plugins(src_ctx, dst_ctx); + + asserted_formulas& src_af = src_ctx.m_asserted_formulas; + asserted_formulas& dst_af = dst_ctx.m_asserted_formulas; + + // Copy asserted formulas. + for (unsigned i = 0; i < src_af.get_num_formulas(); ++i) { + expr_ref fml(dst_m); + proof_ref pr(dst_m); + proof* pr_src = src_af.get_formula_proof(i); + fml = tr(src_af.get_formula(i)); + if (pr_src) { + pr = tr(pr_src); + } + dst_af.assert_expr(fml, pr); + } + + if (!src_ctx.m_setup.already_configured()) { + return; + } + dst_ctx.setup_context(dst_ctx.m_fparams.m_auto_config); + dst_ctx.internalize_assertions(); + + vector b2v; + +#define TRANSLATE(_lit) translate_literal(_lit, src_ctx, dst_ctx, b2v, tr) + + for (unsigned i = 0; i < src_ctx.m_assigned_literals.size(); ++i) { + literal lit; + lit = TRANSLATE(src_ctx.m_assigned_literals[i]); + dst_ctx.mk_clause(1, &lit, 0, CLS_AUX, 0); + } +#if 0 + literal_vector lits; + expr_ref_vector cls(src_m); + for (unsigned i = 0; i < src_ctx.m_lemmas.size(); ++i) { + lits.reset(); + cls.reset(); + clause& src_cls = *src_ctx.m_lemmas[i]; + unsigned sz = src_cls.get_num_literals(); + for (unsigned j = 0; j < sz; ++j) { + literal lit = TRANSLATE(src_cls.get_literal(j)); + lits.push_back(lit); + } + dst_ctx.mk_clause(lits.size(), lits.c_ptr(), 0, src_cls.get_kind(), 0); + } + vector::const_iterator it = src_ctx.m_watches.begin(); + vector::const_iterator end = src_ctx.m_watches.end(); + literal ls[2]; + for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { + literal l1 = to_literal(l_idx); + literal neg_l1 = ~l1; + watch_list const & wl = *it; + literal const * it2 = wl.begin_literals(); + literal const * end2 = wl.end_literals(); + for (; it2 != end2; ++it2) { + literal l2 = *it2; + if (l1.index() < l2.index()) { + ls[0] = TRANSLATE(neg_l1); + ls[1] = TRANSLATE(l2); + dst_ctx.mk_clause(2, ls, 0, CLS_AUX, 0); + } + } + } +#endif + + TRACE("smt_context", + src_ctx.display(tout); + dst_ctx.display(tout);); + } + + context::~context() { flush(); } + void context::copy_plugins(context& src, context& dst) { + + // copy missing simplifier_plugins + // remark: some simplifier_plugins are automatically created by the asserted_formulas class. + simplifier & src_s = src.get_simplifier(); + simplifier & dst_s = dst.get_simplifier(); + ptr_vector::const_iterator it1 = src_s.begin_plugins(); + ptr_vector::const_iterator end1 = src_s.end_plugins(); + for (; it1 != end1; ++it1) { + simplifier_plugin * p = *it1; + if (dst_s.get_plugin(p->get_family_id()) == 0) { + dst.register_plugin(p->mk_fresh()); + } + SASSERT(dst_s.get_plugin(p->get_family_id()) != 0); + } + + // copy theory plugins + ptr_vector::iterator it2 = src.m_theory_set.begin(); + ptr_vector::iterator end2 = src.m_theory_set.end(); + for (; it2 != end2; ++it2) { + theory * new_th = (*it2)->mk_fresh(&dst); + dst.register_plugin(new_th); + } + } + context * context::mk_fresh(symbol const * l, smt_params * p) { context * new_ctx = alloc(context, m_manager, p == 0 ? m_fparams : *p); new_ctx->set_logic(l == 0 ? m_setup.get_logic() : *l); - // copy missing simplifier_plugins - // remark: some simplifier_plugins are automatically created by the asserted_formulas class. - simplifier & s = get_simplifier(); - simplifier & new_s = new_ctx->get_simplifier(); - ptr_vector::const_iterator it1 = s.begin_plugins(); - ptr_vector::const_iterator end1 = s.end_plugins(); - for (; it1 != end1; ++it1) { - simplifier_plugin * p = *it1; - if (new_s.get_plugin(p->get_family_id()) == 0) { - new_ctx->register_plugin(p->mk_fresh()); - } - SASSERT(new_s.get_plugin(p->get_family_id()) != 0); - } - - // copy theory plugins - ptr_vector::iterator it2 = m_theory_set.begin(); - ptr_vector::iterator end2 = m_theory_set.end(); - for (; it2 != end2; ++it2) { - theory * new_th = (*it2)->mk_fresh(new_ctx); - new_ctx->register_plugin(new_th); - } - new_ctx->m_setup.mark_already_configured(); + copy_plugins(*this, *new_ctx); return new_ctx; } + + void context::init() { app * t = m_manager.mk_true(); mk_bool_var(t); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 040054d39..08d68c723 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1326,9 +1326,18 @@ namespace smt { // ----------------------------------- void assert_expr_core(expr * e, proof * pr); + // copy plugins into a fresh context. + void copy_plugins(context& src, context& dst); + + static literal translate_literal( + literal lit, context& src_ctx, context& dst_ctx, + vector b2v, ast_translation& tr); + + public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); + virtual ~context(); /** @@ -1340,6 +1349,12 @@ namespace smt { */ context * mk_fresh(symbol const * l = 0, smt_params * p = 0); + static void copy(context& src, context& dst); + + /** + \brief Translate context to use new manager m. + */ + app * mk_eq_atom(expr * lhs, expr * rhs); bool set_logic(symbol logic) { return m_setup.set_logic(logic); } diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index a4e97380b..de0f91d97 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -32,6 +32,10 @@ namespace smt { m_params(p) { } + static void copy(imp& src, imp& dst) { + context::copy(src.m_kernel, dst.m_kernel); + } + smt_params & fparams() { return m_kernel.get_fparams(); } @@ -193,6 +197,11 @@ namespace smt { return m_imp->m(); } + void kernel::copy(kernel& src, kernel& dst) { + imp::copy(*src.m_imp, *dst.m_imp); + } + + bool kernel::set_logic(symbol logic) { return m_imp->set_logic(logic); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 5c02cf96f..a7a467964 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -50,6 +50,8 @@ namespace smt { ~kernel(); + static void copy(kernel& src, kernel& dst); + ast_manager & m() const; /** diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 524dbeab6..edb4f1e55 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -721,8 +721,8 @@ namespace smt { IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";); st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); IF_VERBOSE(1000, st.display_primitive(verbose_stream());); - bool fixnum = st.arith_k_sum_is_small(); - bool int_only = !st.m_has_rational && !st.m_has_real; + bool fixnum = st.arith_k_sum_is_small() && m_params.m_arith_fixnum; + bool int_only = !st.m_has_rational && !st.m_has_real && m_params.m_arith_int_only; switch(m_params.m_arith_mode) { case AS_NO_ARITH: m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic")); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 1fbb58847..5104291e8 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -37,6 +37,12 @@ namespace smt { if (m_logic != symbol::null) m_context.set_logic(m_logic); } + + virtual solver* translate(ast_manager& m, params_ref const& p) { + solver* result = alloc(solver, m, p, m_logic); + smt::kernel::copy(m_context, result->m_context); + return result; + } virtual ~solver() { } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 5af436919..1e0c7c5f4 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1029,7 +1029,7 @@ namespace smt { theory_arith(ast_manager & m, theory_arith_params & params); virtual ~theory_arith(); - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_arith, get_manager(), m_params); } + virtual theory * mk_fresh(context * new_ctx); virtual void setup(); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 6ae146b1b..96fe2d1f8 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1538,6 +1538,11 @@ namespace smt { theory_arith::~theory_arith() { } + template + theory* theory_arith::mk_fresh(context* new_ctx) { + return alloc(theory_arith, new_ctx->get_manager(), m_params); + } + template void theory_arith::setup() { m_random.set_seed(m_params.m_arith_random_seed); diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 30ae6feac..72e1f1bc2 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -210,7 +210,7 @@ namespace smt { TRACE("arith_int", tout << mk_bounded_pp(bound, get_manager()) << "\n";); context & ctx = get_context(); ctx.internalize(bound, true); - ctx.mark_as_relevant(bound); + ctx.mark_as_relevant(bound.get()); } diff --git a/src/smt/theory_array.h b/src/smt/theory_array.h index ac9e0befa..9cc833d31 100644 --- a/src/smt/theory_array.h +++ b/src/smt/theory_array.h @@ -98,7 +98,7 @@ namespace smt { theory_array(ast_manager & m, theory_array_params & params); virtual ~theory_array(); - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_array, get_manager(), m_params); } + virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_array, new_ctx->get_manager(), m_params); } virtual char const * get_name() const { return "array"; } diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 663816a7d..29e4438c4 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -220,7 +220,7 @@ namespace smt { for (unsigned i = 0; i < dimension; ++i) { sort * ext_sk_domain[2] = { s_array, s_array }; parameter p(i); - func_decl * ext_sk_decl = m.mk_func_decl(get_id(), OP_ARRAY_EXT_SKOLEM, 1, &p, 2, ext_sk_domain); + func_decl * ext_sk_decl = m.mk_func_decl(get_id(), OP_ARRAY_EXT, 1, &p, 2, ext_sk_domain); ext_skolems->push_back(ext_sk_decl); } m_sort2skolem.insert(s_array, ext_skolems); @@ -310,10 +310,7 @@ namespace smt { func_decl_ref_vector * funcs = 0; sort * s = m.get_sort(e1); - if (!m_sort2skolem.find(s, funcs)) { - UNREACHABLE(); - return; - } + VERIFY(m_sort2skolem.find(s, funcs)); unsigned dimension = funcs->size(); diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index 03d180f8c..46cd60fd6 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -36,7 +36,7 @@ namespace smt { bool is_select(app const* n) const { return n->is_app_of(get_id(), OP_SELECT); } bool is_default(app const* n) const { return n->is_app_of(get_id(), OP_ARRAY_DEFAULT); } bool is_const(app const* n) const { return n->is_app_of(get_id(), OP_CONST_ARRAY); } - bool is_array_ext(app const * n) const { return n->is_app_of(get_id(), OP_ARRAY_EXT_SKOLEM); } + bool is_array_ext(app const * n) const { return n->is_app_of(get_id(), OP_ARRAY_EXT); } bool is_as_array(app const * n) const { return n->is_app_of(get_id(), OP_AS_ARRAY); } bool is_array_sort(sort const* s) const { return s->is_sort_of(get_id(), ARRAY_SORT); } bool is_array_sort(app const* n) const { return is_array_sort(get_manager().get_sort(n)); } diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 91f5b68ec..a9dc657dd 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -35,6 +35,10 @@ namespace smt { m_var_data_full.reset(); } + theory* theory_array_full::mk_fresh(context* new_ctx) { + return alloc(theory_array_full, new_ctx->get_manager(), m_params); + } + void theory_array_full::add_map(theory_var v, enode* s) { if (m_params.m_array_cg && !s->is_cgr()) { return; @@ -269,7 +273,7 @@ namespace smt { } context & ctx = get_context(); - if (is_map(n)) { + if (is_map(n) || is_array_ext(n)) { for (unsigned i = 0; i < n->get_num_args(); ++i) { enode* arg = ctx.get_enode(n->get_arg(i)); if (!is_attached_to_var(arg)) { @@ -316,6 +320,10 @@ namespace smt { found_unsupported_op(n); instantiate_default_as_array_axiom(node); } + else if (is_array_ext(n)) { + SASSERT(n->get_num_args() == 2); + instantiate_extensionality(ctx.get_enode(n->get_arg(0)), ctx.get_enode(n->get_arg(1))); + } return true; } diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 870f56739..1200275a2 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -91,7 +91,7 @@ namespace smt { theory_array_full(ast_manager & m, theory_array_params & params); virtual ~theory_array_full(); - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_array_full, get_manager(), m_params); } + virtual theory * mk_fresh(context * new_ctx); virtual void merge_eh(theory_var v1, theory_var v2, theory_var, theory_var); virtual void display_var(std::ostream & out, theory_var v) const; diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index dcf06e1e5..e381e81c1 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1312,6 +1312,11 @@ namespace smt { theory_bv::~theory_bv() { } + + theory* theory_bv::mk_fresh(context* new_ctx) { + return alloc(theory_bv, new_ctx->get_manager(), m_params, m_bb.get_params()); + } + void theory_bv::merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { TRACE("bv", tout << "merging: #" << get_enode(v1)->get_owner_id() << " #" << get_enode(v2)->get_owner_id() << "\n";); diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index 414474a89..bb0dcc907 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -253,7 +253,7 @@ namespace smt { theory_bv(ast_manager & m, theory_bv_params const & params, bit_blaster_params const & bb_params); virtual ~theory_bv(); - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_bv, get_manager(), m_params, m_bb.get_params()); } + virtual theory * mk_fresh(context * new_ctx); virtual char const * get_name() const { return "bit-vector"; } diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index a004da666..cf4658c7d 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -36,6 +36,11 @@ namespace smt { virtual theory_id get_from_theory() const { return null_theory_id; } }; + + theory* theory_datatype::mk_fresh(context* new_ctx) { + return alloc(theory_datatype, new_ctx->get_manager(), m_params); + } + /** \brief Assert the axiom (antecedent => lhs = rhs) antecedent may be null_literal diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 0426613a4..77b1ffc7c 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -101,7 +101,7 @@ namespace smt { public: theory_datatype(ast_manager & m, theory_datatype_params & p); virtual ~theory_datatype(); - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_datatype, get_manager(), m_params); } + virtual theory * mk_fresh(context * new_ctx); virtual void display(std::ostream & out) const; virtual void collect_statistics(::statistics & st) const; virtual void init_model(model_generator & m); diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index b1d1cb632..1b1653eb7 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -282,7 +282,7 @@ namespace smt { theory_dense_diff_logic(ast_manager & m, theory_arith_params & p); virtual ~theory_dense_diff_logic() { reset_eh(); } - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_dense_diff_logic, get_manager(), m_params); } + virtual theory * mk_fresh(context * new_ctx); virtual char const * get_name() const { return "difference-logic"; } diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 4c35647e8..7702a1ef2 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -39,6 +39,11 @@ namespace smt { m_edges.push_back(edge()); } + template + theory* theory_dense_diff_logic::mk_fresh(context * new_ctx) { + return alloc(theory_dense_diff_logic, new_ctx->get_manager(), m_params); + } + template inline app * theory_dense_diff_logic::mk_zero_for(expr * n) { return m_autil.mk_numeral(rational(0), get_manager().get_sort(n)); diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index ed96d050e..390bd271d 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -243,7 +243,7 @@ namespace smt { reset_eh(); } - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_diff_logic, get_manager(), m_params); } + virtual theory * mk_fresh(context * new_ctx); virtual char const * get_name() const { return "difference-logic"; } diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index c791668c3..f444fe88e 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1384,5 +1384,11 @@ bool theory_diff_logic::internalize_objective(expr * n, rational const& m, return true; } +template +theory* theory_diff_logic::mk_fresh(context* new_ctx) { + return alloc(theory_diff_logic, new_ctx->get_manager(), m_params); +} + + #endif /* THEORY_DIFF_LOGIC_DEF_H_ */ diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index 3c80a5ef2..ac64db74c 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -155,7 +155,7 @@ namespace smt { } virtual theory * mk_fresh(context * new_ctx) { - return alloc(theory_dl, get_manager()); + return alloc(theory_dl, new_ctx->get_manager()); } virtual void init_model(smt::model_generator & m) { diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 66a1a6321..0cd803cc0 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -142,7 +142,8 @@ namespace smt { m_trail_stack(*this), m_fpa_util(m_converter.fu()), m_bv_util(m_converter.bu()), - m_arith_util(m_converter.au()) + m_arith_util(m_converter.au()), + m_is_initialized(false) { params_ref p; p.set_bool("arith_lhs", true); @@ -151,10 +152,24 @@ namespace smt { theory_fpa::~theory_fpa() { - ast_manager & m = get_manager(); - dec_ref_map_values(m, m_conversions); - dec_ref_map_values(m, m_wraps); - dec_ref_map_values(m, m_unwraps); + if (m_is_initialized) { + ast_manager & m = get_manager(); + dec_ref_map_values(m, m_conversions); + dec_ref_map_values(m, m_wraps); + dec_ref_map_values(m, m_unwraps); + } + else { + SASSERT(m_conversions.empty()); + SASSERT(m_wraps.empty()); + SASSERT(m_unwraps.empty()); + } + + m_is_initialized = false; + } + + void theory_fpa::init(context * ctx) { + smt::theory::init(ctx); + m_is_initialized = true; } app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { @@ -716,6 +731,10 @@ namespace smt { return; } + theory* theory_fpa::mk_fresh(context* new_ctx) { + return alloc(theory_fpa, new_ctx->get_manager()); + } + void theory_fpa::push_scope_eh() { theory::push_scope_eh(); m_trail_stack.push_scope(); @@ -859,6 +878,16 @@ namespace smt { mk_ismt2_pp(a2, m) << " eq. cls. #" << get_enode(a2)->get_root()->get_owner()->get_id() << std::endl;); res = vp; } + else if (is_app_of(owner, get_family_id(), OP_FPA_INTERNAL_RM)) { + SASSERT(to_app(owner)->get_num_args() == 1); + app_ref a0(m); + a0 = to_app(owner->get_arg(0)); + fpa_rm_value_proc * vp = alloc(fpa_rm_value_proc, this); + vp->add_dependency(ctx.get_enode(a0)); + TRACE("t_fpa_detail", tout << "Depends on: " << + mk_ismt2_pp(a0, m) << " eq. cls. #" << get_enode(a0)->get_root()->get_owner()->get_id() << std::endl;); + res = vp; + } else if (ctx.e_internalized(wrapped)) { if (m_fpa_util.is_rm(owner)) { fpa_rm_value_proc * vp = alloc(fpa_rm_value_proc, this); diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 990701c4a..1b0fc6c54 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -148,6 +148,7 @@ namespace smt { obj_map m_wraps; obj_map m_unwraps; obj_map m_conversions; + bool m_is_initialized; virtual final_check_status final_check_eh(); virtual bool internalize_atom(app * atom, bool gate_ctx); @@ -158,7 +159,7 @@ namespace smt { virtual void push_scope_eh(); virtual void pop_scope_eh(unsigned num_scopes); virtual void reset_eh(); - virtual theory* mk_fresh(context*) { return alloc(theory_fpa, get_manager()); } + virtual theory* mk_fresh(context* new_ctx); virtual char const * get_name() const { return "fpa"; } virtual model_value_proc * mk_value(enode * n, model_generator & mg); @@ -169,9 +170,11 @@ namespace smt { virtual void finalize_model(model_generator & mg); public: - theory_fpa(ast_manager& m); + theory_fpa(ast_manager & m); virtual ~theory_fpa(); + virtual void init(context * ctx); + virtual void display(std::ostream & out) const; protected: diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index c176d2fd1..60350017f 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -29,7 +29,7 @@ namespace smt { virtual bool internalize_term(app*) { return internalize_atom(0,false); } virtual void new_eq_eh(theory_var, theory_var) { } virtual void new_diseq_eh(theory_var, theory_var) {} - virtual theory* mk_fresh(context*) { return alloc(theory_seq_empty, get_manager()); } + virtual theory* mk_fresh(context* new_ctx) { return alloc(theory_seq_empty, new_ctx->get_manager()); } virtual char const * get_name() const { return "seq-empty"; } public: theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {} diff --git a/src/smt/theory_utvpi.cpp b/src/smt/theory_utvpi.cpp index c45cfe74a..9da82c9e6 100644 --- a/src/smt/theory_utvpi.cpp +++ b/src/smt/theory_utvpi.cpp @@ -156,5 +156,5 @@ namespace smt { return true; } - + } diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 8568238fa..35ebd440b 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -183,7 +183,7 @@ namespace smt { virtual ~theory_utvpi(); - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_utvpi, get_manager()); } + virtual theory * mk_fresh(context * new_ctx); virtual char const * get_name() const { return "utvpi-logic"; } diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index bca24406f..22b19b0b1 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -942,6 +942,10 @@ namespace smt { } } + template + theory* theory_utvpi::mk_fresh(context* new_ctx) { + return alloc(theory_utvpi, new_ctx->get_manager()); + } }; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 649a79be2..85f84e26e 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -127,6 +127,17 @@ public: m_use_solver1_results = true; } + solver* translate(ast_manager& m, params_ref const& p) { + solver* s1 = m_solver1->translate(m, p); + solver* s2 = m_solver2->translate(m, p); + combined_solver* r = alloc(combined_solver, s1, s2, p); + r->m_solver2_initialized = m_solver2_initialized; + r->m_inc_mode = m_inc_mode; + r->m_check_sat_executed = m_check_sat_executed; + r->m_use_solver1_results = m_use_solver1_results; + return r; + } + virtual void updt_params(params_ref const & p) { m_solver1->updt_params(p); m_solver2->updt_params(p); diff --git a/src/solver/solver.h b/src/solver/solver.h index 63592ea3b..8b5e98433 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -46,6 +46,12 @@ public: class solver : public check_sat_result { public: virtual ~solver() {} + + /** + \brief Creates a clone of the solver. + */ + virtual solver* translate(ast_manager& m, params_ref const& p) = 0; + /** \brief Update the solver internal settings. */ @@ -135,6 +141,8 @@ public: */ virtual expr * get_assumption(unsigned idx) const = 0; + + /** \brief Display the content of this solver. */ diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index d7dc3ad37..02b9bd347 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -22,6 +22,7 @@ Notes: #include"solver_na2as.h" #include"tactic.h" #include"ast_pp_util.h" +#include"ast_translation.h" /** \brief Simulates the incremental solver interface using a tactic. @@ -45,6 +46,8 @@ public: tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic); virtual ~tactic2solver(); + virtual solver* translate(ast_manager& m, params_ref const& p); + virtual void updt_params(params_ref const & p); virtual void collect_param_descrs(param_descrs & r); @@ -183,6 +186,22 @@ void tactic2solver::set_cancel(bool f) { } } +solver* tactic2solver::translate(ast_manager& m, params_ref const& p) { + tactic* t = m_tactic->translate(m); + tactic2solver* r = alloc(tactic2solver, m, t, p, m_produce_proofs, m_produce_models, m_produce_unsat_cores, m_logic); + r->m_result = 0; + if (!m_scopes.empty()) { + throw default_exception("translation of contexts is only supported at base level"); + } + ast_translation tr(m_assertions.get_manager(), m, false); + + for (unsigned i = 0; i < get_num_assertions(); ++i) { + r->m_assertions.push_back(tr(get_assertion(i))); + } + return r; +} + + void tactic2solver::collect_statistics(statistics & st) const { st.copy(m_stats); //SASSERT(m_stats.size() > 0); diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index b84d5567c..7cba66a5a 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -305,14 +305,16 @@ public: m_nonfd.mark(f, true); expr* e1, *e2; if (m.is_eq(f, e1, e2)) { - if (is_fd(e1, e2)) { + if (is_fd(e1, e2) || is_fd(e2, e1)) { continue; - } - if (is_fd(e2, e1)) { - continue; - } + } } - m_todo.append(to_app(f)->get_num_args(), to_app(f)->get_args()); + if (is_app(f)) { + m_todo.append(to_app(f)->get_num_args(), to_app(f)->get_args()); + } + else if (is_quantifier(f)) { + m_todo.push_back(to_quantifier(f)->get_expr()); + } } } diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp new file mode 100644 index 000000000..6245ed2bc --- /dev/null +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -0,0 +1,377 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + bvarray2uf_rewriter.cpp + +Abstract: + + Rewriter that rewrites bit-vector arrays into bit-vector + (uninterpreted) functions. + +Author: + + Christoph (cwinter) 2015-11-04 + +Notes: + +--*/ + +#include"cooperate.h" +#include"bv_decl_plugin.h" +#include"array_decl_plugin.h" +#include"params.h" +#include"ast_pp.h" +#include"bvarray2uf_rewriter.h" + +// [1] C. M. Wintersteiger, Y. Hamadi, and L. de Moura: Efficiently Solving +// Quantified Bit-Vector Formulas, in Formal Methods in System Design, +// vol. 42, no. 1, pp. 3-23, Springer, 2013. + +bvarray2uf_rewriter_cfg::bvarray2uf_rewriter_cfg(ast_manager & m, params_ref const & p) : + m_manager(m), + m_out(m), + m_bindings(m), + m_bv_util(m), + m_array_util(m), + m_emc(0), + m_fmc(0), + extra_assertions(m) { + updt_params(p); + // We need to make sure that the mananger has the BV and array plugins loaded. + symbol s_bv("bv"); + if (!m_manager.has_plugin(s_bv)) + m_manager.register_plugin(s_bv, alloc(bv_decl_plugin)); + symbol s_array("array"); + if (!m_manager.has_plugin(s_array)) + m_manager.register_plugin(s_array, alloc(array_decl_plugin)); +} + +bvarray2uf_rewriter_cfg::~bvarray2uf_rewriter_cfg() { + for (obj_map::iterator it = m_arrays_fs.begin(); + it != m_arrays_fs.end(); + it++) + m_manager.dec_ref(it->m_value); +} + +void bvarray2uf_rewriter_cfg::reset() {} + +sort * bvarray2uf_rewriter_cfg::get_index_sort(expr * e) { + return get_index_sort(m_manager.get_sort(e)); +} + +sort * bvarray2uf_rewriter_cfg::get_index_sort(sort * s) { + SASSERT(s->get_num_parameters() >= 2); + unsigned total_width = 0; + for (unsigned i = 0; i < s->get_num_parameters() - 1; i++) { + parameter const & p = s->get_parameter(i); + SASSERT(p.is_ast() && is_sort(to_sort(p.get_ast()))); + SASSERT(m_bv_util.is_bv_sort(to_sort(p.get_ast()))); + total_width += m_bv_util.get_bv_size(to_sort(p.get_ast())); + } + return m_bv_util.mk_sort(total_width); +} + +sort * bvarray2uf_rewriter_cfg::get_value_sort(expr * e) { + return get_value_sort(m_manager.get_sort(e)); +} + +sort * bvarray2uf_rewriter_cfg::get_value_sort(sort * s) { + SASSERT(s->get_num_parameters() >= 2); + parameter const & p = s->get_parameter(s->get_num_parameters() - 1); + SASSERT(p.is_ast() && is_sort(to_sort(p.get_ast()))); + return to_sort(p.get_ast()); +} + +bool bvarray2uf_rewriter_cfg::is_bv_array(expr * e) { + return is_bv_array(m_manager.get_sort(e)); +} + +bool bvarray2uf_rewriter_cfg::is_bv_array(sort * s) { + if (!m_array_util.is_array(s)) + return false; + + SASSERT(s->get_num_parameters() >= 2); + for (unsigned i = 0; i < s->get_num_parameters(); i++) { + parameter const & p = s->get_parameter(i); + if (!p.is_ast() || !is_sort(to_sort(p.get_ast())) || + !m_bv_util.is_bv_sort(to_sort(p.get_ast()))) + return false; + } + + return true; +} + +func_decl_ref bvarray2uf_rewriter_cfg::mk_uf_for_array(expr * e) { + SASSERT(is_bv_array(e)); + + if (m_array_util.is_as_array(e)) + return func_decl_ref(static_cast(to_app(e)->get_decl()->get_parameter(0).get_ast()), m_manager); + else { + app * a = to_app(e); + func_decl * bv_f = 0; + if (!m_arrays_fs.find(e, bv_f)) { + sort * domain = get_index_sort(a); + sort * range = get_value_sort(a); + bv_f = m_manager.mk_fresh_func_decl("f_t", "", 1, &domain, range); + if (is_uninterp_const(e)) { + if (m_emc) + m_emc->insert(to_app(e)->get_decl(), + m_array_util.mk_as_array(m_manager.get_sort(e), bv_f)); + } + else if (m_fmc) + m_fmc->insert(bv_f); + m_arrays_fs.insert(e, bv_f); + m_manager.inc_ref(bv_f); + } + + return func_decl_ref(bv_f, m_manager); + } +} + +br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + br_status res = BR_FAILED; + + if (m_manager.is_eq(f) && is_bv_array(f->get_domain()[0])) { + SASSERT(num == 2); + // From [1]: Finally, we replace equations of the form t = s, + // where t and s are arrays, with \forall x . f_t(x) = f_s(x). + func_decl_ref f_t(mk_uf_for_array(args[0]), m_manager); + func_decl_ref f_s(mk_uf_for_array(args[1]), m_manager); + + sort * sorts[1] = { get_index_sort(m_manager.get_sort(args[0])) }; + symbol names[1] = { symbol("x") }; + var_ref x(m_manager.mk_var(0, sorts[0]), m_manager); + + expr_ref body(m_manager); + body = m_manager.mk_eq(m_manager.mk_app(f_t, x.get()), m_manager.mk_app(f_s, x.get())); + + result = m_manager.mk_forall(1, sorts, names, body); + res = BR_DONE; + } + else if (m_manager.is_distinct(f) && is_bv_array(f->get_domain()[0])) { + result = m_manager.mk_distinct_expanded(num, args); + res = BR_REWRITE1; + } + else if (f->get_family_id() == null_family_id) { + TRACE("bvarray2uf_rw", tout << "UF APP: " << f->get_name() << std::endl; ); + + bool has_bv_arrays = false; + func_decl_ref f_t(m_manager); + for (unsigned i = 0; i < num; i++) { + if (is_bv_array(args[i])) { + SASSERT(m_array_util.is_as_array(args[i])); + has_bv_arrays = true; + } + } + + expr_ref t(m_manager); + t = m_manager.mk_app(f, num, args); + + if (is_bv_array(t)) { + // From [1]: For every array term t we create a fresh uninterpreted function f_t. + f_t = mk_uf_for_array(t); + result = m_array_util.mk_as_array(m_manager.get_sort(t), f_t); + res = BR_DONE; + } + else if (has_bv_arrays) { + result = t; + res = BR_DONE; + } + else + res = BR_FAILED; + } + else if (m_array_util.get_family_id() == f->get_family_id()) { + TRACE("bvarray2uf_rw", tout << "APP: " << f->get_name() << std::endl; ); + + if (m_array_util.is_select(f)) { + SASSERT(num == 2); + expr * t = args[0]; + expr * i = args[1]; + TRACE("bvarray2uf_rw", tout << + "select; array: " << mk_ismt2_pp(t, m()) << + " index: " << mk_ismt2_pp(i, m()) << std::endl;); + + if (!is_bv_array(t)) + res = BR_FAILED; + else { + // From [1]: Then, we replace terms of the form select(t, i) with f_t(i). + func_decl_ref f_t(mk_uf_for_array(t), m_manager); + result = m_manager.mk_app(f_t, i); + res = BR_DONE; + } + } + else { + if (!is_bv_array(f->get_range())) + res = BR_FAILED; + else { + if (m_array_util.is_const(f)) { + SASSERT(num == 1); + expr_ref t(m_manager.mk_app(f, num, args), m_manager); + expr * v = args[0]; + func_decl_ref f_t(mk_uf_for_array(t), m_manager); + + result = m_array_util.mk_as_array(f->get_range(), f_t); + res = BR_DONE; + + // Add \forall x . f_t(x) = v + sort * sorts[1] = { get_index_sort(f->get_range()) }; + symbol names[1] = { symbol("x") }; + var_ref x(m_manager.mk_var(0, sorts[0]), m_manager); + + expr_ref body(m_manager); + body = m_manager.mk_eq(m_manager.mk_app(f_t, x.get()), v); + + expr_ref frllx(m_manager.mk_forall(1, sorts, names, body), m_manager); + extra_assertions.push_back(frllx); + } + else if (m_array_util.is_as_array(f)) { + res = BR_FAILED; + } + else if (m_array_util.is_map(f)) { + SASSERT(f->get_num_parameters() == 1); + SASSERT(f->get_parameter(0).is_ast()); + expr_ref t(m_manager.mk_app(f, num, args), m_manager); + func_decl_ref f_t(mk_uf_for_array(t), m_manager); + func_decl_ref map_f(to_func_decl(f->get_parameter(0).get_ast()), m_manager); + + func_decl_ref_vector ss(m_manager); + for (unsigned i = 0; i < num; i++) { + SASSERT(m_array_util.is_array(args[i])); + func_decl_ref fd(mk_uf_for_array(args[i]), m_manager); + ss.push_back(fd); + } + + // Add \forall x . f_t(x) = map_f(a[x], b[x], ...) + sort * sorts[1] = { get_index_sort(f->get_range()) }; + symbol names[1] = { symbol("x") }; + var_ref x(m_manager.mk_var(0, sorts[0]), m_manager); + + expr_ref_vector new_args(m_manager); + for (unsigned i = 0; i < num; i++) + new_args.push_back(m_manager.mk_app(ss[i].get(), x.get())); + + expr_ref body(m_manager); + body = m_manager.mk_eq(m_manager.mk_app(f_t, x.get()), + m_manager.mk_app(map_f, num, new_args.c_ptr())); + + expr_ref frllx(m_manager.mk_forall(1, sorts, names, body), m_manager); + extra_assertions.push_back(frllx); + + result = m_array_util.mk_as_array(f->get_range(), f_t); + res = BR_DONE; + } + else if (m_array_util.is_store(f)) { + SASSERT(num == 3); + expr * s = args[0]; + expr * i = args[1]; + expr * v = args[2]; + TRACE("bvarray2uf_rw", tout << + "store; array: " << mk_ismt2_pp(s, m()) << + " index: " << mk_ismt2_pp(i, m()) << + " value: " << mk_ismt2_pp(v, m()) << std::endl;); + if (!is_bv_array(s)) + res = BR_FAILED; + else { + expr_ref t(m_manager.mk_app(f, num, args), m_manager); + // From [1]: For every term t of the form store(s, i, v), we add the universal + // formula \forall x . x = i \vee f_t(x) = f_s(x), and the ground atom f_t(i) = v. + func_decl_ref f_s(mk_uf_for_array(s), m_manager); + func_decl_ref f_t(mk_uf_for_array(t), m_manager); + + result = m_array_util.mk_as_array(f->get_range(), f_t); + res = BR_DONE; + + sort * sorts[1] = { get_index_sort(f->get_range()) }; + symbol names[1] = { symbol("x") }; + var_ref x(m_manager.mk_var(0, sorts[0]), m_manager); + + expr_ref body(m_manager); + body = m_manager.mk_or(m_manager.mk_eq(x, i), + m_manager.mk_eq(m_manager.mk_app(f_t, x.get()), + m_manager.mk_app(f_s, x.get()))); + + expr_ref frllx(m_manager.mk_forall(1, sorts, names, body), m_manager); + extra_assertions.push_back(frllx); + + expr_ref ground_atom(m_manager); + ground_atom = m_manager.mk_eq(m_manager.mk_app(f_t, i), v); + extra_assertions.push_back(ground_atom); + TRACE("bvarray2uf_rw", tout << "ground atom: " << mk_ismt2_pp(ground_atom, m()) << std::endl; ); + } + } + else { + NOT_IMPLEMENTED_YET(); + res = BR_FAILED; + } + } + } + } + + CTRACE("bvarray2uf_rw", res==BR_DONE, tout << "result: " << mk_ismt2_pp(result, m()) << std::endl; ); + return res; +} + +bool bvarray2uf_rewriter_cfg::pre_visit(expr * t) +{ + TRACE("bvarray2uf_rw_q", tout << "pre_visit: " << mk_ismt2_pp(t, m()) << std::endl;); + + if (is_quantifier(t)) { + quantifier * q = to_quantifier(t); + TRACE("bvarray2uf_rw_q", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;); + sort_ref_vector new_bindings(m_manager); + for (unsigned i = 0; i < q->get_num_decls(); i++) + new_bindings.push_back(q->get_decl_sort(i)); + SASSERT(new_bindings.size() == q->get_num_decls()); + m_bindings.append(new_bindings); + } + return true; +} + +bool bvarray2uf_rewriter_cfg::reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + unsigned curr_sz = m_bindings.size(); + SASSERT(old_q->get_num_decls() <= curr_sz); + unsigned num_decls = old_q->get_num_decls(); + unsigned old_sz = curr_sz - num_decls; + string_buffer<> name_buffer; + ptr_buffer new_decl_sorts; + sbuffer new_decl_names; + for (unsigned i = 0; i < num_decls; i++) { + symbol const & n = old_q->get_decl_name(i); + sort * s = old_q->get_decl_sort(i); + + NOT_IMPLEMENTED_YET(); + + } + result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(), + new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(), + old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns); + result_pr = 0; + m_bindings.shrink(old_sz); + TRACE("bvarray2uf_rw_q", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " << + mk_ismt2_pp(old_q->get_expr(), m()) << std::endl << + " new body: " << mk_ismt2_pp(new_body, m()) << std::endl; + tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;); + return true; +} + +bool bvarray2uf_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { + if (t->get_idx() >= m_bindings.size()) + return false; + + expr_ref new_exp(m()); + sort * s = t->get_sort(); + + NOT_IMPLEMENTED_YET(); + + result = new_exp; + result_pr = 0; + TRACE("bvarray2uf_rw_q", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;); + return true; +} diff --git a/src/tactic/bv/bvarray2uf_rewriter.h b/src/tactic/bv/bvarray2uf_rewriter.h new file mode 100644 index 000000000..e65340cc3 --- /dev/null +++ b/src/tactic/bv/bvarray2uf_rewriter.h @@ -0,0 +1,87 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + bvarray2uf_rewriter.h + +Abstract: + + Rewriter that rewrites bit-vector arrays into bit-vector + (uninterpreted) functions. + +Author: + + Christoph (cwinter) 2015-11-04 + +Notes: + +--*/ +#ifndef BVARRAY2UF_REWRITER_H_ +#define BVARRAY2UF_REWRITER_H_ + +#include"rewriter_def.h" +#include"extension_model_converter.h" +#include"filter_model_converter.h" + +class bvarray2uf_rewriter_cfg : public default_rewriter_cfg { + ast_manager & m_manager; + expr_ref_vector m_out; + sort_ref_vector m_bindings; + bv_util m_bv_util; + array_util m_array_util; + extension_model_converter * m_emc; + filter_model_converter * m_fmc; + + obj_map m_arrays_fs; + +public: + bvarray2uf_rewriter_cfg(ast_manager & m, params_ref const & p); + ~bvarray2uf_rewriter_cfg(); + + ast_manager & m() const { return m_manager; } + void updt_params(params_ref const & p) {} + + void reset(); + + bool pre_visit(expr * t); + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr); + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr); + + bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr); + + expr_ref_vector extra_assertions; + + void set_mcs(extension_model_converter * emc, filter_model_converter * fmc) { m_emc = emc; m_fmc = fmc; } + +protected: + sort * get_index_sort(expr * e); + sort * get_index_sort(sort * s); + sort * get_value_sort(expr * e); + sort * get_value_sort(sort * s); + bool is_bv_array(expr * e); + bool is_bv_array(sort * e); + func_decl_ref mk_uf_for_array(expr * e); +}; + +template class rewriter_tpl; + +struct bvarray2uf_rewriter : public rewriter_tpl { + bvarray2uf_rewriter_cfg m_cfg; + bvarray2uf_rewriter(ast_manager & m, params_ref const & p) : + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, p) { + } + + void set_mcs(extension_model_converter * emc, filter_model_converter * fmc) { m_cfg.set_mcs(emc, fmc); } +}; + +#endif + diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp new file mode 100644 index 000000000..6bf1324f1 --- /dev/null +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -0,0 +1,168 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + bvarray2uf_tactic.cpp + +Abstract: + + Tactic that rewrites bit-vector arrays into bit-vector + (uninterpreted) functions. + +Author: + + Christoph (cwinter) 2015-11-04 + +Notes: + +--*/ +#include"tactical.h" +#include"bv_decl_plugin.h" +#include"expr_replacer.h" +#include"extension_model_converter.h" +#include"filter_model_converter.h" +#include"ast_smt2_pp.h" + +#include"bvarray2uf_tactic.h" +#include"bvarray2uf_rewriter.h" + +class bvarray2uf_tactic : public tactic { + + struct imp { + ast_manager & m_manager; + bool m_produce_models; + bool m_produce_proofs; + bool m_produce_cores; + volatile bool m_cancel; + bvarray2uf_rewriter m_rw; + + ast_manager & m() { return m_manager; } + + imp(ast_manager & m, params_ref const & p) : + m_manager(m), + m_produce_models(false), + m_cancel(false), + m_produce_proofs(false), + m_produce_cores(false), + m_rw(m, p) { + updt_params(p); + } + + void set_cancel(bool f) { + m_cancel = f; + } + + void checkpoint() { + if (m_cancel) + throw tactic_exception(TACTIC_CANCELED_MSG); + } + + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) + { + SASSERT(g->is_well_sorted()); + tactic_report report("bvarray2uf", *g); + mc = 0; pc = 0; core = 0; result.reset(); + fail_if_proof_generation("bvarray2uf", g); + fail_if_unsat_core_generation("bvarray2uf", g); + + TRACE("bvarray2uf", tout << "Before: " << std::endl; g->display(tout); ); + m_produce_models = g->models_enabled(); + + if (m_produce_models) { + extension_model_converter * emc = alloc(extension_model_converter, m_manager); + filter_model_converter * fmc = alloc(filter_model_converter, m_manager); + mc = concat(emc, fmc); + m_rw.set_mcs(emc, fmc); + + } + + + m_rw.reset(); + expr_ref new_curr(m_manager); + proof_ref new_pr(m_manager); + unsigned size = g->size(); + for (unsigned idx = 0; idx < size; idx++) { + if (g->inconsistent()) + break; + expr * curr = g->form(idx); + m_rw(curr, new_curr, new_pr); + //if (m_produce_proofs) { + // proof * pr = g->pr(idx); + // new_pr = m.mk_modus_ponens(pr, new_pr); + //} + g->update(idx, new_curr, new_pr, g->dep(idx)); + } + + for (unsigned i = 0; i < m_rw.m_cfg.extra_assertions.size(); i++) + g->assert_expr(m_rw.m_cfg.extra_assertions[i].get()); + + g->inc_depth(); + result.push_back(g.get()); + TRACE("bvarray2uf", tout << "After: " << std::endl; g->display(tout);); + SASSERT(g->is_well_sorted()); + } + + void updt_params(params_ref const & p) { + } + }; + + imp * m_imp; + params_ref m_params; + +public: + bvarray2uf_tactic(ast_manager & m, params_ref const & p) : + m_params(p) { + m_imp = alloc(imp, m, p); + } + + virtual tactic * translate(ast_manager & m) { + return alloc(bvarray2uf_tactic, m, m_params); + } + + virtual ~bvarray2uf_tactic() { + dealloc(m_imp); + } + + virtual void updt_params(params_ref const & p) { + m_params = p; + m_imp->updt_params(p); + } + + virtual void collect_param_descrs(param_descrs & r) { + insert_produce_models(r); + } + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + (*m_imp)(in, result, mc, pc, core); + } + + virtual void cleanup() { + ast_manager & m = m_imp->m(); + imp * d = alloc(imp, m, m_params); + #pragma omp critical (tactic_cancel) + { + std::swap(d, m_imp); + } + dealloc(d); + } + + virtual void set_cancel(bool f) { + if (m_imp) + m_imp->set_cancel(f); + } + +}; + + +tactic * mk_bvarray2uf_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(bvarray2uf_tactic, m, p)); +} diff --git a/src/tactic/bv/bvarray2uf_tactic.h b/src/tactic/bv/bvarray2uf_tactic.h new file mode 100644 index 000000000..608a831e0 --- /dev/null +++ b/src/tactic/bv/bvarray2uf_tactic.h @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + bvarray2ufbvarray2uf_tactic.h + +Abstract: + + Tactic that rewrites bit-vector arrays into bit-vector + (uninterpreted) functions. + +Author: + + Christoph (cwinter) 2015-11-04 + +Notes: + +--*/ +#ifndef BV_ARRAY2UF_TACTIC_H_ +#define BV_ARRAY2UF_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_bvarray2uf_tactic(ast_manager & m, params_ref const & p = params_ref()); +/* + ADD_TACTIC("bvarray2uf", "Rewrite bit-vector arrays into bit-vector (uninterpreted) functions.", "mk_bvarray2uf_tactic(m, p)") +*/ + + +#endif \ No newline at end of file diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp new file mode 100644 index 000000000..d2c7ff5f4 --- /dev/null +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -0,0 +1,332 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + elim_small_bv.h + +Abstract: + + Tactic that eliminates small, quantified bit-vectors. + +Author: + + Christoph (cwinter) 2015-11-09 + +Revision History: + +--*/ +#include"tactical.h" +#include"rewriter_def.h" +#include"filter_model_converter.h" +#include"cooperate.h" +#include"bv_decl_plugin.h" +#include"used_vars.h" +#include"well_sorted.h" +#include"var_subst.h" +#include"simplifier.h" +#include"basic_simplifier_plugin.h" +#include"bv_simplifier_plugin.h" + +#include"elim_small_bv_tactic.h" + +class elim_small_bv_tactic : public tactic { + + struct rw_cfg : public default_rewriter_cfg { + ast_manager & m; + bv_util m_util; + simplifier m_simp; + ref m_mc; + goal * m_goal; + unsigned m_max_bits; + unsigned long long m_max_steps; + unsigned long long m_max_memory; // in bytes + bool m_produce_models; + sort_ref_vector m_bindings; + unsigned long m_num_eliminated; + + rw_cfg(ast_manager & _m, params_ref const & p) : + m(_m), + m_util(_m), + m_simp(_m), + m_bindings(_m), + m_num_eliminated(0) { + updt_params(p); + m_goal = 0; + m_max_steps = UINT_MAX; + + basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m); + // bsimp->set_eliminate_and(true); + m_simp.register_plugin(bsimp); + + bv_simplifier_params bv_params; + bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m, *bsimp, bv_params); + m_simp.register_plugin(bvsimp); + } + + bool max_steps_exceeded(unsigned long long num_steps) const { + cooperate("elim-small-bv"); + if (num_steps > m_max_steps) + return true; + if (memory::get_allocation_size() > m_max_memory) + throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + return false; + } + + bool is_small_bv(sort * s) { + return m_util.is_bv_sort(s) && m_util.get_bv_size(s) <= m_max_bits; + } + + expr_ref replace_var(used_vars & uv, + unsigned num_decls, unsigned max_var_idx_p1, + unsigned idx, sort * s, expr * e, expr * replacement) { + TRACE("elim_small_bv", tout << "replace idx " << idx << " with " << mk_ismt2_pp(replacement, m) << + " in " << mk_ismt2_pp(e, m) << std::endl;); + expr_ref res(m); + expr_ref_vector substitution(m); + + substitution.resize(num_decls, 0); + substitution[num_decls - idx - 1] = replacement; + + // (VAR 0) is in the first position of substitution; (VAR num_decls-1) is in the last position. + + for (unsigned i = 0; i < max_var_idx_p1; i++) { + sort * s = uv.get(i); + substitution.push_back(0); + } + + // (VAR num_decls) ... (VAR num_decls+sz-1); are in positions num_decls .. num_decls+sz-1 + + std::reverse(substitution.c_ptr(), substitution.c_ptr() + substitution.size()); + + // (VAR 0) should be in the last position of substitution. + + TRACE("elim_small_bv", tout << "substitution: " << std::endl; + for (unsigned k = 0; k < substitution.size(); k++) { + expr * se = substitution[k].get(); + tout << k << " = "; + if (se == 0) tout << "0"; + else tout << mk_ismt2_pp(se, m); + tout << std::endl; + }); + + var_subst vsbst(m); + vsbst(e, substitution.size(), substitution.c_ptr(), res); + SASSERT(is_well_sorted(m, res)); + + proof_ref pr(m); + m_simp(res, res, pr); + TRACE("elim_small_bv", tout << "replace done: " << mk_ismt2_pp(res, m) << std::endl;); + + return res; + } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + result = m.mk_app(f, num, args); + TRACE("elim_small_bv_app", tout << "reduce " << mk_ismt2_pp(result, m) << std::endl; ); + return BR_FAILED; + } + + bool reduce_quantifier( + quantifier * q, + expr * old_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + TRACE("elim_small_bv", tout << "reduce_quantifier " << mk_ismt2_pp(q, m) << std::endl; ); + unsigned long long num_steps = 0; + unsigned curr_sz = m_bindings.size(); + SASSERT(q->get_num_decls() <= curr_sz); + unsigned num_decls = q->get_num_decls(); + unsigned old_sz = curr_sz - num_decls; + + used_vars uv; + uv(q); + SASSERT(is_well_sorted(m, q)); + unsigned max_var_idx_p1 = uv.get_max_found_var_idx_plus_1(); + + expr_ref body(old_body, m); + for (unsigned i = num_decls-1; i != ((unsigned)-1) && !max_steps_exceeded(num_steps); i--) { + sort * s = q->get_decl_sort(i); + symbol const & name = q->get_decl_name(i); + unsigned bv_sz = m_util.get_bv_size(s); + + if (is_small_bv(s) && !max_steps_exceeded(num_steps)) { + TRACE("elim_small_bv", tout << "eliminating " << name << + "; sort = " << mk_ismt2_pp(s, m) << + "; body = " << mk_ismt2_pp(body, m) << std::endl;); + + expr_ref_vector new_bodies(m); + for (unsigned j = 0; j < bv_sz && !max_steps_exceeded(num_steps); j ++) { + expr_ref n(m_util.mk_numeral(j, bv_sz), m); + expr_ref nb(m); + nb = replace_var(uv, num_decls, max_var_idx_p1, i, s, body, n); + new_bodies.push_back(nb); + num_steps++; + } + + TRACE("elim_small_bv", tout << "new bodies: " << std::endl; + for (unsigned k = 0; k < new_bodies.size(); k++) + tout << mk_ismt2_pp(new_bodies[k].get(), m) << std::endl; ); + + body = q->is_forall() ? m.mk_and(new_bodies.size(), new_bodies.c_ptr()) : + m.mk_or(new_bodies.size(), new_bodies.c_ptr()); + SASSERT(is_well_sorted(m, body)); + + proof_ref pr(m); + m_simp(body, body, pr); + m_num_eliminated++; + } + } + + quantifier_ref new_q(m); + new_q = m.update_quantifier(q, body); + unused_vars_eliminator el(m); + el(new_q, result); + + TRACE("elim_small_bv", tout << "elimination result: " << mk_ismt2_pp(result, m) << std::endl; ); + + result_pr = 0; // proofs NIY + m_bindings.shrink(old_sz); + return true; + } + + bool pre_visit(expr * t) { + TRACE("elim_small_bv_pre", tout << "pre_visit: " << mk_ismt2_pp(t, m) << std::endl;); + if (is_quantifier(t)) { + quantifier * q = to_quantifier(t); + TRACE("elim_small_bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m) << std::endl;); + sort_ref_vector new_bindings(m); + for (unsigned i = 0; i < q->get_num_decls(); i++) + new_bindings.push_back(q->get_decl_sort(i)); + SASSERT(new_bindings.size() == q->get_num_decls()); + m_bindings.append(new_bindings); + } + return true; + } + + void updt_params(params_ref const & p) { + m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_max_steps = p.get_uint("max_steps", UINT_MAX); + m_max_bits = p.get_uint("max_bits", 4); + } + }; + + struct rw : public rewriter_tpl { + rw_cfg m_cfg; + + rw(ast_manager & m, params_ref const & p) : + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, p) { + } + }; + + struct imp { + ast_manager & m; + rw m_rw; + + imp(ast_manager & _m, params_ref const & p) : + m(_m), + m_rw(m, p) { + } + + void set_cancel(bool f) { + m_rw.set_cancel(f); + } + + void updt_params(params_ref const & p) { + m_rw.cfg().updt_params(p); + } + + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(g->is_well_sorted()); + mc = 0; pc = 0; core = 0; + tactic_report report("elim-small-bv", *g); + bool produce_proofs = g->proofs_enabled(); + fail_if_proof_generation("elim-small-bv", g); + fail_if_unsat_core_generation("elim-small-bv", g); + m_rw.cfg().m_produce_models = g->models_enabled(); + + m_rw.m_cfg.m_goal = g.get(); + expr_ref new_curr(m); + proof_ref new_pr(m); + unsigned size = g->size(); + for (unsigned idx = 0; idx < size; idx++) { + expr * curr = g->form(idx); + m_rw(curr, new_curr, new_pr); + if (produce_proofs) { + proof * pr = g->pr(idx); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_curr, new_pr, g->dep(idx)); + } + mc = m_rw.m_cfg.m_mc.get(); + + report_tactic_progress(":elim-small-bv-num-eliminated", m_rw.m_cfg.m_num_eliminated); + g->inc_depth(); + result.push_back(g.get()); + TRACE("elim-small-bv", g->display(tout);); + SASSERT(g->is_well_sorted()); + } + }; + + imp * m_imp; + params_ref m_params; +public: + elim_small_bv_tactic(ast_manager & m, params_ref const & p) : + m_params(p) { + m_imp = alloc(imp, m, p); + } + + virtual tactic * translate(ast_manager & m) { + return alloc(elim_small_bv_tactic, m, m_params); + } + + virtual ~elim_small_bv_tactic() { + dealloc(m_imp); + } + + virtual void updt_params(params_ref const & p) { + m_params = p; + m_imp->m_rw.cfg().updt_params(p); + } + + virtual void collect_param_descrs(param_descrs & r) { + insert_max_memory(r); + insert_max_steps(r); + r.insert("max_bits", CPK_UINT, "(default: 4) maximum bit-vector size of quantified bit-vectors to be eliminated."); + } + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + (*m_imp)(in, result, mc, pc, core); + } + + virtual void cleanup() { + ast_manager & m = m_imp->m; + imp * d = alloc(imp, m, m_params); +#pragma omp critical (tactic_cancel) + { + std::swap(d, m_imp); + } + dealloc(d); + } + + virtual void set_cancel(bool f) { + if (m_imp) + m_imp->set_cancel(f); + } +}; + +tactic * mk_elim_small_bv_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(elim_small_bv_tactic, m, p)); +} + diff --git a/src/tactic/bv/elim_small_bv_tactic.h b/src/tactic/bv/elim_small_bv_tactic.h new file mode 100644 index 000000000..bcdd8aad6 --- /dev/null +++ b/src/tactic/bv/elim_small_bv_tactic.h @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + elim_small_bv.h + +Abstract: + + Tactic that eliminates small, quantified bit-vectors. + +Author: + + Christoph (cwinter) 2015-11-09 + +Revision History: + +--*/ +#ifndef ELIM_SMALL_BV_H_ +#define ELIM_SMALL_BV_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_elim_small_bv_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("elim-small-bv", "eliminate small, quantified bit-vectors by expansion.", "mk_elim_small_bv_tactic(m, p)") +*/ + +#endif diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 62ad363fd..fdbe54c4d 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -177,7 +177,6 @@ expr_ref fpa2bv_model_converter::convert_bv2rm(expr * eval_v) const { rational bv_val(0); unsigned sz = 0; - if (bu.is_numeral(eval_v, bv_val, sz)) { SASSERT(bv_val.is_uint64()); switch (bv_val.get_uint64()) { @@ -309,9 +308,9 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { expr * bvval = to_app(val)->get_arg(0); expr_ref fv(m); fv = convert_bv2rm(bv_mdl, var, bvval); - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << std::endl;); + TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); float_mdl->register_decl(var, fv); - seen.insert(to_app(val)->get_decl()); + seen.insert(to_app(bvval)->get_decl()); } for (obj_map::iterator it = m_uf2bvuf.begin(); diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index d10b7c1b4..816d69b1f 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -25,6 +25,7 @@ Notes: #include"max_bv_sharing_tactic.h" #include"bv_size_reduction_tactic.h" #include"reduce_args_tactic.h" +#include"qfbv_tactic.h" tactic * mk_qfufbv_tactic(ast_manager & m, params_ref const & p) { params_ref main_p; @@ -41,13 +42,11 @@ tactic * mk_qfufbv_tactic(ast_manager & m, params_ref const & p) { ); tactic * st = using_params(and_then(preamble_st, - mk_smt_tactic()), + cond(mk_is_qfbv_probe(), + mk_qfbv_tactic(m), + mk_smt_tactic())), main_p); - //cond(is_qfbv(), - // and_then(mk_bit_blaster(m), - // mk_sat_solver(m)), - // mk_smt_solver()) st->updt_params(p); return st; } diff --git a/src/util/util.cpp b/src/util/util.cpp index c4b729adb..bfd4923a8 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -151,24 +151,3 @@ void escaped::display(std::ostream & out) const { } } -#ifdef _WINDOWS -#ifdef ARRAYSIZE -#undef ARRAYSIZE -#endif -#include -#endif - -void z3_bound_num_procs() { - -#ifdef _Z3_COMMERCIAL -#define Z3_COMMERCIAL_MAX_CORES 4 -#ifdef _WINDOWS - DWORD_PTR numProcs = (1 << Z3_COMMERCIAL_MAX_CORES) - 1; - SetProcessAffinityMask(GetCurrentProcess(), numProcs); -#endif -#else - // Not bounded: Research evaluations are - // not reasonable if run with artificial - // or hidden throttles. -#endif -} diff --git a/src/util/util.h b/src/util/util.h index f97f5c1f9..1e15b526c 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -400,7 +400,6 @@ inline size_t megabytes_to_bytes(unsigned mb) { return r; } -void z3_bound_num_procs(); #endif /* UTIL_H_ */