From 89971e2a98e513a7516d84b09609dd8997337b5b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 10:37:30 -0800 Subject: [PATCH 01/72] remove smtlib1 dependencies Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 3 +- src/CMakeLists.txt | 1 - src/api/CMakeLists.txt | 1 - src/api/api_context.cpp | 37 - src/api/api_context.h | 12 +- src/api/api_interp.cpp | 30 +- src/api/api_parsers.cpp | 222 +-- src/api/z3_api.h | 106 +- src/parsers/smt/CMakeLists.txt | 8 - src/parsers/smt/smtlib.cpp | 258 --- src/parsers/smt/smtlib.h | 232 --- src/parsers/smt/smtlib_solver.cpp | 119 -- src/parsers/smt/smtlib_solver.h | 48 - src/parsers/smt/smtparser.cpp | 2760 ----------------------------- src/parsers/smt/smtparser.h | 48 - src/shell/main.cpp | 11 +- src/shell/smtlib_frontend.cpp | 38 +- src/test/quant_elim.cpp | 7 +- 18 files changed, 23 insertions(+), 3918 deletions(-) delete mode 100644 src/parsers/smt/CMakeLists.txt delete mode 100644 src/parsers/smt/smtlib.cpp delete mode 100644 src/parsers/smt/smtlib.h delete mode 100644 src/parsers/smt/smtlib_solver.cpp delete mode 100644 src/parsers/smt/smtlib_solver.h delete mode 100644 src/parsers/smt/smtparser.cpp delete mode 100644 src/parsers/smt/smtparser.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 05190f217..5ab56d1c7 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -75,10 +75,9 @@ def init_project_def(): add_lib('smtlogic_tactics', ['ackermannization', 'sat_solver', 'arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe','nlsat_smt_tactic'], 'tactic/smtlogics') add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic', 'arith_tactics', 'smtlogic_tactics'], 'tactic/fpa') add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') - add_lib('smtparser', ['portfolio'], 'parsers/smt') add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic', 'sat_solver'], 'opt') API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_interp.h', 'z3_fpa.h', 'z3_spacer.h'] - add_lib('api', ['portfolio', 'smtparser', 'realclosure', 'interp', 'opt'], + add_lib('api', ['portfolio', 'realclosure', 'interp', 'opt'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing', 'simplex'], exe_name='test-z3', install=False) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfe6e5265..7cde89ae2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -98,7 +98,6 @@ add_subdirectory(sat/sat_solver) add_subdirectory(tactic/smtlogics) add_subdirectory(tactic/fpa) add_subdirectory(tactic/portfolio) -add_subdirectory(parsers/smt) add_subdirectory(opt) add_subdirectory(api) add_subdirectory(api/dll) diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index a413376ac..fcdbb1651 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -71,5 +71,4 @@ z3_add_component(api opt portfolio realclosure - smtparser ) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 1e3f7a0a4..73fb2c212 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -19,7 +19,6 @@ Revision History: --*/ #include #include "api/api_context.h" -#include "parsers/smt/smtparser.h" #include "util/version.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" @@ -89,8 +88,6 @@ namespace api { m_print_mode = Z3_PRINT_SMTLIB_FULL; m_searching = false; - m_smtlib_parser = 0; - m_smtlib_parser_has_decls = false; m_interruptable = 0; m_error_handler = &default_error_handler; @@ -111,7 +108,6 @@ namespace api { context::~context() { - reset_parser(); m_last_obj = 0; u_map::iterator it = m_allocated_objects.begin(); while (it != m_allocated_objects.end()) { @@ -304,39 +300,6 @@ namespace api { } } - - // ------------------------ - // - // Parser interface for backward compatibility - // - // ------------------------ - - void context::reset_parser() { - if (m_smtlib_parser) { - dealloc(m_smtlib_parser); - m_smtlib_parser = 0; - m_smtlib_parser_has_decls = false; - m_smtlib_parser_decls.reset(); - m_smtlib_parser_sorts.reset(); - } - SASSERT(!m_smtlib_parser_has_decls); - } - - void context::extract_smtlib_parser_decls() { - if (m_smtlib_parser) { - if (!m_smtlib_parser_has_decls) { - smtlib::symtable * table = m_smtlib_parser->get_benchmark()->get_symtable(); - table->get_func_decls(m_smtlib_parser_decls); - table->get_sorts(m_smtlib_parser_sorts); - m_smtlib_parser_has_decls = true; - } - } - else { - m_smtlib_parser_decls.reset(); - m_smtlib_parser_sorts.reset(); - } - } - // ------------------------ // // RCF manager diff --git a/src/api/api_context.h b/src/api/api_context.h index 6f8dc43f6..58893d1c1 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -220,19 +220,11 @@ namespace api { // ------------------------ // - // Parser interface for backward compatibility + // Parser interface // // ------------------------ - // TODO: move to a "parser" object visible to the external world. - std::string m_smtlib_error_buffer; - smtlib::parser * m_smtlib_parser; - bool m_smtlib_parser_has_decls; - ptr_vector m_smtlib_parser_decls; - ptr_vector m_smtlib_parser_sorts; - - void reset_parser(); - void extract_smtlib_parser_decls(); + std::string m_parser_error_buffer; }; diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index 416c71adf..d6f4e1128 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -510,31 +510,15 @@ extern "C" { read_error.clear(); try { std::string foo(filename); - if (foo.size() >= 5 && foo.substr(foo.size() - 5) == ".smt2"){ - Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); - Z3_app app = Z3_to_app(ctx, assrts); - int nconjs = Z3_get_app_num_args(ctx, app); - assertions.resize(nconjs); - for (int k = 0; k < nconjs; k++) - assertions[k] = Z3_get_app_arg(ctx, app, k); - } - else { - Z3_parse_smtlib_file(ctx, filename, 0, 0, 0, 0, 0, 0); - int numa = Z3_get_smtlib_num_assumptions(ctx); - int numf = Z3_get_smtlib_num_formulas(ctx); - int num = numa + numf; - - assertions.resize(num); - for (int j = 0; j < num; j++){ - if (j < numa) - assertions[j] = Z3_get_smtlib_assumption(ctx, j); - else - assertions[j] = Z3_get_smtlib_formula(ctx, j - numa); - } - } + Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); + Z3_app app = Z3_to_app(ctx, assrts); + int nconjs = Z3_get_app_num_args(ctx, app); + assertions.resize(nconjs); + for (int k = 0; k < nconjs; k++) + assertions[k] = Z3_get_app_arg(ctx, app, k); } catch (...) { - read_error << "SMTLIB parse error: " << Z3_get_smtlib_error(ctx); + read_error << "SMTLIB parse error: " << Z3_get_parser_error(ctx); read_msg = read_error.str(); *error = read_msg.c_str(); return false; diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index b3252281b..867117984 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -22,232 +22,16 @@ Revision History: #include "api/api_util.h" #include "cmd_context/cmd_context.h" #include "parsers/smt2/smt2parser.h" -#include "parsers/smt/smtparser.h" #include "solver/solver_na2as.h" extern "C" { - void init_smtlib_parser(Z3_context c, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const types[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[]) { - mk_c(c)->reset_parser(); - mk_c(c)->m_smtlib_parser = smtlib::parser::create(mk_c(c)->m()); - mk_c(c)->m_smtlib_parser->initialize_smtlib(); - smtlib::symtable * table = mk_c(c)->m_smtlib_parser->get_benchmark()->get_symtable(); - for (unsigned i = 0; i < num_sorts; i++) { - table->insert(to_symbol(sort_names[i]), to_sort(types[i])); - } - for (unsigned i = 0; i < num_decls; i++) { - table->insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); - } - } - - void Z3_API Z3_parse_smtlib_string(Z3_context c, - const char * str, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const sorts[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[]) { - Z3_TRY; - LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - scoped_ptr outs = alloc(std::ostringstream); - bool ok = false; - RESET_ERROR_CODE(); - init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(*outs); - try { - ok = mk_c(c)->m_smtlib_parser->parse_string(str); - } - catch (...) { - ok = false; - } - mk_c(c)->m_smtlib_error_buffer = outs->str(); - outs = nullptr; - if (!ok) { - mk_c(c)->reset_parser(); - SET_ERROR_CODE(Z3_PARSER_ERROR); - } - Z3_CATCH; - } - - void Z3_API Z3_parse_smtlib_file(Z3_context c, - const char * file_name, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const types[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[]) { + Z3_string Z3_API Z3_get_parser_error(Z3_context c) { Z3_TRY; - LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls); - bool ok = false; - RESET_ERROR_CODE(); - scoped_ptr outs = alloc(std::ostringstream); - init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(*outs); - try { - ok = mk_c(c)->m_smtlib_parser->parse_file(file_name); - } - catch(...) { - ok = false; - } - mk_c(c)->m_smtlib_error_buffer = outs->str(); - outs = nullptr; - if (!ok) { - mk_c(c)->reset_parser(); - SET_ERROR_CODE(Z3_PARSER_ERROR); - } - Z3_CATCH; - } - - unsigned Z3_API Z3_get_smtlib_num_formulas(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_formulas(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - return mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_formulas(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_ast Z3_API Z3_get_smtlib_formula(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_formula(c, i); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - if (i < mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_formulas()) { - ast * f = mk_c(c)->m_smtlib_parser->get_benchmark()->begin_formulas()[i]; - mk_c(c)->save_ast_trail(f); - RETURN_Z3(of_ast(f)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - unsigned Z3_API Z3_get_smtlib_num_assumptions(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_assumptions(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - return mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_axioms(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_ast Z3_API Z3_get_smtlib_assumption(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_assumption(c, i); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - if (i < mk_c(c)->m_smtlib_parser->get_benchmark()->get_num_axioms()) { - ast * a = mk_c(c)->m_smtlib_parser->get_benchmark()->begin_axioms()[i]; - mk_c(c)->save_ast_trail(a); - RETURN_Z3(of_ast(a)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - unsigned Z3_API Z3_get_smtlib_num_decls(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_decls(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - mk_c(c)->extract_smtlib_parser_decls(); - return mk_c(c)->m_smtlib_parser_decls.size(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_func_decl Z3_API Z3_get_smtlib_decl(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_decl(c, i); + LOG_Z3_get_parser_error(c); RESET_ERROR_CODE(); - mk_c(c)->extract_smtlib_parser_decls(); - if (mk_c(c)->m_smtlib_parser) { - if (i < mk_c(c)->m_smtlib_parser_decls.size()) { - func_decl * d = mk_c(c)->m_smtlib_parser_decls[i]; - mk_c(c)->save_ast_trail(d); - RETURN_Z3(of_func_decl(d)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - unsigned Z3_API Z3_get_smtlib_num_sorts(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_num_sorts(c); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - mk_c(c)->extract_smtlib_parser_decls(); - return mk_c(c)->m_smtlib_parser_sorts.size(); - } - SET_ERROR_CODE(Z3_NO_PARSER); - return 0; - Z3_CATCH_RETURN(0); - } - - Z3_sort Z3_API Z3_get_smtlib_sort(Z3_context c, unsigned i) { - Z3_TRY; - LOG_Z3_get_smtlib_sort(c, i); - RESET_ERROR_CODE(); - if (mk_c(c)->m_smtlib_parser) { - mk_c(c)->extract_smtlib_parser_decls(); - if (i < mk_c(c)->m_smtlib_parser_sorts.size()) { - sort* s = mk_c(c)->m_smtlib_parser_sorts[i]; - mk_c(c)->save_ast_trail(s); - RETURN_Z3(of_sort(s)); - } - else { - SET_ERROR_CODE(Z3_IOB); - } - } - else { - SET_ERROR_CODE(Z3_NO_PARSER); - } - RETURN_Z3(0); - Z3_CATCH_RETURN(0); - } - - Z3_string Z3_API Z3_get_smtlib_error(Z3_context c) { - Z3_TRY; - LOG_Z3_get_smtlib_error(c); - RESET_ERROR_CODE(); - return mk_c(c)->m_smtlib_error_buffer.c_str(); + return mk_c(c)->m_parser_error_buffer.c_str(); Z3_CATCH_RETURN(""); } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index cf1c8fca7..56d9f69b7 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5228,115 +5228,13 @@ extern "C" { Z3_symbol const decl_names[], Z3_func_decl const decls[]); - /** - \brief Parse the given string using the SMT-LIB parser. - - The symbol table of the parser can be initialized using the given sorts and declarations. - The symbols in the arrays \c sort_names and \c decl_names don't need to match the names - of the sorts and declarations in the arrays \c sorts and \c decls. This is an useful feature - since we can use arbitrary names to reference sorts and declarations defined using the C API. - - The formulas, assumptions and declarations defined in \c str can be extracted using the functions: - #Z3_get_smtlib_num_formulas, #Z3_get_smtlib_formula, #Z3_get_smtlib_num_assumptions, #Z3_get_smtlib_assumption, - #Z3_get_smtlib_num_decls, and #Z3_get_smtlib_decl. - - def_API('Z3_parse_smtlib_string', VOID, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) - */ - void Z3_API Z3_parse_smtlib_string(Z3_context c, - Z3_string str, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const sorts[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[] - ); - - /** - \brief Similar to #Z3_parse_smtlib_string, but reads the benchmark from a file. - - def_API('Z3_parse_smtlib_file', VOID, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) - */ - void Z3_API Z3_parse_smtlib_file(Z3_context c, - Z3_string file_name, - unsigned num_sorts, - Z3_symbol const sort_names[], - Z3_sort const sorts[], - unsigned num_decls, - Z3_symbol const decl_names[], - Z3_func_decl const decls[] - ); - - /** - \brief Return the number of SMTLIB formulas parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_formulas', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_formulas(Z3_context c); - - /** - \brief Return the i-th formula parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_formulas(c) - - def_API('Z3_get_smtlib_formula', AST, (_in(CONTEXT), _in(UINT))) - */ - Z3_ast Z3_API Z3_get_smtlib_formula(Z3_context c, unsigned i); - - /** - \brief Return the number of SMTLIB assumptions parsed by #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_assumptions', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_assumptions(Z3_context c); - - /** - \brief Return the i-th assumption parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_assumptions(c) - - def_API('Z3_get_smtlib_assumption', AST, (_in(CONTEXT), _in(UINT))) - */ - Z3_ast Z3_API Z3_get_smtlib_assumption(Z3_context c, unsigned i); - - /** - \brief Return the number of declarations parsed by #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_decls', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_decls(Z3_context c); - - /** - \brief Return the i-th declaration parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_decls(c) - - def_API('Z3_get_smtlib_decl', FUNC_DECL, (_in(CONTEXT), _in(UINT))) - */ - Z3_func_decl Z3_API Z3_get_smtlib_decl(Z3_context c, unsigned i); - - /** - \brief Return the number of sorts parsed by #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - def_API('Z3_get_smtlib_num_sorts', UINT, (_in(CONTEXT), )) - */ - unsigned Z3_API Z3_get_smtlib_num_sorts(Z3_context c); - - /** - \brief Return the i-th sort parsed by the last call to #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. - - \pre i < Z3_get_smtlib_num_sorts(c) - - def_API('Z3_get_smtlib_sort', SORT, (_in(CONTEXT), _in(UINT))) - */ - Z3_sort Z3_API Z3_get_smtlib_sort(Z3_context c, unsigned i); /** \brief Retrieve that last error message information generated from parsing. - def_API('Z3_get_smtlib_error', STRING, (_in(CONTEXT), )) + def_API('Z3_get_parser_error', STRING, (_in(CONTEXT), )) */ - Z3_string Z3_API Z3_get_smtlib_error(Z3_context c); + Z3_string Z3_API Z3_get_parser_error(Z3_context c); /*@}*/ /** @name Error Handling */ diff --git a/src/parsers/smt/CMakeLists.txt b/src/parsers/smt/CMakeLists.txt deleted file mode 100644 index 2edf7b679..000000000 --- a/src/parsers/smt/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -z3_add_component(smtparser - SOURCES - smtlib.cpp - smtlib_solver.cpp - smtparser.cpp - COMPONENT_DEPENDENCIES - portfolio -) diff --git a/src/parsers/smt/smtlib.cpp b/src/parsers/smt/smtlib.cpp deleted file mode 100644 index 71dd48156..000000000 --- a/src/parsers/smt/smtlib.cpp +++ /dev/null @@ -1,258 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - - -#include "parsers/smt/smtlib.h" -#include "ast/ast_pp.h" -#include "ast/ast_smt2_pp.h" - -#ifdef _WINDOWS -#ifdef ARRAYSIZE -#undef ARRAYSIZE -#endif -#include -#include -#endif - -#include - - -using namespace smtlib; - -// -------------------------------------------------------------------------- -// symtable - -symtable::~symtable() { - reset(); -} - -void symtable::reset() { - svector*> range; - m_ids.get_range(range); - for (unsigned i = 0; i < range.size(); ++i) { - ptr_vector const & v = *range[i]; - for (unsigned j = 0; j < v.size(); ++j) { - m_manager.dec_ref(v[j]); - } - dealloc(range[i]); - } - m_ids.reset(); - ptr_vector sorts; - m_sorts1.get_range(sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - m_manager.dec_ref(sorts[i]); - } - m_sorts1.reset(); - ptr_vector sort_builders; - m_sorts.get_range(sort_builders); - for (unsigned i = 0; i < sort_builders.size(); ++i) { - dealloc(sort_builders[i]); - } - m_sorts.reset(); -} - - -void symtable::insert(symbol s, func_decl * d) { - ptr_vector* decls = 0; - m_manager.inc_ref(d); - if (!m_ids.find(s, decls)) { - SASSERT(!decls); - decls = alloc(ptr_vector); - decls->push_back(d); - m_ids.insert(s, decls); - } - else { - SASSERT(decls); - if ((*decls)[0] != d) { - decls->push_back(d); - } - else { - m_manager.dec_ref(d); - } - } -} - -bool symtable::find1(symbol s, func_decl*& d) { - ptr_vector* decls = 0; - - if (!m_ids.find(s, decls)) { - SASSERT(!decls); - return false; - } - SASSERT(decls && !decls->empty()); - d = (*decls)[0]; - return true; -} - -bool symtable::find_overload(symbol s, ptr_vector const & dom, func_decl * & d) { - ptr_vector* decls = 0; - d = 0; - if (!m_ids.find(s, decls)) { - SASSERT(!decls); - return false; - } - SASSERT(decls); - for (unsigned i = 0; i < decls->size(); ++i) { - func_decl* decl = (*decls)[i]; - if (decl->is_associative() && decl->get_arity() > 0) { - for (unsigned j = 0; j < dom.size(); ++j) { - if (dom[j] != decl->get_domain(0)) { - goto try_next; - } - } - d = decl; - return true; - } - - if (decl->get_arity() != dom.size()) { - goto try_next; - } - for (unsigned j = 0; j < decl->get_arity(); ++j) { - if (decl->get_domain(j) != dom[j]) { - goto try_next; - } - } - d = decl; - return true; - - try_next: - if (decl->get_family_id() == m_manager.get_basic_family_id() && decl->get_decl_kind() == OP_DISTINCT) { - // we skip type checking for 'distinct' - d = decl; - return true; - } - } - return false; -} - -// Store in result the func_decl that are not attached to any family id. -// That is, the uninterpreted constants and function declarations. -void symtable::get_func_decls(ptr_vector & result) const { - svector*> tmp; - m_ids.get_range(tmp); - svector*>::const_iterator it = tmp.begin(); - svector*>::const_iterator end = tmp.end(); - for (; it != end; ++it) { - ptr_vector * curr = *it; - if (curr) { - ptr_vector::const_iterator it2 = curr->begin(); - ptr_vector::const_iterator end2 = curr->end(); - for (; it2 != end2; ++it2) { - func_decl * d = *it2; - if (d && d->get_family_id() == null_family_id) { - result.push_back(d); - } - } - } - } -} - -void symtable::insert(symbol s, sort_builder* sb) { - m_sorts.insert(s, sb); -} - -bool symtable::lookup(symbol s, sort_builder*& sb) { - return m_sorts.find(s, sb); -} - -void symtable::push_sort(symbol name, sort* srt) { - m_sorts.begin_scope(); - sort_builder* sb = alloc(basic_sort_builder,srt); - m_sorts.insert(name, sb); - m_sorts_trail.push_back(sb); -} - -void symtable::pop_sorts(unsigned num_sorts) { - while (num_sorts > 0) { - dealloc(m_sorts_trail.back()); - m_sorts_trail.pop_back(); - m_sorts.end_scope(); - } -} - -void symtable::get_sorts(ptr_vector& result) const { - vector tmp; - m_sorts1.get_range(tmp); - for (unsigned i = 0; i < tmp.size(); ++i) { - if (tmp[i]->get_family_id() == null_family_id) { - result.push_back(tmp[i]); - } - } -} - - -// -------------------------------------------------------------------------- -// theory - -func_decl * theory::declare_func(symbol const & id, sort_ref_buffer & domain, sort * range, - bool is_assoc, bool is_comm, bool is_inj) { - func_decl * decl = m_ast_manager.mk_func_decl(id, domain.size(), domain.c_ptr(), range, - is_assoc, is_comm, is_inj); - - m_symtable.insert(id, decl); - m_asts.push_back(decl); - return decl; -} - - -sort * theory::declare_sort(symbol const & id) { - sort * decl = m_ast_manager.mk_uninterpreted_sort(id); - m_symtable.insert(id, decl); - m_asts.push_back(decl); - return decl; -} - - -bool theory::get_func_decl(symbol id, func_decl * & decl) { - return m_symtable.find1(id, decl); -} - -bool theory::get_sort(symbol id, sort* & s) { - return m_symtable.find(id, s); -} - -bool theory::get_const(symbol id, expr * & term) { - func_decl* decl = 0; - if (!get_func_decl(id,decl)) { - return false; - } - if (decl->get_arity() != 0) { - return false; - } - term = m_ast_manager.mk_const(decl); - m_asts.push_back(term); - return true; -} - -void benchmark::display_as_smt2(std::ostream & out) const { - if (m_logic != symbol::null) - out << "(set-logic " << m_logic << ")\n"; - out << "(set-info :smt-lib-version 2.0)\n"; - out << "(set-info :status "; - switch (m_status) { - case SAT: out << "sat"; break; - case UNSAT: out << "unsat"; break; - default: out << "unknown"; break; - } - out << ")\n"; -#if 0 - ast_manager & m = m_ast_manager; - ptr_vector decls; - m_symtable.get_func_decls(decls); - ptr_vector::const_iterator it = decls.begin(); - ptr_vector::const_iterator end = decls.end(); - for (; it != end; ++it) { - func_decl * f = *it; - out << "(declare-fun " << f->get_name() << " ("; - for (unsigned i = 0; i < f->get_arity(); i++) { - if (i > 0) out << " "; - out << mk_ismt2_pp(f->get_domain(i), m); - } - out << ") " << mk_ismt2_pp(f->get_range(), m); - out << ")\n"; - } -#endif -} diff --git a/src/parsers/smt/smtlib.h b/src/parsers/smt/smtlib.h deleted file mode 100644 index f037e3d74..000000000 --- a/src/parsers/smt/smtlib.h +++ /dev/null @@ -1,232 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtlib.h - -Abstract: - - SMT library utilities - -Author: - - Nikolaj Bjorner (nbjorner) 2006-09-29 - -Revision History: - ---*/ -#ifndef SMTLIB_H_ -#define SMTLIB_H_ - -#include "ast/ast.h" -#include "util/symbol_table.h" -#include "util/map.h" -#include "ast/arith_decl_plugin.h" - -namespace smtlib { - - class sort_builder { - public: - virtual ~sort_builder() {} - virtual bool apply(unsigned num_params, parameter const* params, sort_ref& result) = 0; - virtual char const* error_message() { return ""; } - }; - - class basic_sort_builder : public sort_builder { - sort* m_sort; - public: - basic_sort_builder(sort* s) : m_sort(s) {} - - virtual bool apply(unsigned np, parameter const*, sort_ref& result) { - result = m_sort; - return m_sort && np != 0; - } - }; - - - class symtable { - ast_manager& m_manager; - symbol_table m_sorts1; - symbol_table m_sorts; - ptr_vector m_sorts_trail; - symbol_table* > m_ids; - - public: - - symtable(ast_manager& m): m_manager(m) {} - - ~symtable(); - - void reset(); - - void insert(symbol s, func_decl * d); - - bool find(symbol s, ptr_vector * & decls) { - return m_ids.find(s, decls); - } - - bool find1(symbol s, func_decl * & d); - - bool find_overload(symbol s, ptr_vector const & dom, func_decl * & d); - - void insert(symbol s, sort * d) { - sort * d2; - if (m_sorts1.find(s, d2)) { - m_manager.dec_ref(d2); - } - m_manager.inc_ref(d); - m_sorts1.insert(s, d); - } - - bool find(symbol s, sort * & d) { - return m_sorts1.find(s, d); - } - - void insert(symbol s, sort_builder* sb); - - bool lookup(symbol s, sort_builder*& sb); - - void push_sort(symbol s, sort*); - - void pop_sorts(unsigned num_sorts); - - void get_func_decls(ptr_vector & result) const; - - void get_sorts(ptr_vector& result) const; - }; - - class theory { - public: - typedef ptr_vector::const_iterator expr_iterator; - - theory(ast_manager & ast_manager, symbol const& name): - m_name(name), - m_ast_manager(ast_manager), - m_symtable(ast_manager), - m_asts(ast_manager) - {} - - virtual ~theory() {} - - symtable * get_symtable() { return &m_symtable; } - - void insert(sort * s) { m_symtable.insert(s->get_name(), s); } - - void insert(func_decl * c) { m_symtable.insert(c->get_name(), c); } - - func_decl * declare_func(symbol const & id, sort_ref_buffer & domain, sort * range, - bool is_assoc, bool is_comm, bool is_inj); - - sort * declare_sort(symbol const & id); - - void add_axiom(expr * axiom) { - m_asts.push_back(axiom); - m_axioms.push_back(axiom); - } - - expr_iterator begin_axioms() const { - return m_axioms.begin(); - } - - unsigned get_num_axioms() const { - return m_axioms.size(); - } - - expr * const * get_axioms() const { - return m_axioms.c_ptr(); - } - - expr_iterator end_axioms() const { - return m_axioms.end(); - } - - void add_assumption(expr * axiom) { - m_asts.push_back(axiom); - m_assumptions.push_back(axiom); - } - - unsigned get_num_assumptions() const { - return m_assumptions.size(); - } - - expr * const * get_assumptions() const { - return m_assumptions.c_ptr(); - } - - bool get_func_decl(symbol, func_decl*&); - - bool get_sort(symbol, sort*&); - - bool get_const(symbol, expr*&); - - void set_name(symbol const& name) { m_name = name; } - - symbol const get_name() const { return m_name; } - protected: - symbol m_name; - ast_manager& m_ast_manager; - ptr_vector m_axioms; - ptr_vector m_assumptions; - symtable m_symtable; - ast_ref_vector m_asts; - - private: - theory& operator=(theory const&); - - theory(theory const&); - }; - - class benchmark : public theory { - public: - enum status { - UNKNOWN, - SAT, - UNSAT - }; - - benchmark(ast_manager & ast_manager, symbol const & name) : - theory(ast_manager, name), - m_status(UNKNOWN) {} - - virtual ~benchmark() {} - - status get_status() const { return m_status; } - void set_status(status status) { m_status = status; } - - symbol get_logic() const { - if (m_logic == symbol::null) { - return symbol("ALL"); - } - return m_logic; - } - - void set_logic(symbol const & s) { m_logic = s; } - - unsigned get_num_formulas() const { - return m_formulas.size(); - } - - expr_iterator begin_formulas() const { - return m_formulas.begin(); - } - - expr_iterator end_formulas() const { - return m_formulas.end(); - } - - void add_formula(expr * formula) { - m_asts.push_back(formula); - m_formulas.push_back(formula); - } - - void display_as_smt2(std::ostream & out) const; - - private: - status m_status; - symbol m_logic; - ptr_vector m_formulas; - }; -}; - -#endif diff --git a/src/parsers/smt/smtlib_solver.cpp b/src/parsers/smt/smtlib_solver.cpp deleted file mode 100644 index 339be2ddd..000000000 --- a/src/parsers/smt/smtlib_solver.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtlib_solver.cpp - -Abstract: - - SMT based solver. - -Author: - - Nikolaj Bjorner (nbjorner) 2006-11-3. - -Revision History: - ---*/ - -#include "parsers/smt/smtparser.h" -#include "parsers/smt/smtlib_solver.h" -#include "util/warning.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/well_sorted.h" -#include "model/model.h" -#include "model/model_v2_pp.h" -#include "solver/solver.h" -#include "tactic/portfolio/smt_strategic_solver.h" -#include "cmd_context/cmd_context.h" -#include "model/model_params.hpp" -#include "parsers/util/parser_params.hpp" - -namespace smtlib { - - solver::solver(): - m_ast_manager(m_params.m_proof ? PGM_ENABLED : PGM_DISABLED, - m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0), - m_ctx(0), - m_error_code(0) { - parser_params ps; - m_parser = parser::create(m_ast_manager, ps.ignore_user_patterns()); - m_parser->initialize_smtlib(); - } - - solver::~solver() { - if (m_ctx) - dealloc(m_ctx); - } - - bool solver::solve_smt(char const * benchmark_file) { - IF_VERBOSE(100, verbose_stream() << "parsing...\n";); - if (!m_parser->parse_file(benchmark_file)) { - if (benchmark_file) { - warning_msg("could not parse file '%s'.", benchmark_file); - } - else { - warning_msg("could not parse input stream."); - } - m_error_code = ERR_PARSER; - return false; - } - benchmark * benchmark = m_parser->get_benchmark(); - solve_benchmark(*benchmark); - return true; - } - - bool solver::solve_smt_string(char const * benchmark_string) { - if (!m_parser->parse_string(benchmark_string)) { - warning_msg("could not parse string '%s'.", benchmark_string); - return false; - } - benchmark * benchmark = m_parser->get_benchmark(); - solve_benchmark(*benchmark); - return true; - } - - void solver::display_statistics() { - if (m_ctx) - m_ctx->display_statistics(); - } - - void solver::solve_benchmark(benchmark & benchmark) { - if (benchmark.get_num_formulas() == 0) { - // Hack: it seems SMT-LIB allow benchmarks without any :formula - benchmark.add_formula(m_ast_manager.mk_true()); - } - m_ctx = alloc(cmd_context, true, &m_ast_manager, benchmark.get_logic()); - m_ctx->set_solver_factory(mk_smt_strategic_solver_factory()); - theory::expr_iterator fit = benchmark.begin_formulas(); - theory::expr_iterator fend = benchmark.end_formulas(); - for (; fit != fend; ++fit) - solve_formula(benchmark, *fit); - } - - void solver::solve_formula(benchmark const & benchmark, expr * f) { - IF_VERBOSE(100, verbose_stream() << "starting...\n";); - m_ctx->reset(); - for (unsigned i = 0; i < benchmark.get_num_axioms(); i++) - m_ctx->assert_expr(benchmark.get_axioms()[i]); - m_ctx->assert_expr(f); - m_ctx->check_sat(benchmark.get_num_assumptions(), benchmark.get_assumptions()); - check_sat_result * r = m_ctx->get_check_sat_result(); - if (r != 0) { - proof * pr = r->get_proof(); - if (pr != 0 && m_params.m_proof) - std::cout << mk_ll_pp(pr, m_ast_manager, false, false); - model_ref md; - if (r->status() != l_false) r->get_model(md); - if (md.get() != 0 && m_params.m_model) { - model_params p; - model_v2_pp(std::cout, *(md.get()), p.partial()); - } - } - else { - m_error_code = ERR_UNKNOWN_RESULT; - } - } -}; diff --git a/src/parsers/smt/smtlib_solver.h b/src/parsers/smt/smtlib_solver.h deleted file mode 100644 index 6288c360b..000000000 --- a/src/parsers/smt/smtlib_solver.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtlib_solver.h - -Abstract: - - SMT based solver. - -Author: - - Nikolaj Bjorner (nbjorner) 2006-11-3. - -Revision History: - ---*/ -#ifndef SMTLIB_SOLVER_H_ -#define SMTLIB_SOLVER_H_ - -#include "parsers/smt/smtparser.h" -#include "cmd_context/context_params.h" -#include "util/lbool.h" - -class cmd_context; - -namespace smtlib { - class solver { - context_params m_params; - ast_manager m_ast_manager; - cmd_context * m_ctx; - scoped_ptr m_parser; - unsigned m_error_code; - public: - solver(); - ~solver(); - bool solve_smt(char const * benchmark_file); - bool solve_smt_string(char const * benchmark_string); - void display_statistics(); - unsigned get_error_code() const { return m_error_code; } - private: - void solve_benchmark(benchmark & benchmark); - void solve_formula(benchmark const & benchmark, expr * f); - }; -}; - -#endif diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp deleted file mode 100644 index 15f094e33..000000000 --- a/src/parsers/smt/smtparser.cpp +++ /dev/null @@ -1,2760 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtparser.cpp - -Abstract: - - SMT parser into ast. - -Author: - - Nikolaj Bjorner (nbjorner) 2006-10-4. - Leonardo de Moura (leonardo) - -Revision History: ---*/ -#include -#include -#include -#include -#include -#include "util/region.h" -#include "parsers/util/scanner.h" -#include "util/symbol.h" -#include "util/vector.h" -#include "util/symbol_table.h" -#include "parsers/smt/smtlib.h" -#include "parsers/smt/smtparser.h" -#include "ast/ast_pp.h" -#include "ast/bv_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "util/warning.h" -#include "util/error_codes.h" -#include "parsers/util/pattern_validation.h" -#include "ast/rewriter/var_subst.h" -#include "ast/well_sorted.h" -#include "util/str_hashtable.h" -#include "util/stopwatch.h" - -class id_param_info { - symbol m_string; - unsigned m_num_params; - parameter m_params[0]; -public: - id_param_info(symbol const& s, unsigned n, parameter const* p) : m_string(s), m_num_params(n) { - for (unsigned i = 0; i < n; ++i) { - new (&(m_params[i])) parameter(); - m_params[i] = p[i]; - } - } - symbol string() const { return m_string; } - parameter * params() { return m_params; } - unsigned num_params() const { return m_num_params; } -}; - -class proto_region { - ptr_vector m_rationals; - ptr_vector m_id_infos; - region m_region; -public: - proto_region() { } - - ~proto_region() { reset(); } - - rational* allocate(rational const & n) { - rational* r = alloc(rational, n); - m_rationals.push_back(r); - return r; - } - - id_param_info* allocate(vector const& params, symbol const & s) { - unsigned size = sizeof(id_param_info) + sizeof(parameter)*(params.size()); - id_param_info* r = static_cast(m_region.allocate(size)); - new (r) id_param_info(s, params.size(), params.c_ptr()); - m_id_infos.push_back(r); - return r; - } - - void* allocate(size_t s) { return m_region.allocate(s); } - - void reset() { - for (unsigned i = 0; i < m_rationals.size(); ++i) { - dealloc(m_rationals[i]); - } - for (unsigned i = 0; i < m_id_infos.size(); ++i) { - unsigned n = m_id_infos[i]->num_params(); - for (unsigned j = 0; j < n; ++j) { - m_id_infos[i]->params()[j].~parameter(); - } - } - m_rationals.reset(); - m_id_infos.reset(); - m_region.reset(); - } - -private: - -}; - -inline void * operator new(size_t s, proto_region& r) { return r.allocate(s); } -inline void * operator new[](size_t s, proto_region & r) { return r.allocate(s); } -inline void operator delete(void*, proto_region& r) {} -inline void operator delete[](void *, proto_region& r) {} - -class proto_expr { -public: - - enum kind_t { - ID, - STRING, - COMMENT, - ANNOTATION, - INT, - FLOAT, - CONS - }; -private: - - int m_kind:8; - int m_line:24; - int m_pos; - union { - id_param_info* m_id_info; - rational* m_number; - proto_expr** m_children; - }; - -public: - - symbol string() { - if (m_kind == INT || m_kind == FLOAT) { - std::string s = m_number->to_string(); - return symbol(s.c_str()); - } - if (m_kind == CONS) { - return symbol(""); - } - SASSERT(m_kind == STRING || m_kind == COMMENT || m_kind == ID || m_kind == ANNOTATION); - return m_id_info->string(); - } - - rational const& number() { - SASSERT(m_kind == INT || m_kind == FLOAT); - return *m_number; - } - - proto_expr* const* children() const { - if (m_kind == CONS) { - return m_children; - } - else { - return 0; - } - } - - int line() { return m_line; } - int pos() { return m_pos; } - kind_t kind() { return static_cast(m_kind); } - - unsigned num_params() const { - SASSERT(m_kind == ID); - return m_id_info->num_params(); - } - - parameter * params() { - SASSERT(m_kind == ID); - return m_id_info->params(); - } - - proto_expr(proto_region & region, kind_t kind, symbol const & s, vector const & params, int line, int pos): - m_kind(kind), - m_line(line), - m_pos(pos), - m_id_info(region.allocate(params, s)) { - SASSERT(kind != CONS); - SASSERT(kind != INT); - SASSERT(kind != FLOAT); - } - - proto_expr(proto_region& region, bool is_int, rational const & n, int line, int pos): - m_kind(is_int?INT:FLOAT), - m_line(line), - m_pos(pos), - m_number(region.allocate(n)) - {} - - proto_expr(proto_region& region, ptr_vector& proto_exprs, int line, int pos): - m_kind(CONS), - m_line(line), - m_pos(pos) { - // - // null terminated list of proto_expression pointers. - // - unsigned num_children = proto_exprs.size(); - m_children = new (region) proto_expr*[num_children+1]; - for (unsigned i = 0; i < num_children; ++i) { - m_children[i] = proto_exprs[i]; - } - m_children[num_children] = 0; - } - - ~proto_expr() {} - - - static proto_expr* copy(proto_region& r, proto_expr* e) { - switch(e->kind()) { - case proto_expr::CONS: { - ptr_vector args; - proto_expr* const* children = e->children(); - while (children && *children) { - args.push_back(copy(r, *children)); - ++children; - } - return new (r) proto_expr(r, args, e->line(), e->pos()); - } - case proto_expr::INT: { - return new (r) proto_expr(r, true, e->number(), e->line(), e->pos()); - } - case proto_expr::FLOAT: { - return new (r) proto_expr(r, false, e->number(), e->line(), e->pos()); - } - case proto_expr::ID: { - vector params; - for (unsigned i = 0; i < e->num_params(); ++i) { - params.push_back(e->params()[i]); - } - return new (r) proto_expr(r, e->kind(), e->string(), params, e->line(), e->pos()); - } - default: { - vector params; - return new (r) proto_expr(r, e->kind(), e->string(), params, e->line(), e->pos()); - } - } - } - -private: - - proto_expr(proto_expr const & other); - proto_expr& operator=(proto_expr const & other); -}; - - -// -// build up proto_expr tree from token stream. -// - -class proto_expr_parser { - proto_region& m_region; - scanner& m_scanner; - std::ostream& m_err; - bool m_at_eof; -public: - proto_expr_parser(proto_region& region, scanner& scanner, std::ostream& err): - m_region(region), - m_scanner(scanner), - m_err(err), - m_at_eof(false) { - } - - ~proto_expr_parser() {} - - bool parse(ptr_vector & proto_exprs, bool parse_single_expr = false) { - scanner::token token; - vector stack; - proto_expr* result = 0; - - stack.push_back(frame(PROTO_EXPRS_PRE)); - - token = m_scanner.scan(); - - if (token == scanner::EOF_TOKEN) { - proto_exprs.reset(); - return true; - } - - while (!stack.empty()) { - - if (token == scanner::EOF_TOKEN) { - break; - } - - if (token == scanner::ERROR_TOKEN) { - print_error("unexpected token"); - goto done; - } - - switch(stack.back().m_state) { - - case PROTO_EXPR: - switch (token) { - case scanner::LEFT_PAREN: - stack.back().m_state = PROTO_EXPRS_PRE; - token = m_scanner.scan(); - break; - default: - stack.back().m_state = ATOM; - break; - } - break; - - case ATOM: - SASSERT(!result); - switch(token) { - case scanner::ID_TOKEN: - result = new (m_region) proto_expr(m_region, proto_expr::ID, m_scanner.get_id(), m_scanner.get_params(), - m_scanner.get_line(), m_scanner.get_pos()); - break; - case scanner::INT_TOKEN: - result = new (m_region) proto_expr(m_region, true, m_scanner.get_number(), m_scanner.get_line(), - m_scanner.get_pos()); - break; - case scanner::FLOAT_TOKEN: - result = new (m_region) proto_expr(m_region, false, m_scanner.get_number(), m_scanner.get_line(), - m_scanner.get_pos()); - break; - case scanner::STRING_TOKEN: - result = new (m_region) proto_expr(m_region, proto_expr::STRING, m_scanner.get_id(), m_scanner.get_params(), - m_scanner.get_line(), m_scanner.get_pos()); - break; - case scanner::COMMENT_TOKEN: - result = new (m_region) proto_expr(m_region, proto_expr::COMMENT, m_scanner.get_id(), m_scanner.get_params(), - m_scanner.get_line(), m_scanner.get_pos()); - break; - case scanner::COLON: - token = m_scanner.scan(); - if (token == scanner::ID_TOKEN) { - result = new (m_region) proto_expr(m_region, proto_expr::ANNOTATION, m_scanner.get_id(), - m_scanner.get_params(), m_scanner.get_line(), m_scanner.get_pos()); - } - else { - print_error("unexpected identifier ':'"); - token = scanner::ERROR_TOKEN; - goto done; - } - break; - default: - print_error("unexpected token"); - token = scanner::ERROR_TOKEN; - goto done; - } - stack.pop_back(); - SASSERT(!stack.empty()); - stack.back().m_proto_exprs.push_back(result); - result = 0; - if (parse_single_expr && stack.size() == 1) { - goto done; - } - token = m_scanner.scan(); - break; - - case PROTO_EXPRS_PRE: - SASSERT(!result); - switch(token) { - case scanner::RIGHT_PAREN: - result = new (m_region) proto_expr(m_region, stack.back().m_proto_exprs, m_scanner.get_line(), - m_scanner.get_pos()); - stack.pop_back(); - - if (stack.empty()) { - print_error("unexpected right parenthesis"); - token = scanner::ERROR_TOKEN; - result = 0; - goto done; - } - stack.back().m_proto_exprs.push_back(result); - if (parse_single_expr && stack.size() == 1) { - goto done; - } - result = 0; - token = m_scanner.scan(); - break; - - case scanner::EOF_TOKEN: - m_at_eof = true; - break; - - case scanner::ERROR_TOKEN: - print_error("could not parse expression"); - goto done; - - default: - stack.back().m_state = PROTO_EXPRS_POST; - stack.push_back(frame(PROTO_EXPR)); - break; - } - break; - - case PROTO_EXPRS_POST: - stack.back().m_state = PROTO_EXPRS_PRE; - break; - } - } - - done: - - if (stack.size() == 1) { - for (unsigned i = 0; i < stack.back().m_proto_exprs.size(); ++i) { - proto_exprs.push_back(stack.back().m_proto_exprs[i]); - } - return true; - } - - if (stack.size() == 2) { - proto_exprs.push_back(new (m_region) proto_expr(m_region, stack.back().m_proto_exprs, m_scanner.get_line(), - m_scanner.get_pos())); - return true; - } - - print_error("unexpected nesting of parenthesis: ", stack.size()); - return false; - } - - int get_line() { - return m_scanner.get_line(); - } - - bool at_eof() const { - return m_at_eof; - } - -private: - - template - void print_error(char const* msg1, T msg2) { - m_err << "ERROR: line " << m_scanner.get_line() - << " column " << m_scanner.get_pos() << ": " - << msg1 << msg2 << "\n"; - } - - void print_error(char const* msg) { - print_error(msg, ""); - } - - // stack frame: - enum frame_state { - PROTO_EXPR, - PROTO_EXPRS_PRE, - PROTO_EXPRS_POST, - ATOM - }; - - class frame { - public: - frame_state m_state; - ptr_vector m_proto_exprs; - frame(frame_state state): - m_state(state){ - } - frame(frame const & other): - m_state(other.m_state), - m_proto_exprs(other.m_proto_exprs) { - } - private: - frame& operator=(frame const &); - }; - -}; - -using namespace smtlib; - -class idbuilder { -public: - virtual ~idbuilder() {} - virtual bool apply(expr_ref_vector const & args, expr_ref & result) = 0; -}; - -class builtin_sort_builder : public sort_builder { - ast_manager& m_manager; - family_id m_fid; - decl_kind m_kind; -public: - builtin_sort_builder(ast_manager& m, family_id fid, decl_kind k) : - m_manager(m), m_fid(fid), m_kind(k) {} - - virtual bool apply(unsigned num_params, parameter const* params, sort_ref & result) { - result = m_manager.mk_sort(m_fid, m_kind, num_params, params); - return result.get() != 0; - } -}; - -class array_sort : public builtin_sort_builder { -public: - array_sort(ast_manager& m) : - builtin_sort_builder(m, m.mk_family_id("array"), ARRAY_SORT) {} -}; - -class bv_sort : public builtin_sort_builder { -public: - bv_sort(ast_manager& m) : - builtin_sort_builder(m, m.mk_family_id("bv"), BV_SORT) {} -}; - -class user_sort : public sort_builder { - user_sort_plugin * m_plugin; - decl_kind m_kind; - symbol m_name; - unsigned m_num_args; - std::string m_error_message; -public: - user_sort(ast_manager& m, unsigned num_args, symbol name): - m_name(name), - m_num_args(num_args) { - m_plugin = m.get_user_sort_plugin(); - m_kind = m_plugin->register_name(name); - } - - ~user_sort() {} - - virtual bool apply(unsigned num_params, parameter const* params, sort_ref & result) { - if (num_params != m_num_args) { - std::ostringstream strm; - strm << "wrong number of arguments passed to " << m_name << " " - << m_num_args << " expected, but " << num_params << " given"; - m_error_message = strm.str(); - return false; - } - result = m_plugin->mk_sort(m_kind, num_params, params); - return true; - } - - virtual char const* error_message() { - return m_error_message.c_str(); - } -}; - -class smtparser : public parser { - struct builtin_op { - family_id m_family_id; - decl_kind m_kind; - builtin_op() : m_family_id(null_family_id), m_kind(0) {} - builtin_op(family_id fid, decl_kind k) : m_family_id(fid), m_kind(k) {} - }; - - class add_plugins { - - public: - add_plugins(ast_manager& m) { -#define REGISTER_PLUGIN(NAME, MK) { \ - family_id fid = m.mk_family_id(symbol(NAME)); \ - if (!m.has_plugin(fid)) { \ - m.register_plugin(fid, MK); \ - } \ - } ((void) 0) - - REGISTER_PLUGIN("arith", alloc(arith_decl_plugin)); - REGISTER_PLUGIN("bv", alloc(bv_decl_plugin)); - REGISTER_PLUGIN("array", alloc(array_decl_plugin)); - - }; - }; - - ast_manager& m_manager; - add_plugins m_plugins; - arith_util m_anum_util; - bv_util m_bvnum_util; - pattern_validator m_pattern_validator; - bool m_ignore_user_patterns; - unsigned m_binding_level; // scope level for bound vars - benchmark m_benchmark; // currently parsed benchmark - - typedef map op_map; - op_map m_builtin_ops; - op_map m_builtin_sorts; - - symbol m_let; // commonly used symbols. - symbol m_flet; - symbol m_forall; - symbol m_exists; - symbol m_lblneg; - symbol m_lblpos; - symbol m_associative; - symbol m_commutative; - symbol m_injective; - symbol m_sorts; - symbol m_funs; - symbol m_preds; - symbol m_axioms; - symbol m_notes; - symbol m_array; - symbol m_bang; - symbol m_underscore; - sort* m_int_sort; - sort* m_real_sort; - family_id m_bv_fid; - family_id m_arith_fid; - family_id m_array_fid; - family_id m_rel_fid; - func_decl * m_sk_hack; - std::ostream* m_err; - bool m_display_error_for_vs; - - -public: - - smtparser(ast_manager& m, bool ignore_user_patterns): - m_manager(m), - m_plugins(m), - m_anum_util(m), - m_bvnum_util(m), - m_pattern_validator(m), - m_ignore_user_patterns(ignore_user_patterns), - m_binding_level(0), - m_benchmark(m_manager, symbol("")), - m_let("let"), - m_flet("flet"), - m_forall("forall"), - m_exists("exists"), - m_lblneg("lblneg"), - m_lblpos("lblpos"), - m_associative("assoc"), - m_commutative("comm"), - m_injective("injective"), - m_sorts("sorts"), - m_funs("funs"), - m_preds("preds"), - m_axioms("axioms"), - m_notes("notes"), - m_array("array"), - m_bang("!"), - m_underscore("_"), - m_err(0), - m_display_error_for_vs(false) - { - family_id bfid = m_manager.get_basic_family_id(); - - add_builtin_type("bool", bfid, BOOL_SORT); - m_benchmark.get_symtable()->insert(symbol("Array"), alloc(array_sort, m)); - m_benchmark.get_symtable()->insert(symbol("BitVec"), alloc(bv_sort, m)); - - - add_builtins(bfid); - } - - ~smtparser() { - } - - void set_error_stream(std::ostream& strm) { m_err = &strm; } - - std::ostream& get_err() { return m_err?(*m_err):std::cerr; } - - bool ignore_user_patterns() const { return m_ignore_user_patterns; } - - bool parse_stream(std::istream& stream) { - proto_region region; - scanner scanner(stream, get_err(), false); - proto_expr_parser parser(region, scanner, get_err()); - return parse(parser); - } - - bool parse_file(char const * filename) { - if (filename != 0) { - std::ifstream stream(filename); - if (!stream) { - get_err() << "ERROR: could not open file '" << filename << "'.\n"; - return false; - } - return parse_stream(stream); - } - else { - return parse_stream(std::cin); - } - } - - bool parse_string(char const * str) { - std::string s = str; - std::istringstream is(s); - return parse_stream(is); - } - - void add_builtin_op(char const * s, family_id fid, decl_kind k) { - m_builtin_ops.insert(symbol(s), builtin_op(fid, k)); - } - - void add_builtin_type(char const * s, family_id fid, decl_kind k) { - m_builtin_sorts.insert(symbol(s), builtin_op(fid, k)); - } - - void initialize_smtlib() { - smtlib::symtable* table = m_benchmark.get_symtable(); - - symbol arith("arith"); - family_id afid = m_manager.mk_family_id(arith); - m_arith_fid = afid; - - add_builtin_type("Int", afid, INT_SORT); - add_builtin_type("Real", afid, REAL_SORT); - add_builtin_type("Bool", m_manager.get_basic_family_id(), BOOL_SORT); - - m_int_sort = m_manager.mk_sort(m_arith_fid, INT_SORT); - m_real_sort = m_manager.mk_sort(m_arith_fid, REAL_SORT); - - add_builtins(afid); - - symbol bv("bv"); - family_id bfid = m_manager.mk_family_id(bv); - m_bv_fid = bfid; - - add_builtins(bfid); - - add_builtin_type("BitVec", bfid, BV_SORT); - - symbol array("array"); - afid = m_manager.mk_family_id(array); - m_array_fid = afid; - - add_builtins(afid); - - sort* a1, *a2; - func_decl* store1, *sel1, *store2, *sel2; - - // Array - parameter params0[2] = { parameter(m_int_sort), parameter(m_int_sort) }; - a1 = m_manager.mk_sort(afid, ARRAY_SORT, 2, params0); - table->insert(symbol("Array"), a1); - parameter param0(a1); - sort * args0[3] = { a1, m_int_sort, m_int_sort }; - store1 = m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, args0); - table->insert(symbol("store"), store1); - sel1 = m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, args0); - table->insert(symbol("select"), sel1); - - // Array1 - parameter params1[2] = { parameter(m_int_sort), parameter(m_real_sort) }; - a1 = m_manager.mk_sort(afid, ARRAY_SORT, 2, params1); - table->insert(symbol("Array1"), a1); - parameter param1(a1); - sort * args1[3] = { a1, m_int_sort, m_real_sort }; - store1 = m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, args1); - table->insert(symbol("store"), store1); - sel1 = m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, args1); - table->insert(symbol("select"), sel1); - - // Array2 - parameter params2[2] = { parameter(m_int_sort), parameter(a1) }; - a2 = m_manager.mk_sort(afid, ARRAY_SORT, 2, params2); - table->insert(symbol("Array2"), a2); - parameter param2(a2); - sort * args2[3] = { a2, m_int_sort, a1 }; - store2 = m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, args2); - table->insert(symbol("store"), store2); - sel2 = m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, args2); - table->insert(symbol("select"), sel2); - - m_benchmark.declare_sort(symbol("U")); - - sort * bool_sort = m_manager.mk_bool_sort(); - m_sk_hack = m_manager.mk_func_decl(symbol("sk_hack"), 1, &bool_sort, bool_sort); - table->insert(symbol("sk_hack"), m_sk_hack); - } - - - void add_builtins(family_id fid) { - decl_plugin * plugin = m_manager.get_plugin(fid); - SASSERT(plugin); - svector op_names; - plugin->get_op_names(op_names); - for (unsigned i = 0; i < op_names.size(); ++i) { - add_builtin_op(op_names[i].m_name.bare_str(), fid, op_names[i].m_kind); - } - } - - smtlib::benchmark* get_benchmark() { return &m_benchmark; } - -private: - - - bool parse(proto_expr_parser& parser) { - symbol benchmark("benchmark"); - symbol name(""); - proto_expr* const* rest = 0; - ptr_vector proto_exprs; - bool result = parser.parse(proto_exprs); - proto_expr* proto_expr = 0; - - if (!result) { - get_err() << "ERROR: parse error at line " << parser.get_line() << ".\n"; - } - - for (unsigned i = 0; result && i < proto_exprs.size(); ++i) { - - proto_expr = proto_exprs[i]; - - if (match_cons(proto_expr, benchmark, name, rest)) { - result = make_benchmark(name, rest); - } - else if (proto_expr && proto_expr->kind() != proto_expr::COMMENT) { - set_error("could not match expression to benchmark ", proto_expr); - } - else { - // proto_expr->kind() == proto_expr::COMMENT. - } - } - return result; - } - - void error_prefix(proto_expr* e) { - if (m_display_error_for_vs) { - if (e) { - get_err() << "Z3(" << e->line() << "," << e->pos() << "): ERROR: "; - } - } - else { - get_err() << "ERROR: "; - if (e) { - get_err() << "line " << e->line() << " column " << e->pos() << ": "; - } - } - } - - void set_error(char const * str, proto_expr* e) { - error_prefix(e); - if (e->kind() == proto_expr::ID) { - get_err() << str << " '" << e->string() << "'.\n"; - } - else { - get_err() << str << ".\n"; - } - } - - template - void set_error(T1 str1, T2 str2, proto_expr* e) { - error_prefix(e); - get_err() << str1 << " " << str2 << ".\n"; - } - - template - void set_error(T1 str1, T2 str2, T3 str3, proto_expr* e) { - error_prefix(e); - get_err() << str1 << str2 << str3 << ".\n"; - } - - bool match_cons(proto_expr * e, symbol const & sym, symbol & name, proto_expr* const*& proto_exprs) { - if (e && - e->kind() == proto_expr::CONS && - e->children() && - e->children()[0] && - e->children()[0]->string() == sym && - e->children()[1]) { - proto_exprs = e->children() + 2; - name = e->children()[1]->string(); - return true; - } - - return false; - } - - bool make_benchmark(symbol & name, proto_expr * const* proto_exprs) { - symbol extrasorts("extrasorts"); - symbol extrafuns("extrafuns"); - symbol extrapreds("extrapreds"); - symbol assumption("assumption"); - symbol assumption_core("assumption-core"); - symbol define_sorts_sym("define_sorts"); - symbol logic("logic"); - symbol formula("formula"); - symbol status("status"); - symbol sat("sat"); - symbol unsat("unsat"); - symbol unknown("unknown"); - symbol empty(""); - symbol source("source"); - symbol difficulty("difficulty"); - symbol category("category"); - bool success = true; - - push_benchmark(name); - - while (proto_exprs && *proto_exprs) { - proto_expr* e = *proto_exprs; - ++proto_exprs; - proto_expr* e1 = *proto_exprs; - - if (logic == e->string() && e1) { - name = e1->string(); - m_benchmark.set_logic(name); - - set_default_num_sort(name); - - if (name == symbol("QF_AX")) { - // Hack for supporting new QF_AX theory... - sort * index = m_manager.mk_uninterpreted_sort(symbol("Index")); - sort * element = m_manager.mk_uninterpreted_sort(symbol("Element")); - parameter params[2] = { parameter(index), parameter(element) }; - sort * array = m_manager.mk_sort(m_array_fid, ARRAY_SORT, 2, params); - smtlib::symtable* table = m_benchmark.get_symtable(); - table->insert(symbol("Index"), index); - table->insert(symbol("Element"), element); - // overwrite Array definition... - table->insert(symbol("Array"), array); - sort * args[3] = { array, index, element }; - func_decl * store = m_manager.mk_func_decl(m_array_fid, OP_STORE, 0, 0, 3, args); - table->insert(symbol("store"), store); - func_decl * sel = m_manager.mk_func_decl(m_array_fid, OP_SELECT, 0, 0, 2, args); - table->insert(symbol("select"), sel); - } - - ++proto_exprs; - continue; - } - - if (assumption == e->string() && e1) { - expr_ref t(m_manager); - if (!make_expression(e1, t) || - !push_assumption(t.get())) { - return false; - } - ++proto_exprs; - continue; - } - - if (assumption_core == e->string() && e1) { - expr_ref t(m_manager); - if (!make_expression(e1, t)) - return false; - m_benchmark.add_assumption(t.get()); - ++proto_exprs; - continue; - } - - if (define_sorts_sym == e->string() && e1) { - if (!define_sorts(e1)) { - return false; - } - ++proto_exprs; - continue; - } - - if (formula == e->string() && e1) { - expr_ref t(m_manager); - if (!make_expression(e1, t) || - !push_formula(t.get())) { - return false; - } - ++proto_exprs; - continue; - } - - if (status == e->string() && e1) { - if (sat == e1->string()) { - if (!push_status(smtlib::benchmark::SAT)) { - set_error("could not push status ", e1->string(),e1); - return false; - } - } - else if (unsat == e1->string()) { - if (!push_status(smtlib::benchmark::UNSAT)) { - set_error("could not push status ", e1->string(),e1); - return false; - } - } - else if (unknown == e1->string()) { - if (!push_status(smtlib::benchmark::UNKNOWN)) { - set_error("could not push status ", e1->string(),e1); - return false; - } - } - else { - set_error("could not recognize status ", e1->string(),e1); - return false; - } - ++proto_exprs; - continue; - } - - if (extrasorts == e->string() && e1) { - if (!declare_sorts(e1)) { - return false; - } - ++proto_exprs; - continue; - } - if (extrafuns == e->string() && e1) { - if (!declare_funs(e1)) { - return false; - } - ++proto_exprs; - continue; - } - if (extrapreds == e->string() && e1) { - if (!declare_preds(e1)) { - return false; - } - ++proto_exprs; - continue; - } - if (m_notes == e->string() && e1) { - ++proto_exprs; - continue; - } - - if ((source == e->string() || difficulty == e->string() || category == e->string()) && e1) { - ++proto_exprs; - continue; - } - - if (e->string() != empty) { - set_error("ignoring unknown attribute '", e->string().bare_str(), "'", e); - if (e1) { - ++proto_exprs; - } - // do not fail. - // success = false; - continue; - } - - TRACE("smtparser", - tout << "skipping: " << e->string() << " " << - e->line() << " " << - e->pos() << ".\n";); - continue; - } - return success; - } - - bool is_id_token(proto_expr* expr) { - return - expr && - (expr->kind() == proto_expr::ID || - expr->kind() == proto_expr::STRING || - expr->kind() == proto_expr::ANNOTATION); - } - - bool check_id(proto_expr* e) { - return is_id_token(e); - } - - bool make_expression(proto_expr * e, expr_ref & result) { - m_binding_level = 0; - symbol_table local_scope; - return make_expression(local_scope, e, result); - } - - bool make_func_decl(proto_expr* e, func_decl_ref& result) { - func_decl* f; - if (m_benchmark.get_symtable()->find1(e->string(), f)) { - result = f; - return true; - } - else { - return false; - } - } - - bool make_bool_expression(symbol_table& local_scope, proto_expr * e, expr_ref & result) { - if (!make_expression(local_scope, e, result)) { - return false; - } - if (!m_manager.is_bool(result)) { - set_error("expecting Boolean expression", e); - return false; - } - return true; - } - - bool make_bool_expressions(symbol_table& local_scope, proto_expr * const* chs, expr_ref_vector & exprs) { - while (chs && *chs) { - expr_ref result(m_manager); - m_binding_level = 0; - if (!make_bool_expression(local_scope, *chs, result)) { - return false; - } - exprs.push_back(result); - ++chs; - } - return true; - } - - bool make_expression(symbol_table& local_scope, proto_expr * e, expr_ref & result) { - // - // Walk proto_expr by using the zipper. - // That is, maintain a stack of what's - // . left - already processed. - // . right - to be processed. - // . up - above the processed node. - // - - region region; - - expr_ref_vector * left = alloc(expr_ref_vector, m_manager); - proto_expr* const* right = 0; - ptr_vector up; - proto_expr* current = e; - bool success = false; - idbuilder* builder = 0; - - while (true) { - - if (!current && right && *right) { - // - // pull the current from right. - // - current = *right; - ++right; - } - - if (!current && up.empty()) { - // - // we are done. - // - if (left->size() == 0) { - // set_error(); - set_error("there are no expressions to return", e); - goto cleanup; - } - if (left->size() != 1) { - set_error("there are too many expressions to return", e); - goto cleanup; - } - result = left->back(); - success = true; - goto cleanup; - } - - if (!current && !up.empty()) { - // - // There is nothing more to process at this level. - // - // Apply the operator on the stack to the - // current 'left' vector. - // Adjust the stack by popping the left and right - // work-lists. - // - expr_ref term(m_manager); - parse_frame* above = up.back(); - // symbol sym = above->get_proto_expr()->string(); - - if (above->make_term()) { - if (!above->make_term()->apply(*left, term)) { - set_error("Could not create application", - above->get_proto_expr()); - success = false; - goto cleanup; - } - } - else if (!make_app(above->get_proto_expr(), *left, term)) { - success = false; - goto cleanup; - } - dealloc(left); - left = above->detach_left(); - left->push_back(term.get()); - right = above->right(); - m_binding_level = above->binding_level(); - up.pop_back(); - continue; - } - - while (current && - current->kind() == proto_expr::CONS && - current->children() && - current->children()[0] && - !current->children()[1]) { - current = current->children()[0]; - } - - switch(current->kind()) { - - case proto_expr::ANNOTATION: - // ignore - current = 0; - break; - - case proto_expr::ID: { - symbol const& id = current->string(); - expr_ref term(m_manager); - expr * const_term = 0; - bool ok = true; - - if (local_scope.find(id, builder)) { - expr_ref_vector tmp(m_manager); - if (!builder->apply(tmp, term)) { - set_error("identifier supplied with the wrong number of arguments ", id, current); - goto cleanup; - - } - } - else if (m_benchmark.get_const(id, const_term)) { - // found. - term = const_term; - } - else if (is_builtin_const(id, current, current->num_params(), current->params(), ok, term)) { - if (!ok) goto cleanup; - } - else if (is_bvconst(id, current->num_params(), current->params(), term)) { - // found - } - else { - set_error("could not locate id ", id, current); - goto cleanup; - } - - left->push_back(term.get()); - current = 0; - break; - } - - case proto_expr::STRING: - // - // Ignore strings. - // - current = 0; - break; - - case proto_expr::COMMENT: - // - // Ignore comments. - // - current = 0; - break; - - case proto_expr::INT: - - left->push_back(mk_number(current->number(), true)); - current = 0; - break; - - case proto_expr::FLOAT: - left->push_back(mk_number(current->number(), false)); - current = 0; - break; - - case proto_expr::CONS: - - if (!current->children() || - !current->children()[0]) { - set_error("cons does not have children", current); - current = 0; - goto cleanup; - } - - // - // expect the head to be a symbol - // which can be used to build a term of - // the subterms. - // - - symbol const& head_symbol = current->children()[0]->string(); - - if (head_symbol == m_underscore) { - - expr_ref term(m_manager); - - proto_expr * const* chs = current->children() + 1; - symbol const& id = chs[0]->string(); - sort_ref_vector sorts(m_manager); - vector params; - bool ok = true; - if (!parse_params(chs+1, params, sorts)) { - goto cleanup; - } - if (is_builtin_const(id, current, params.size(), params.c_ptr(), ok, term)) { - if (!ok) goto cleanup; - } - else if (is_bvconst(id, params.size(), params.c_ptr(), term)) { - // ok - } - else { - set_error("Could not parse _ term", current); - goto cleanup; - } - left->push_back(term.get()); - current = 0; - break; - } - - if ((head_symbol == m_let) || - (head_symbol == m_flet)) { - - if (!current->children()[1] || - !current->children()[2]) { - set_error("let does not have two arguments", current); - goto cleanup; - } - - proto_expr * let_binding = current->children()[1]; - proto_expr * const* let_body = current->children()+2; - - // - // Collect bound variables and definitions for the bound variables - // into vectors 'vars' and 'bound'. - // - svector vars; - ptr_vector bound_vec; - if (is_binary_let_binding(let_binding)) { - vars.push_back(let_binding->children()[0]->string()); - bound_vec.push_back(let_binding->children()[1]); - } - else { - proto_expr* const* children = let_binding->children(); - if (!children) { - set_error("let binding does not have two arguments", let_binding); - goto cleanup; - } - while (*children) { - proto_expr* ch = *children; - if (!is_binary_let_binding(ch)) { - set_error("let binding does not have two arguments", ch); - goto cleanup; - } - vars.push_back(ch->children()[0]->string()); - bound_vec.push_back(ch->children()[1]); - ++children; - } - } - bound_vec.push_back(0); - - proto_expr** bound = new (region) proto_expr*[bound_vec.size()]; - for (unsigned i = 0; i < bound_vec.size(); ++i) { - bound[i] = bound_vec[i]; - } - - // - // Let's justify the transformation that - // pushes push_let and pop_let on the stack. - // and how it processes the let declaration. - // - // walk up left ((let ((v1 x1) (v2 x2)) z)::right) - // - // = - // - // walk (up::(pop_let(),left,right)::(bind(v1,v2),[],[z])) [] [x1;x2] - // - // = (* assume x1 -> y1, x2 -> y2 *) - // - // walk (up::(pop_let(),left,right)::(bind(v1,v2),[],[z])) [y1;y2] [] - // - // = (* apply binding *) - // - // walk (up::(pop_let(),left,right)) [] [z] - // - // = (* assume z -> u *) - // - // walk up {left::u] right - // - // so if pop_let(v) [a,b] has the effect of removing v from the environment - // and projecting the second element "b", we obtain the effect of a let-binding. - // - - expr_ref_vector * pinned = alloc(expr_ref_vector, m_manager); - pop_let * popl = new (region) pop_let(local_scope, pinned); - up.push_back(new (region) parse_frame(let_binding, popl, left, right, m_binding_level)); - - - push_let_and * pushl = new (region) push_let_and(this, region, local_scope, pinned, vars.size(), vars.c_ptr()); - expr_ref_vector * tmp = alloc(expr_ref_vector, m_manager); - up.push_back(new (region) parse_frame(let_binding, pushl, tmp, let_body, m_binding_level)); - - - left = alloc(expr_ref_vector, m_manager); - right = bound; - current = 0; - break; - } - - if (head_symbol == m_lblneg || - head_symbol == m_lblpos) { - if (!current->children()[1] || - !current->children()[2]) { - set_error("labels require two arguments", current); - goto cleanup; - } - - bool is_pos = head_symbol == m_lblpos; - idbuilder* lbl = new (region) build_label(this, is_pos, current->children()[1]); - - up.push_back(new (region) parse_frame(current, lbl, left, right, m_binding_level)); - - // - // process the body. - // - left = alloc(expr_ref_vector, m_manager); - right = 0; - current = current->children()[2]; - break; - } - - if (head_symbol == m_bang) { - proto_expr* const* children = current->children(); - proto_expr* body = children[1]; - proto_expr* lblname = 0; - bool is_pos = false; - - children += 2; - - while (children[0] && - children[0]->kind() == proto_expr::ANNOTATION && - children[1]) { - symbol id = children[0]->string(); - - if ((id == m_lblneg) || - (id == m_lblpos)) { - is_pos = id == m_lblpos; - lblname = children[1]; - } - - children += 2; - } - - if (lblname) { - idbuilder* lbl = new (region) build_label(this, is_pos, lblname); - up.push_back(new (region) parse_frame(current, lbl, left, right, m_binding_level)); - left = alloc(expr_ref_vector, m_manager); - right = 0; - } - - // - // process the body. - // - current = body; - break; - } - - if ((head_symbol == m_forall) || - (head_symbol == m_exists)) { - - expr_ref_buffer patterns(m_manager); - expr_ref_buffer no_patterns(m_manager); - sort_ref_buffer sorts(m_manager); - svector vars; - int weight = 1; - - proto_expr* const* children = current->children(); - proto_expr* body = 0; - - ++children; - - if (!children[0] || !children[1]) { - set_error("quantifier should have at least two arguments", current); - goto cleanup; - } - - // - // restore 'left' and 'right' working set and m_binding_level. - // - up.push_back(new (region) parse_frame(current, new (region) identity(), left, right, m_binding_level)); - left = alloc(expr_ref_vector, m_manager); - - // - // declare the bound variables. - // - - local_scope.begin_scope(); - - while (children[0] && children[1] && - (children[1]->kind() != proto_expr::ANNOTATION)) { - - if (!parse_bound(local_scope, region, *children, vars, sorts)) { - goto cleanup; - } - ++children; - } - - body = children[0]; - - if (is_annotated_cons(body)) { - children = body->children()+1; - body = body->children()[1]; - } - - ++children; - - symbol qid = symbol(current->line()); - symbol skid = symbol(); - - read_patterns(vars.size(), local_scope, children, patterns, no_patterns, weight, qid, skid); - - // - // push a parse_frame to undo the scope of the quantifier. - // - - SASSERT(sorts.size() > 0); - - idbuilder* pop_q = new (region) pop_quantifier(this, (head_symbol == m_forall), weight, qid, skid, patterns, no_patterns, sorts, vars, local_scope); - - expr_ref_vector * empty_v = alloc(expr_ref_vector, m_manager); - up.push_back(new (region) parse_frame(current, pop_q, empty_v, 0, m_binding_level)); - - // - // process the body. - // - right = 0; - current = body; - break; - } - - if (is_underscore_op(region, current->children()[0], builder)) { - up.push_back(new (region) parse_frame(current, builder, left, right, m_binding_level)); - } - else if (local_scope.find(head_symbol, builder)) { - up.push_back(new (region) parse_frame(current, builder, left, right, m_binding_level)); - } - else { - up.push_back(new (region) parse_frame(current->children()[0], left, right, m_binding_level)); - } - left = alloc(expr_ref_vector, m_manager); - right = current->children() + 1; - current = 0; - break; - } - } - - cleanup: - - if (success && !is_well_sorted(m_manager, result)) { - set_error("expression is not well sorted", e); - success = false; - } - - dealloc(left); - while (!up.empty()) { - dealloc(up.back()->detach_left()); - up.pop_back(); - } - return success; - } - - bool read_patterns(unsigned num_bindings, symbol_table & local_scope, proto_expr * const * & children, - expr_ref_buffer & patterns, expr_ref_buffer & no_patterns, int& weight, symbol& qid, symbol& skid) { - proto_region region; - while (children[0] && - children[0]->kind() == proto_expr::ANNOTATION && - children[1]) { - - if (children[0]->string() == symbol("qid") || - children[0]->string() == symbol("named")) { - qid = children[1]->string(); - children += 2; - continue; - } - - if (children[0]->string() == symbol("skolemid")) { - skid = children[1]->string(); - children += 2; - continue; - } - - ptr_vector proto_exprs; - - if (children[1]->kind() == proto_expr::COMMENT) { - std::string s = children[1]->string().str(); - std::istringstream stream(s); - scanner scanner(stream, get_err(), false); - proto_expr_parser parser(region, scanner, get_err()); - - if (!parser.parse(proto_exprs)) { - set_error("could not parse expression", children[1]); - return false; - } - } else if (children[1]->kind() == proto_expr::CONS) { - for (proto_expr* const* pexpr = children[1]->children(); *pexpr; pexpr++) - proto_exprs.push_back(*pexpr); - } else { - proto_exprs.push_back(children[1]); - } - - expr_ref_buffer ts(m_manager); - for (unsigned i = 0; i < proto_exprs.size(); ++i) { - expr_ref t(m_manager); - if (!make_expression(local_scope, proto_exprs[i], t)) { - return false; - } - ts.push_back(t.get()); - } - - if (children[0]->string() == symbol("pat") || - children[0]->string() == symbol("pats") || - children[0]->string() == symbol("pattern")) { - for (unsigned i = 0; i < ts.size(); ++i) { - if (!is_app(ts[i])) { - set_error("invalid pattern", children[0]); - return false; - } - } - expr_ref p(m_manager); - p = m_manager.mk_pattern(ts.size(), (app*const*)(ts.c_ptr())); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { - set_error("invalid pattern", children[0]); - return false; - } - patterns.push_back(p); - } - else if (children[0]->string() == symbol("ex_act") && ts.size() == 1) { - app_ref sk_hack(m_manager); - sk_hack = m_manager.mk_app(m_sk_hack, 1, ts.c_ptr()); - app * sk_hackp = sk_hack.get(); - expr_ref p(m_manager); - p = m_manager.mk_pattern(1, &sk_hackp); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { - set_error("invalid pattern", children[0]); - return false; - } - patterns.push_back(p); - } - else if ((children[0]->string() == symbol("nopat") || - children[0]->string() == symbol("no-pattern")) - && ts.size() == 1) { - no_patterns.push_back(ts[0]); - } - else if (children[0]->string() == symbol("weight") && ts.size() == 1 && - proto_exprs[0]->kind() == proto_expr::INT && - proto_exprs[0]->number().is_unsigned()) { - weight = proto_exprs[0]->number().get_unsigned(); - } - else { - // TODO: this should be a warning, perferably once per unknown kind of annotation - set_error("could not understand annotation '", - children[0]->string().bare_str(), "'", children[0]); - } - - children += 2; - } - return true; - } - - void set_default_num_sort(symbol const& name) { - if (name == symbol("QF_RDL") || - name == symbol("QF_LRA") || - name == symbol("LRA") || - name == symbol("RDL") || - name == symbol("QF_NRA") || - name == symbol("QF_UFNRA") || - name == symbol("QF_UFLRA")) { - m_int_sort = m_real_sort; - } - } - - bool get_sort(theory* th, char const * s, sort_ref& sort) { - return make_sort(symbol(s), 0, 0, sort); - } - - - bool make_sort(symbol const & id, unsigned num_params, parameter const* params, sort_ref& s) { - builtin_op info; - if (m_builtin_sorts.find(id, info)) { - s = m_manager.mk_sort(info.m_family_id, info.m_kind, num_params, params); - return true; - } - - if (num_params == 2 && symbol("Array") == id) { - // Old HACK to accomodate bit-vector arrays. - - if (!params[0].is_int()) { - throw default_exception("Non-integer parameter to array"); - return false; - } - if (!params[1].is_int()) { - throw default_exception("Non-integer parameter to array"); - return false; - } - parameter bv_params0[1] = { parameter(params[0].get_int()) }; - parameter bv_params1[1] = { parameter(params[1].get_int()) }; - - sort * t1 = m_manager.mk_sort(m_bv_fid, BV_SORT, 1, bv_params0); - sort * t2 = m_manager.mk_sort(m_bv_fid, BV_SORT, 1, bv_params1); - parameter params[2] = { parameter(t1), parameter(t2) }; - s = m_manager.mk_sort(m_array_fid, ARRAY_SORT, 2, params); - return true; - } - - sort* srt = 0; - if (m_benchmark.get_sort(id, srt)) { - s = srt; - return true; - } - return false; - } - - bool make_sort(proto_expr * e, sort_ref& s) { - SASSERT(can_be_sort(e)); - symtable& env = *m_benchmark.get_symtable(); - sort_builder* mk_sort; - switch(e->kind()) { - case proto_expr::ID: { - if (make_sort(e->string(), e->num_params(), e->params(), s)) { - return true; - } - if (env.lookup(e->string(), mk_sort)) { - if (!mk_sort->apply(e->num_params(), e->params(), s)) { - set_error(mk_sort->error_message(), e); - return false; - } - return true; - } - set_error("could not find sort ", e); - return false; - } - case proto_expr::CONS: { - if (!can_be_sort(e)) { - set_error("expression cannot be a sort", e); - return false; - } - proto_expr *const* chs = e->children(); - if (is_underscore(e)) { - ++chs; - } - symbol name = (*chs)->string(); - if (!env.lookup(name, mk_sort)) { - set_error("could not find sort symbol '", name.str(), "'", e); - return false; - } - sort_ref_vector sorts(m_manager); - vector params; - if (!parse_params(chs+1, params, sorts)) { - return false; - } - - if (!mk_sort->apply(params.size(), params.c_ptr(), s)) { - set_error(mk_sort->error_message(), e); - return false; - } - return true; - } - default: - set_error("could not create sort ", e); - return false; - } - } - - bool parse_params(proto_expr* const* chs,vector& params, sort_ref_vector& sorts) { - while (*chs) { - if ((*chs)->kind() == proto_expr::INT) { - rational const& num = (*chs)->number(); - if (num.is_unsigned()) { - params.push_back(parameter(num.get_unsigned())); - } - else { - params.push_back(parameter(num)); - } - } - else { - sort_ref s1(m_manager); - if (!make_sort(*chs, s1)) { - return false; - } - sorts.push_back(s1); - params.push_back(parameter((ast*)s1.get())); - } - ++chs; - } - return true; - } - - bool parse_bound( - symbol_table& local_scope, - region& region, - proto_expr* bound, - svector& vars, - sort_ref_buffer& sorts - ) - { - if (is_cons_list(bound)) { - proto_expr *const* children = bound->children(); - while (*children) { - if (!parse_bound(local_scope, region, *children, vars, sorts)) { - return false; - } - ++children; - } - return true; - } - if (!can_be_sorted_var(bound)) { - set_error("bound variable should contain a list of pairs", bound); - return false; - } - proto_expr* var = bound->children()[0]; - proto_expr* sort_proto_expr = bound->children()[1]; - - sort_ref sort(m_manager); - if (!make_sort(sort_proto_expr, sort)) { - return false; - } - sorts.push_back(sort); - vars.push_back(var->string()); - - local_scope.insert( - var->string(), - new (region) bound_var(this, sort) - ); - - ++m_binding_level; - - return true; - } - - bool can_be_sort(proto_expr* e) { - if (e && e->kind() == proto_expr::ID) { - return true; - } - if (is_underscore(e)) { - return true; - } - - if (e && - e->kind() == proto_expr::CONS && - e->children() && - e->children()[0] && - e->children()[1]) { - proto_expr* const* ch = e->children(); - while(*ch) { - if (!can_be_sort(*ch)) { - return false; - } - ++ch; - } - return true; - } - return false; - } - - bool declare_sorts(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - proto_expr* ch = *children; - switch(ch->kind()) { - - case proto_expr::ID: - m_benchmark.declare_sort(ch->string()); - break; - - case proto_expr::CONS: - // - // The declaration of type constructors - // consists of an identifier together with - // a number indicating the arity of the - // constructor. - // - if (ch->children() && - ch->children()[0] && - ch->children()[0]->kind() == proto_expr::ID && - ch->children()[1] && - ch->children()[1]->kind() == proto_expr::INT) { - - // unsigned num = (unsigned) ch->children()[1]->number().get_uint64(); - m_benchmark.declare_sort(ch->children()[0]->string()); - } - break; - - case proto_expr::ANNOTATION: - break; - - default: - set_error("unexpected argument to sorts",ch); - return false; - } - ++children; - } - return true; - } - - bool define_sorts(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - if (!define_sort(*children)) { - return false; - } - ++children; - } - return true; - } - - bool define_sort(proto_expr* e) { - proto_expr* const * children = e->children(); - sort_ref_buffer domain(m_manager); - - // - // First element in list must be an identifier. - // there should be just two elements. - // - if (!children || - !children[0] || - !(children[0]->kind() == proto_expr::ID) || - !children[1] || - children[2]) { - set_error("unexpected arguments to function declaration", e); - return false; - } - symbol name = children[0]->string(); - sort_ref s(m_manager); - if (!can_be_sort(children[1]) || - !make_sort(children[1], s)) { - set_error("unexpected arguments to function declaration", e); - return false; - } - - m_benchmark.get_symtable()->insert(name, s); - - return true; - } - - bool declare_funs(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - if (!declare_fun(*children)) { - return false; - } - ++children; - } - return true; - } - class define_sort_cls : public sort_builder { - smtparser& m_parser; - proto_region m_region; - proto_expr* m_expr; - svector m_params; - symbol m_name; - std::string m_error_message; - - public: - define_sort_cls(smtparser& p, symbol const& name, proto_expr* e, unsigned num_params, symbol* params) : - m_parser(p), - m_name(name) { - for (unsigned i = 0; i < num_params; ++i) { - m_params.push_back(params[i]); - } - m_expr = proto_expr::copy(m_region, e); - } - - virtual bool apply(unsigned num_params, parameter const* params, sort_ref & result) { - smtlib::symtable * symtable = m_parser.m_benchmark.get_symtable(); - if (m_params.size() != num_params) { - std::ostringstream strm; - strm << "wrong number of arguments passed to " << m_name << " " - << m_params.size() << " expected, but " << num_params << " given"; - m_error_message = strm.str(); - return false; - } - for (unsigned i = 0; i < num_params; ++i) { - parameter p(params[i]); - if (!p.is_ast() || !is_sort(p.get_ast())) { - symtable->pop_sorts(i); - std::ostringstream strm; - strm << "argument " << i << " is not a sort"; - m_error_message = strm.str(); - return false; - } - symtable->push_sort(m_params[i], to_sort(p.get_ast())); - } - bool success = m_parser.make_sort(m_expr, result); - - symtable->pop_sorts(num_params); - return success; - } - - virtual char const* error_message() { - return m_error_message.c_str(); - } - - }; - - // (define-sort name (*) ) - bool define_sort(proto_expr* id, proto_expr* sorts, proto_expr* srt) { - symbol name = id->string(); - proto_expr* const * children = sorts->children(); - svector names; - - if (!children) { - set_error("Sort definition expects a list of sort symbols",id); - return false; - } - - while (children[0]) { - id = children[0]; - if(id->kind() != proto_expr::ID) { - set_error("unexpected argument, expected ID", id); - return false; - } - names.push_back(id->string()); - ++children; - } - - m_benchmark.get_symtable()->insert(name, alloc(define_sort_cls, *this, name, srt, names.size(), names.c_ptr())); - return true; - } - - bool declare_fun(proto_expr* id, proto_expr* sorts, proto_expr* srt) { - proto_expr* const * children = sorts?sorts->children():0; - sort_ref_buffer domain(m_manager); - symbol name = id->string(); - - if (sorts && !children) { - set_error("Function declaration expects a list of sorts", id); - return false; - } - // - // parse domain. - // - while (sorts && children[0]) { - sort_ref s(m_manager); - if (!make_sort(children[0], s)) { - return false; - } - domain.push_back(s); - ++children; - } - - sort_ref range(m_manager); - if (!make_sort(srt, range)) { - return false; - } - bool is_associative = false; - bool is_commutative = false; - bool is_injective = false; - m_benchmark.declare_func(name, domain, range, is_associative, is_commutative, is_injective); - return true; - } - - bool declare_fun(proto_expr* e) { - proto_expr* const * children = e->children(); - sort_ref_buffer domain(m_manager); - // - // Skip declaration of numbers. - // - if (children && - children[0] && - children[0]->kind() == proto_expr::INT) { - return true; - } - - // - // First element in list must be an identifier. - // - if (!children || - !children[0] || - !(children[0]->kind() == proto_expr::ID)) { - set_error("unexpected arguments to function declaration", e); - return false; - } - - symbol name = children[0]->string(); - - ++children; - - - if (!can_be_sort(children[0])) { - set_error("unexpected arguments to function declaration", e); - return false; - } - - // - // parse domain. - // - while (can_be_sort(children[1])) { - sort_ref s(m_manager); - if (!make_sort(children[0], s)) { - return false; - } - domain.push_back(s); - ++children; - } - - // - // parse range. - // - SASSERT(can_be_sort(children[0])); - - sort_ref range(m_manager); - if (!make_sort(children[0], range)) { - return false; - } - ++children; - - // - // parse attributes. - // - bool is_associative = false; - bool is_commutative = false; - bool is_injective = false; - - while(children[0] && children[0]->kind() == proto_expr::ANNOTATION) { - - if (m_associative == children[0]->string()) { - is_associative = true; - } - else if (m_commutative == children[0]->string()) { - is_commutative = true; - } - else if (m_injective == children[0]->string()) { - is_injective = true; - } - ++children; - } - - m_benchmark.declare_func(name, domain, range, is_associative, is_commutative, is_injective); - - return true; - } - - bool declare_preds(proto_expr* e) { - proto_expr* const * children = e->children(); - - while (children && *children) { - if (!declare_pred(*children)) { - return false; - } - ++children; - } - return true; - } - - - bool declare_pred(proto_expr* e) { - proto_expr* const * children = e->children(); - if (!children || !children[0] || !(children[0]->kind() == proto_expr::ID)) { - set_error("unexpected arguments to predicate declaration", e); - return false; - } - symbol const & name = children[0]->string(); - sort_ref_buffer domain(m_manager); - sort * bool_sort = m_manager.mk_bool_sort(); - - ++children; - - while (can_be_sort(children[0])) { - sort_ref s(m_manager); - if (!make_sort(children[0], s)) { - return false; - } - domain.push_back(s); - ++children; - } - - m_benchmark.declare_func(name, domain, bool_sort, false, false, false); - - return true; - } - - bool can_be_sorted_var(proto_expr* e) { - return - e && - (e->kind() == proto_expr::CONS) && - e->children() && - e->children()[0] && - (e->children()[0]->kind() == proto_expr::ID) && - can_be_sort(e->children()[1]); - } - - bool is_cons_list(proto_expr* e) { - return - e && - (e->kind() == proto_expr::CONS) && - e->children() && - e->children()[0] && - e->children()[0]->kind() == proto_expr::CONS; - } - - bool is_prefixed(proto_expr* e, symbol const& s) { - return - e && - (e->kind() == proto_expr::CONS) && - e->children() && - e->children()[0] && - e->children()[1] && - e->children()[0]->string() == s; - - } - - bool is_underscore(proto_expr* e) { - return - is_prefixed(e, m_underscore) && - e->children()[1]->kind() == proto_expr::ID; - } - - bool is_annotated_cons(proto_expr* e) { - return is_prefixed(e, m_bang); - } - - bool is_builtin_const(symbol const& id, proto_expr* current, unsigned num_params, parameter * params, bool& ok, expr_ref& term) { - builtin_op info; - ok = true; - if (!m_builtin_ops.find(id, info)) { - return false; - } - fix_parameters(num_params, params); - func_decl* d = m_manager.mk_func_decl(info.m_family_id, info.m_kind, num_params, params, 0, (expr * const *)0); - if (!d) { - set_error("could not create a term from constant ", id, current); - ok = false; - } - else if (d->get_arity() != 0) { - set_error("identifier expects arguments ", id, current); - ok = false; - } - else { - term = m_manager.mk_const(d); - } - return true; - } - - bool is_underscore_op(region& r, proto_expr* e, idbuilder*& builder) { - if (!is_underscore(e)) { - return false; - } - builtin_op info; - proto_expr *const* chs = e->children()+1; - symbol const& id = (*chs)->string(); - sort_ref_vector sorts(m_manager); - vector params; - - if (!m_builtin_ops.find(id, info)) { - return false; - } - if (!parse_params(chs+1, params, sorts)) { - return false; - } - - builder = new (r) builtin_builder(this, info.m_family_id, info.m_kind, params); - return true; - } - - void fix_parameters(unsigned num_params, parameter* params) { - for (unsigned i = 0; i < num_params; ++i) { - func_decl* d = 0; - sort* s = 0; - builtin_op info; - if (params[i].is_symbol() && m_benchmark.get_symtable()->find1(params[i].get_symbol(), d)) { - params[i] = parameter(d); - } - else if (params[i].is_symbol() && m_benchmark.get_symtable()->find(params[i].get_symbol(), s)) { - params[i] = parameter(s); - } - else if (params[i].is_symbol() && m_builtin_sorts.find(params[i].get_symbol(), info)) { - params[i] = parameter(m_manager.mk_sort(info.m_family_id, info.m_kind, 0, 0)); - } - } - } - - bool make_app(proto_expr * proto_expr, expr_ref_vector const & args, expr_ref & result) { - symbol const& name = proto_expr->string(); - ptr_vector sorts; - func_decl * d = 0; - smtlib::symtable * symtable = m_benchmark.get_symtable(); - - for (unsigned i = 0; i < args.size(); ++i) { - sorts.push_back(m_manager.get_sort(args.get(i))); - } - - if (symtable->find_overload(name, sorts, d)) { - result = m_manager.mk_app(d, args.size(), args.c_ptr()); - return true; - } - - builtin_op info; - if (m_builtin_ops.find(name, info)) { - unsigned num_params = proto_expr->num_params(); - parameter * params = proto_expr->params(); - fix_parameters(num_params, params); - d = m_manager.mk_func_decl(info.m_family_id, info.m_kind, num_params, params, args.size(), args.c_ptr()); - if (d) { - result = m_manager.mk_app(d, args.size(), args.c_ptr()); - return true; - } - } - - rational arg2_value; - bool arg2_is_int; - - if (name == symbol("store") && - args.size() == 3 && - m_anum_util.is_numeral(args.get(2), arg2_value, arg2_is_int) && - arg2_is_int) { - expr_ref_vector new_args(m_manager); - new_args.push_back(args.get(0)); - new_args.push_back(args.get(1)); - new_args.push_back(m_anum_util.mk_numeral(arg2_value, false)); - sorts.reset(); - for (unsigned i = 0; i < args.size(); ++i) { - sorts.push_back(m_manager.get_sort(new_args.get(i))); - } - if (symtable->find_overload(name, sorts, d)) { - result = m_manager.mk_app(d, new_args.size(), new_args.c_ptr()); - return true; - } - } - - error_prefix(proto_expr); - get_err() << "could not find overload for '" << name << "' "; - for (unsigned i = 0; i < sorts.size(); ++i) { - get_err() << "Argument: " - << mk_pp(args.get(i), m_manager) - << " has type " - << mk_pp(sorts[i], m_manager) - << ".\n"; - } - return false; - } - - class nullary : public idbuilder { - expr* m_expr; - smtparser* m_parser; - unsigned m_decl_level_save; - public: - nullary(expr* e, smtparser* p) : m_expr(e), m_parser(p), m_decl_level_save(p->m_binding_level) {} - - virtual bool apply(expr_ref_vector const& args, expr_ref & result) { - unsigned decl_level = m_parser->m_binding_level; - SASSERT(decl_level >= m_decl_level_save); - shift_vars shifty(m_parser->m_manager); - shifty(m_expr, decl_level - m_decl_level_save, result); - return (args.size() == 0); - } - }; - - class identity : public idbuilder { - public: - identity() {} - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() == 1) { - result = args.back(); - return true; - } - else { - return false; - } - } - }; - - class parse_frame { - public: - - parse_frame(proto_expr * e, idbuilder * make, expr_ref_vector * left, proto_expr * const* right, unsigned binding_level): - m_proto_expr(e), - m_make_term(make), - m_left(left), - m_right(right), - m_binding_level(binding_level) { - } - - parse_frame(proto_expr * e, expr_ref_vector * left, proto_expr * const* right, unsigned binding_level): - m_proto_expr(e), - m_make_term(0), - m_left(left), - m_right(right), - m_binding_level(binding_level) { - } - - expr_ref_vector * detach_left() { - expr_ref_vector * result = m_left; - SASSERT(m_left); - m_left = 0; - return result; - } - - unsigned binding_level() const { return m_binding_level; } - - proto_expr* const * right() const { return m_right; } - - idbuilder* make_term() { return m_make_term; } - - proto_expr* get_proto_expr() const { return m_proto_expr; } - - ~parse_frame() { dealloc(m_left); } - - private: - - proto_expr* m_proto_expr; - idbuilder* m_make_term; - expr_ref_vector * m_left; - proto_expr* const * m_right; - unsigned m_binding_level; - - parse_frame & operator=(parse_frame const & other); - - parse_frame(parse_frame const & other); - - }; - - class build_label : public idbuilder { - bool m_pos; - symbol m_sym; - smtparser * m_smt; - public: - build_label(smtparser * smt, bool is_pos, proto_expr * sym): m_pos(is_pos), m_smt(smt) { - switch(sym->kind()) { - case proto_expr::ID: - case proto_expr::STRING: - m_sym = sym->string(); - break; - case proto_expr::INT: - m_sym = symbol(sym->number().to_string().c_str()); - break; - default: - UNREACHABLE(); - break; - } - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() >= 1) { - result = m_smt->m_manager.mk_label(m_pos, m_sym, args.get(0)); - return true; - } - else { - return false; - } - } - }; - - class pop_let : public idbuilder { - public: - pop_let(symbol_table & local_scope, expr_ref_vector* pinned = 0): - m_local_scope(local_scope), - m_pinned(pinned) { - } - - virtual ~pop_let() {} - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - dealloc(m_pinned); - if (args.size() == 2) { - m_local_scope.end_scope(); - result = args.get(1); - return true; - } - else { - return false; - } - } - private: - symbol_table & m_local_scope; - expr_ref_vector* m_pinned; - }; - - class push_let : public idbuilder { - smtparser* m_parser; - region & m_region; - symbol_table & m_local_scope; - symbol m_let_var; - - public: - push_let(smtparser* p, region & region, symbol_table & local_scope, symbol const & let_var): - m_parser(p), - m_region(region), - m_local_scope(local_scope), - m_let_var(let_var) { - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - // - // . push a scope, - // . create a nullary function using the variable/term association. - // . return the (first) argument. - // - // - if (args.size() == 1) { - m_local_scope.begin_scope(); - m_local_scope.insert(m_let_var, new (m_region) nullary(args.back(), m_parser)); - result = args.back(); - return true; - } - else { - return false; - } - } - }; - - // push multiple let bound variables. - class push_let_and : public idbuilder { - smtparser* m_parser; - region & m_region; - symbol_table & m_local_scope; - unsigned m_num_vars; - symbol* m_vars; - expr_ref_vector* m_pinned; - - public: - push_let_and(smtparser* p, region & region, symbol_table & local_scope, expr_ref_vector* pinned, unsigned num_vars, symbol const* vars): - m_parser(p), - m_region(region), - m_local_scope(local_scope), - m_num_vars(num_vars), - m_vars(new (region) symbol[num_vars]), - m_pinned(pinned) { - for (unsigned i = 0; i < num_vars; ++i) { - m_vars[i] = vars[i]; - } - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() != m_num_vars) { - return false; - } - - // - // . push a scope, - // . create a nullary function using the variable/term association. - // . return the last argument (arbitrary). - // - - m_local_scope.begin_scope(); - for (unsigned i = 0; i < m_num_vars; ++i) { - m_local_scope.insert(m_vars[i], new (m_region) nullary(args[i], m_parser)); - m_pinned->push_back(args[i]); - } - result = args.back(); - return true; - } - }; - - class bound_var : public idbuilder { - public: - bound_var(smtparser * smt, sort * sort): - m_smt(smt), - m_decl_level(smt->m_binding_level), - m_sort(sort) { - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - SASSERT(m_smt->m_binding_level > m_decl_level); - unsigned idx = m_smt->m_binding_level - m_decl_level - 1; - result = m_smt->m_manager.mk_var(idx, m_sort); - return args.empty(); - } - - private: - smtparser * m_smt; - unsigned m_decl_level; - sort * m_sort; - }; - - class pop_quantifier : public idbuilder { - public: - pop_quantifier(smtparser * smt, bool is_forall, int weight, symbol const& qid, symbol const& skid, expr_ref_buffer & patterns, expr_ref_buffer & no_patterns, sort_ref_buffer & sorts, - svector& vars, symbol_table & local_scope): - m_smt(smt), - m_is_forall(is_forall), - m_weight(weight), - m_qid(qid), - m_skid(skid), - m_patterns(m_smt->m_manager), - m_no_patterns(m_smt->m_manager), - m_sorts(m_smt->m_manager), - m_local_scope(local_scope) { - SASSERT(sorts.size() == vars.size()); - - m_vars.append(vars); - m_sorts.append(sorts); - m_patterns.append(patterns); - m_no_patterns.append(no_patterns); - } - - virtual bool apply(expr_ref_vector const & args, expr_ref & result) { - if (args.size() != 1) { - return false; - } - - m_local_scope.end_scope(); - - expr * body = args.back(); - - if (m_smt->ignore_user_patterns()) { - TRACE("pat_bug", tout << "ignoring user patterns...: " << m_patterns.size() << "\n";); - result = m_smt->m_manager.mk_quantifier(m_is_forall, - m_sorts.size(), // num_decls - m_sorts.c_ptr(), // decl_sorts - m_vars.begin(), // decl_names - body, - m_weight, - m_qid, - m_skid, - 0, - 0, - 0, - 0); - } - else if (!m_patterns.empty()) { - if (!m_no_patterns.empty()) { - m_smt->set_error("patterns were provided, ignoring :nopat attribute.", ((proto_expr*)0)); - } - result = m_smt->m_manager.mk_quantifier(m_is_forall, - m_sorts.size(), // num_decls - m_sorts.c_ptr(), // decl_sorts - m_vars.begin(), // decl_names - body, - m_weight, - m_qid, - m_skid, - m_patterns.size(), - m_patterns.c_ptr(), - 0, - 0); - } - else { - result = m_smt->m_manager.mk_quantifier(m_is_forall, - m_sorts.size(), // num_decls - m_sorts.c_ptr(), // decl_sorts - m_vars.begin(), // decl_names - body, - m_weight, - m_qid, - m_skid, - 0, - 0, - m_no_patterns.size(), - m_no_patterns.c_ptr()); - } - - // - // reclaim memory resources on application. - // - - m_vars.finalize(); - m_sorts.finalize(); - m_patterns.finalize(); - m_no_patterns.finalize(); - return true; - } - - private: - smtparser* m_smt; - bool m_is_forall; - int m_weight; - symbol m_qid; - symbol m_skid; - expr_ref_buffer m_patterns; - expr_ref_buffer m_no_patterns; - sort_ref_buffer m_sorts; - svector m_vars; - symbol_table& m_local_scope; - }; - - class builtin_builder : public idbuilder { - smtparser* m_smt; - family_id m_fid; - decl_kind m_kind; - vector m_params; - - public: - builtin_builder(smtparser* smt, family_id fid, decl_kind k,vector const& p): - m_smt(smt), - m_fid(fid), - m_kind(k), - m_params(p) - { - } - - virtual bool apply(expr_ref_vector const& args, expr_ref& result) { - ast_manager& m = m_smt->m_manager; - func_decl* d = m.mk_func_decl(m_fid, m_kind, m_params.size(), m_params.c_ptr(), args.size(), args.c_ptr()); - if (d) { - result = m.mk_app(d, args.size(), args.c_ptr()); - } - m_params.finalize(); - return d != 0; - } - }; - - bool push_status(smtlib::benchmark::status status) { - m_benchmark.set_status( status); - return true; - } - - expr * mk_number(rational const & r, bool is_int){ - if (m_int_sort == m_real_sort) // integer constants should be mapped to real - is_int = false; - return m_anum_util.mk_numeral(r, is_int); - } - - void push_benchmark(symbol const & name) { - m_benchmark.set_name(name); - } - - bool push_assumption(expr * t) { - m_benchmark.add_axiom(t); - return true; - } - - bool push_formula(expr * t) { - m_benchmark.add_formula(t); - return true; - } - - bool is_binary_let_binding(proto_expr* let_binding) { - return - let_binding && - let_binding->children() && - let_binding->children()[0] && - (let_binding->children()[0]->kind() == proto_expr::ID) && - let_binding->children()[1] && - !let_binding->children()[2]; - } - - bool is_bvconst(symbol const & fname, unsigned num_params, parameter const* params, expr_ref & term) { - rational n; - char const * str = fname.bare_str(); - unsigned sz = 0; - - if (strncmp(str, "bvbin", 5) == 0) { - str += 5; - n = rational(0); - while (*str == '1' || *str == '0') { - n *= rational(2); - n += rational(*str - '0'); - ++sz; - ++str; - } - if (sz == 0) { - return false; - } - } - else if (strncmp(str, "bvhex", 5) == 0) { - n = rational(0); - str += 5; - while (('0' <= *str && *str <= '9') || - ('a' <= *str && *str <= 'f') || - ('A' <= *str && *str <= 'F')) { - n *= rational(16); - if ('0' <= *str && *str <= '9') { - n += rational(*str - '0'); - } - else if ('a' <= *str && *str <= 'f') { - n += rational(10); - n += rational(*str - 'a'); - } - else { - SASSERT('A' <= *str && *str <= 'F'); - n += rational(10); - n += rational(*str - 'A'); - } - sz += 4; - ++str; - } - if (sz == 0) { - return false; - } - } - else if (strncmp(str, "bv", 2) == 0 && '0' <= *(str + 2) && *(str + 2) <= '9') { - n = rational(0); - str += 2; - while ('0' <= *str && *str <= '9') { - n *= rational(10); - n += rational(*str - '0'); - ++str; - } - if (num_params == 1) { - sz = params[0].get_int(); - } - else { - sz = 32; - } - } - else { - return false; - } - - term = m_bvnum_util.mk_numeral(n, sz); - - return true; - } -}; - - -parser * parser::create(ast_manager& ast_manager, bool ignore_user_patterns) { - return alloc(smtparser, ast_manager, ignore_user_patterns); -} diff --git a/src/parsers/smt/smtparser.h b/src/parsers/smt/smtparser.h deleted file mode 100644 index d8999e8ab..000000000 --- a/src/parsers/smt/smtparser.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - smtparser.h - -Abstract: - - SMT parsing utilities - -Author: - - Nikolaj Bjorner (nbjorner) 2006-09-25 - -Revision History: - ---*/ -#ifndef SMT_PARSER_H_ -#define SMT_PARSER_H_ - -#include -#include "ast/ast.h" -#include "util/vector.h" -#include "parsers/smt/smtlib.h" - -namespace smtlib { - class parser { - public: - static parser * create(ast_manager & ast_manager, bool ignore_user_patterns = false); - - virtual ~parser() {} - - virtual void add_builtin_op(char const *, family_id fid, decl_kind kind) = 0; - virtual void add_builtin_type(char const *, family_id fid, decl_kind kind) = 0; - - virtual void initialize_smtlib() = 0; - - virtual void set_error_stream(std::ostream& strm) = 0; - - virtual bool parse_file(char const * path) = 0; - virtual bool parse_string(char const * string) = 0; - - virtual benchmark * get_benchmark() = 0; - }; -}; - -#endif diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 3d2609c4f..8b719681c 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -37,7 +37,7 @@ Revision History: #include "util/env_params.h" #include "shell/lp_frontend.h" -typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; +typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; std::string g_aux_input_file; char const * g_input_file = 0; @@ -169,9 +169,6 @@ void parse_cmd_line_args(int argc, char ** argv) { std::cout << "\n"; exit(0); } - else if (strcmp(opt_name, "smt") == 0) { - g_input_kind = IN_SMTLIB; - } else if (strcmp(opt_name, "smt2") == 0) { g_input_kind = IN_SMTLIB_2; } @@ -340,9 +337,6 @@ int STD_CALL main(int argc, char ** argv) { else if (strcmp(ext, "smt2") == 0) { g_input_kind = IN_SMTLIB_2; } - else if (strcmp(ext, "smt") == 0) { - g_input_kind = IN_SMTLIB; - } else if (strcmp(ext, "mps") == 0 || strcmp(ext, "sif") == 0 || strcmp(ext, "MPS") == 0 || strcmp(ext, "SIF") == 0) { g_input_kind = IN_MPS; @@ -350,9 +344,6 @@ int STD_CALL main(int argc, char ** argv) { } } switch (g_input_kind) { - case IN_SMTLIB: - return_value = read_smtlib_file(g_input_file); - break; case IN_SMTLIB_2: memory::exit_when_out_of_memory(true, "(error \"out of memory\")"); return_value = read_smtlib2_commands(g_input_file); diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 666a1e1fe..8c716a81a 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -21,7 +21,6 @@ Revision History: #include #include #include -#include "parsers/smt/smtlib_solver.h" #include "util/timeout.h" #include "parsers/smt2/smt2parser.h" #include "muz/fp/dl_cmds.h" @@ -35,20 +34,14 @@ Revision History: extern bool g_display_statistics; static clock_t g_start_time; -static smtlib::solver* g_solver = 0; static cmd_context * g_cmd_context = 0; static void display_statistics() { clock_t end_time = clock(); - if ((g_solver || g_cmd_context) && g_display_statistics) { + if (g_cmd_context && g_display_statistics) { std::cout.flush(); std::cerr.flush(); - if (g_solver) { - g_solver->display_statistics(); - memory::display_max_usage(std::cout); - std::cout << "time: " << ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC) << " secs\n"; - } - else if (g_cmd_context) { + if (g_cmd_context) { g_cmd_context->set_regular_stream("stdout"); g_cmd_context->display_statistics(true, ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC)); } @@ -72,33 +65,6 @@ static void STD_CALL on_ctrl_c(int) { raise(SIGINT); } -unsigned read_smtlib_file(char const * benchmark_file) { - g_start_time = clock(); - register_on_timeout_proc(on_timeout); - signal(SIGINT, on_ctrl_c); - smtlib::solver solver; - g_solver = &solver; - - bool ok = true; - - ok = solver.solve_smt(benchmark_file); - if (!ok) { - if (benchmark_file) { - std::cerr << "ERROR: solving '" << benchmark_file << "'.\n"; - } - else { - std::cerr << "ERROR: solving input stream.\n"; - } - } - - #pragma omp critical (g_display_stats) - { - display_statistics(); - register_on_timeout_proc(0); - g_solver = 0; - } - return solver.get_error_code(); -} unsigned read_smtlib2_commands(char const * file_name) { g_start_time = clock(); diff --git a/src/test/quant_elim.cpp b/src/test/quant_elim.cpp index 3674e6b70..12fca706d 100644 --- a/src/test/quant_elim.cpp +++ b/src/test/quant_elim.cpp @@ -8,8 +8,6 @@ Copyright (c) 2015 Microsoft Corporation #include "smt/params/smt_params.h" #include "qe/qe.h" #include "ast/ast_pp.h" -#include "parsers/smt/smtlib.h" -#include "parsers/smt/smtparser.h" #include "util/lbool.h" #include #include "ast/reg_decl_plugins.h" @@ -54,6 +52,9 @@ static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char cons static void test_formula(lbool expected_outcome, char const* fml) { ast_manager m; reg_decl_plugins(m); + // No-op requires SMTLIB2 + +#if 0 scoped_ptr parser = smtlib::parser::create(m); parser->initialize_smtlib(); @@ -73,8 +74,10 @@ static void test_formula(lbool expected_outcome, char const* fml) { for (; it != end; ++it) { test_qe(m, expected_outcome, *it, 0); } +#endif } + void tst_quant_elim() { disable_debug("heap"); From 92b4b9e7a728bf95c0971fc0abec718b28534beb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 11:14:00 -0800 Subject: [PATCH 02/72] fix error messaging for parsers Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 16 ++++++++++++-- src/api/api_parsers.cpp | 14 +++++++++++- src/api/python/z3/z3.py | 38 +++++++++++++++++++++++++++------ src/cmd_context/cmd_context.cpp | 7 ++++++ src/cmd_context/cmd_context.h | 2 ++ 5 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 9f5f7dd5d..ac11e1a33 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -286,11 +286,23 @@ extern "C" { scoped_ptr ctx = alloc(cmd_context, false, &m); install_opt_cmds(*ctx.get(), to_optimize_ptr(opt)); ctx->set_ignore_check(true); - if (!parse_smt2_commands(*ctx.get(), s)) { + std::stringstream errstrm; + ctx->set_regular_stream(errstrm); + try { + if (!parse_smt2_commands(*ctx.get(), s)) { + mk_c(c)->m_parser_error_buffer = errstrm.str(); + ctx = nullptr; + SET_ERROR_CODE(Z3_PARSER_ERROR); + return; + } + } + catch (z3_exception& e) { + errstrm << e.msg(); + mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); return; - } + } ptr_vector::const_iterator it = ctx->begin_assertions(); ptr_vector::const_iterator end = ctx->end_assertions(); for (; it != end; ++it) { diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 867117984..a7235ef65 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -55,7 +55,19 @@ extern "C" { psort* ps = ctx->pm().mk_psort_cnst(to_sort(sorts[i])); ctx->insert(ctx->pm().mk_psort_user_decl(0, to_symbol(sort_names[i]), ps)); } - if (!parse_smt2_commands(*ctx.get(), is)) { + std::stringstream errstrm; + ctx->set_regular_stream(errstrm); + try { + if (!parse_smt2_commands(*ctx.get(), is)) { + ctx = nullptr; + mk_c(c)->m_parser_error_buffer = errstrm.str(); + SET_ERROR_CODE(Z3_PARSER_ERROR); + return of_ast(mk_c(c)->m().mk_true()); + } + } + catch (z3_exception& e) { + errstrm << e.msg(); + mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); return of_ast(mk_c(c)->m().mk_true()); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1f050d3bd..2304491c8 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6668,11 +6668,17 @@ class Fixedpoint(Z3PPObject): def parse_string(self, s): """Parse rules and queries from a string""" - return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx) + try: + return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def parse_file(self, f): """Parse rules and queries from a file""" - return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx) + try: + return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def get_rules(self): """retrieve rules that have been added to fixedpoint context""" @@ -6995,15 +7001,21 @@ class Optimize(Z3PPObject): def upper_values(self, obj): if not isinstance(obj, OptimizeObjective): raise Z3Exception("Expecting objective handle returned by maximize/minimize") - return obj.upper_values() + return obj.upper_values() def from_file(self, filename): """Parse assertions and objectives from a file""" - Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename) + try: + Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def from_string(self, s): """Parse assertions and objectives from a string""" - Z3_optimize_from_string(self.ctx.ref(), self.optimize, s) + try: + Z3_optimize_from_string(self.ctx.ref(), self.optimize, s) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def assertions(self): """Return an AST vector containing all added constraints.""" @@ -8071,6 +8083,12 @@ def _dict2darray(decls, ctx): i = i + 1 return sz, _names, _decls +def _handle_parse_error(ex, ctx): + msg = Z3_get_parser_error(ctx.ref()) + if msg != "": + raise Z3Exception(msg) + raise ex + def parse_smt2_string(s, sorts={}, decls={}, ctx=None): """Parse a string in SMT 2.0 format using the given sorts and decls. @@ -8089,7 +8107,10 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - return _to_expr_ref(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + try: + return _to_expr_ref(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + except Z3Exception as e: + _handle_parse_error(e, ctx) def parse_smt2_file(f, sorts={}, decls={}, ctx=None): """Parse a file in SMT 2.0 format using the given sorts and decls. @@ -8099,7 +8120,10 @@ def parse_smt2_file(f, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + try: + return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + except Z3Exception as e: + _handle_parse_error(e, ctx) def Interpolant(a,ctx=None): """Create an interpolation operator. diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index a1e7a4745..ec2eea032 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -339,6 +339,13 @@ void ast_object_ref::finalize(cmd_context & ctx) { ctx.m().dec_ref(m_ast); } +void stream_ref::set(std::ostream& out) { + reset(); + m_owner = false; + m_name = "caller-owned"; + m_stream = &out; +} + void stream_ref::set(char const * name) { if (!name) { throw cmd_exception("invalid stream name"); diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index b60f590a9..99d6c8284 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -128,6 +128,7 @@ public: stream_ref(std::string n, std::ostream & d):m_default_name(n), m_default(d), m_name(n), m_stream(&d), m_owner(false) {} ~stream_ref() { reset(); } void set(char const * name); + void set(std::ostream& strm); void reset(); std::ostream & operator*() { return *m_stream; } char const * name() const { return m_name.c_str(); } @@ -404,6 +405,7 @@ public: void reset_object_refs(); void reset_user_tactics(); void set_regular_stream(char const * name) { m_regular.set(name); } + void set_regular_stream(std::ostream& out) { m_regular.set(out); } void set_diagnostic_stream(char const * name); virtual std::ostream & regular_stream() { return *m_regular; } virtual std::ostream & diagnostic_stream() { return *m_diagnostic; } From 161b6a99831817379a8b81af4c39a7c810e51f71 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 11:51:37 -0800 Subject: [PATCH 03/72] increase minor version, update java/.net apis Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/api/dotnet/Context.cs | 150 -------------------------------------- src/api/java/Context.java | 139 ----------------------------------- 3 files changed, 1 insertion(+), 290 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 5ab56d1c7..8f75e97ed 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 5, 1, 0) + set_version(4, 6, 1, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 914cee615..ac23d1dbc 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3320,160 +3320,10 @@ namespace Microsoft.Z3 #endregion #region SMT Files & Strings - /// - /// Convert a benchmark into an SMT-LIB formatted string. - /// - /// Name of the benchmark. The argument is optional. - /// The benchmark logic. - /// The status string (sat, unsat, or unknown) - /// Other attributes, such as source, difficulty or category. - /// Auxiliary assumptions. - /// Formula to be checked for consistency in conjunction with assumptions. - /// A string representation of the benchmark. - public string BenchmarkToSMTString(string name, string logic, string status, string attributes, - BoolExpr[] assumptions, BoolExpr formula) - { - Contract.Requires(assumptions != null); - Contract.Requires(formula != null); - Contract.Ensures(Contract.Result() != null); - - return Native.Z3_benchmark_to_smtlib_string(nCtx, name, logic, status, attributes, - (uint)assumptions.Length, AST.ArrayToNative(assumptions), - formula.NativeObject); - } - - /// - /// Parse the given string using the SMT-LIB parser. - /// - /// - /// The symbol table of the parser can be initialized using the given sorts and declarations. - /// The symbols in the arrays and - /// don't need to match the names of the sorts and declarations in the arrays - /// and . This is a useful feature since we can use arbitrary names to - /// reference sorts and declarations. - /// - public void ParseSMTLIBString(string str, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) - { - uint csn = Symbol.ArrayLength(sortNames); - uint cs = Sort.ArrayLength(sorts); - uint cdn = Symbol.ArrayLength(declNames); - uint cd = AST.ArrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.Z3_parse_smtlib_string(nCtx, str, - AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), - AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)); - } - - /// - /// Parse the given file using the SMT-LIB parser. - /// - /// - public void ParseSMTLIBFile(string fileName, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) - { - uint csn = Symbol.ArrayLength(sortNames); - uint cs = Sort.ArrayLength(sorts); - uint cdn = Symbol.ArrayLength(declNames); - uint cd = AST.ArrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.Z3_parse_smtlib_file(nCtx, fileName, - AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), - AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)); - } - - /// - /// The number of SMTLIB formulas parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBFormulas { get { return Native.Z3_get_smtlib_num_formulas(nCtx); } } - - /// - /// The formulas parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public BoolExpr[] SMTLIBFormulas - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBFormulas; - BoolExpr[] res = new BoolExpr[n]; - for (uint i = 0; i < n; i++) - res[i] = (BoolExpr)Expr.Create(this, Native.Z3_get_smtlib_formula(nCtx, i)); - return res; - } - } - - /// - /// The number of SMTLIB assumptions parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBAssumptions { get { return Native.Z3_get_smtlib_num_assumptions(nCtx); } } - - /// - /// The assumptions parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public BoolExpr[] SMTLIBAssumptions - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBAssumptions; - BoolExpr[] res = new BoolExpr[n]; - for (uint i = 0; i < n; i++) - res[i] = (BoolExpr)Expr.Create(this, Native.Z3_get_smtlib_assumption(nCtx, i)); - return res; - } - } - - /// - /// The number of SMTLIB declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBDecls { get { return Native.Z3_get_smtlib_num_decls(nCtx); } } - - /// - /// The declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public FuncDecl[] SMTLIBDecls - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBDecls; - FuncDecl[] res = new FuncDecl[n]; - for (uint i = 0; i < n; i++) - res[i] = new FuncDecl(this, Native.Z3_get_smtlib_decl(nCtx, i)); - return res; - } - } - - /// - /// The number of SMTLIB sorts parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public uint NumSMTLIBSorts { get { return Native.Z3_get_smtlib_num_sorts(nCtx); } } - - /// - /// The declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. - /// - public Sort[] SMTLIBSorts - { - get - { - Contract.Ensures(Contract.Result() != null); - - uint n = NumSMTLIBSorts; - Sort[] res = new Sort[n]; - for (uint i = 0; i < n; i++) - res[i] = Sort.Create(this, Native.Z3_get_smtlib_sort(nCtx, i)); - return res; - } - } /// /// Parse the given string using the SMT-LIB2 parser. /// - /// /// A conjunction of assertions in the scope (up to push/pop) at the end of the string. public BoolExpr ParseSMTLIB2String(string str, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) { diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 76303d670..3458f4d97 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2540,147 +2540,8 @@ public class Context implements AutoCloseable { AST.arrayToNative(assumptions), formula.getNativeObject()); } - /** - * Parse the given string using the SMT-LIB parser. - * Remarks: The symbol - * table of the parser can be initialized using the given sorts and - * declarations. The symbols in the arrays {@code sortNames} and - * {@code declNames} don't need to match the names of the sorts - * and declarations in the arrays {@code sorts} and {@code decls}. This is a useful feature since we can use arbitrary names - * to reference sorts and declarations. - **/ - public void parseSMTLIBString(String str, Symbol[] sortNames, Sort[] sorts, - Symbol[] declNames, FuncDecl[] decls) - { - int csn = Symbol.arrayLength(sortNames); - int cs = Sort.arrayLength(sorts); - int cdn = Symbol.arrayLength(declNames); - int cd = AST.arrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.parseSmtlibString(nCtx(), str, AST.arrayLength(sorts), - Symbol.arrayToNative(sortNames), AST.arrayToNative(sorts), - AST.arrayLength(decls), Symbol.arrayToNative(declNames), - AST.arrayToNative(decls)); - } - - /** - * Parse the given file using the SMT-LIB parser. - * @see #parseSMTLIBString - **/ - public void parseSMTLIBFile(String fileName, Symbol[] sortNames, - Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) - - { - int csn = Symbol.arrayLength(sortNames); - int cs = Sort.arrayLength(sorts); - int cdn = Symbol.arrayLength(declNames); - int cd = AST.arrayLength(decls); - if (csn != cs || cdn != cd) - throw new Z3Exception("Argument size mismatch"); - Native.parseSmtlibFile(nCtx(), fileName, AST.arrayLength(sorts), - Symbol.arrayToNative(sortNames), AST.arrayToNative(sorts), - AST.arrayLength(decls), Symbol.arrayToNative(declNames), - AST.arrayToNative(decls)); - } - - /** - * The number of SMTLIB formulas parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBFormulas() - { - return Native.getSmtlibNumFormulas(nCtx()); - } - - /** - * The formulas parsed by the last call to {@code ParseSMTLIBString} or - * {@code ParseSMTLIBFile}. - **/ - public BoolExpr[] getSMTLIBFormulas() - { - - int n = getNumSMTLIBFormulas(); - BoolExpr[] res = new BoolExpr[n]; - for (int i = 0; i < n; i++) - res[i] = (BoolExpr) Expr.create(this, - Native.getSmtlibFormula(nCtx(), i)); - return res; - } - - /** - * The number of SMTLIB assumptions parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBAssumptions() - { - return Native.getSmtlibNumAssumptions(nCtx()); - } - - /** - * The assumptions parsed by the last call to {@code ParseSMTLIBString} - * or {@code ParseSMTLIBFile}. - **/ - public BoolExpr[] getSMTLIBAssumptions() - { - - int n = getNumSMTLIBAssumptions(); - BoolExpr[] res = new BoolExpr[n]; - for (int i = 0; i < n; i++) - res[i] = (BoolExpr) Expr.create(this, - Native.getSmtlibAssumption(nCtx(), i)); - return res; - } - - /** - * The number of SMTLIB declarations parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBDecls() - { - return Native.getSmtlibNumDecls(nCtx()); - } - - /** - * The declarations parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public FuncDecl[] getSMTLIBDecls() - { - - int n = getNumSMTLIBDecls(); - FuncDecl[] res = new FuncDecl[n]; - for (int i = 0; i < n; i++) - res[i] = new FuncDecl(this, Native.getSmtlibDecl(nCtx(), i)); - return res; - } - - /** - * The number of SMTLIB sorts parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public int getNumSMTLIBSorts() - { - return Native.getSmtlibNumSorts(nCtx()); - } - - /** - * The declarations parsed by the last call to - * {@code ParseSMTLIBString} or {@code ParseSMTLIBFile}. - **/ - public Sort[] getSMTLIBSorts() - { - - int n = getNumSMTLIBSorts(); - Sort[] res = new Sort[n]; - for (int i = 0; i < n; i++) - res[i] = Sort.create(this, Native.getSmtlibSort(nCtx(), i)); - return res; - } - /** * Parse the given string using the SMT-LIB2 parser. - * @see #parseSMTLIBString * * @return A conjunction of assertions in the scope (up to push/pop) at the * end of the string. From eeee77889b7759bab231797e7242c7cc7a9e0535 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 11:58:58 -0800 Subject: [PATCH 04/72] add parser error Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4b5e9d04e..236750bdf 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -174,6 +174,15 @@ namespace z3 { return e; } + void check_parser_error() const { + Z3_error_code e = Z3_get_error_code(*this); + if (e != Z3_OK && enable_exceptions()) { + Z3_string s = Z3_get_parser_error(*this); + if (s && *s) Z3_THROW(exception(s)); + } + check_error(); + } + /** \brief The C++ API uses by defaults exceptions on errors. For applications that don't work well with exceptions (there should be only few) @@ -2774,13 +2783,12 @@ namespace z3 { inline expr context::parse_string(char const* s) { Z3_ast r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); - check_error(); - return expr(*this, r); - + check_parser_error(); + return expr(*this, r); } inline expr context::parse_file(char const* s) { Z3_ast r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); - check_error(); + check_parser_error(); return expr(*this, r); } @@ -2796,7 +2804,7 @@ namespace z3 { decl_names[i] = decls[i].name(); } Z3_ast r = Z3_parse_smtlib2_string(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); - check_error(); + check_parser_error(); return expr(*this, r); } @@ -2812,7 +2820,7 @@ namespace z3 { decl_names[i] = decls[i].name(); } Z3_ast r = Z3_parse_smtlib2_file(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); - check_error(); + check_parser_error(); return expr(*this, r); } From d1ee5431a7798c451cba613c2301a5e5b5b8ef6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 14:19:30 -0800 Subject: [PATCH 05/72] Update version Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 715679957..0be2de537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ endif() # Project version ################################################################################ set(Z3_VERSION_MAJOR 4) -set(Z3_VERSION_MINOR 5) +set(Z3_VERSION_MINOR 6) set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") From b8e5fc9f435f6c67de4c9ea78298ac567dd40502 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 15:08:28 -0800 Subject: [PATCH 06/72] remove SMTLIB1 printing Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 23 +---------------------- src/api/z3_api.h | 4 +--- src/ast/ast_smt_pp.cpp | 17 +++++++++-------- src/ast/ast_smt_pp.h | 1 - 4 files changed, 11 insertions(+), 34 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index e22603225..76b0eb717 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -832,30 +832,9 @@ extern "C" { case Z3_PRINT_LOW_LEVEL: buffer << mk_ll_pp(to_ast(a), mk_c(c)->m()); break; - case Z3_PRINT_SMTLIB_COMPLIANT: { - ast_smt_pp pp(mk_c(c)->m()); - pp_params params; - pp.set_simplify_implies(params.simplify_implies()); - ast* a1 = to_ast(a); - pp.set_logic(mk_c(c)->fparams().m_logic); - if (!is_expr(a1)) { - buffer << mk_pp(a1, mk_c(c)->m()); - break; - } - if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB_COMPLIANT) { - pp.display_expr(buffer, to_expr(a1)); - break; - } - if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB2_COMPLIANT) { - pp.display_expr_smt2(buffer, to_expr(a1)); - break; - } - break; - } - case Z3_PRINT_SMTLIB2_COMPLIANT: { + case Z3_PRINT_SMTLIB2_COMPLIANT: buffer << mk_ismt2_pp(to_ast(a), mk_c(c)->m()); break; - } default: UNREACHABLE(); } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 56d9f69b7..7edcada37 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1314,13 +1314,11 @@ typedef enum { - Z3_PRINT_SMTLIB_FULL: Print AST nodes in SMTLIB verbose format. - Z3_PRINT_LOW_LEVEL: Print AST nodes using a low-level format. - - Z3_PRINT_SMTLIB_COMPLIANT: Print AST nodes in SMTLIB 1.x compliant format. - Z3_PRINT_SMTLIB2_COMPLIANT: Print AST nodes in SMTLIB 2.x compliant format. */ typedef enum { Z3_PRINT_SMTLIB_FULL, Z3_PRINT_LOW_LEVEL, - Z3_PRINT_SMTLIB_COMPLIANT, Z3_PRINT_SMTLIB2_COMPLIANT } Z3_ast_print_mode; @@ -5116,7 +5114,7 @@ extern "C" { To print shared common subexpressions only once, use the Z3_PRINT_LOW_LEVEL mode. To print in way that conforms to SMT-LIB standards and uses let - expressions to share common sub-expressions use Z3_PRINT_SMTLIB_COMPLIANT. + expressions to share common sub-expressions use Z3_PRINT_SMTLIB2_COMPLIANT. \sa Z3_ast_to_string \sa Z3_pattern_to_string diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 906fd054b..352c8db98 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -478,7 +478,7 @@ class smt_printer { void print_no_lets(expr *e) { - smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, true, m_indent, m_num_var_names, m_var_names); + smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names); p(e); } @@ -511,7 +511,7 @@ class smt_printer { m_out << "(! "; } { - smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names); + smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_simplify_implies, m_indent, m_num_var_names, m_var_names); p(q->get_expr()); } @@ -704,7 +704,7 @@ class smt_printer { public: smt_printer(std::ostream& out, ast_manager& m, ptr_vector& ql, smt_renaming& rn, - symbol logic, bool no_lets, bool is_smt2, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = 0) : + symbol logic, bool no_lets, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = 0) : m_out(out), m_manager(m), m_qlists(ql), @@ -895,24 +895,25 @@ ast_smt_pp::ast_smt_pp(ast_manager& m): {} +#if 0 void ast_smt_pp::display_expr(std::ostream& strm, expr* n) { - ptr_vector ql; - smt_renaming rn; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); + ptr_vector ql; smt_renaming rn; + smt_printer p(strm, m_manager, ql, rn, m_logic, false, m_simplify_implies, 0); p(n); } +#endif void ast_smt_pp::display_expr_smt2(std::ostream& strm, expr* n, unsigned indent, unsigned num_var_names, char const* const* var_names) { ptr_vector ql; smt_renaming rn; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, indent, num_var_names, var_names); + smt_printer p(strm, m_manager, ql, rn, m_logic, false, m_simplify_implies, indent, num_var_names, var_names); p(n); } void ast_smt_pp::display_ast_smt2(std::ostream& strm, ast* a, unsigned indent, unsigned num_var_names, char const* const* var_names) { ptr_vector ql; smt_renaming rn; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, indent, num_var_names, var_names); + smt_printer p(strm, m_manager, ql, rn, m_logic, false, m_simplify_implies, indent, num_var_names, var_names); if (is_expr(a)) { p(to_expr(a)); } diff --git a/src/ast/ast_smt_pp.h b/src/ast/ast_smt_pp.h index dd2a6d753..41ed06a92 100644 --- a/src/ast/ast_smt_pp.h +++ b/src/ast/ast_smt_pp.h @@ -77,7 +77,6 @@ public: void display(std::ostream& strm, expr* n); void display_smt2(std::ostream& strm, expr* n); - void display_expr(std::ostream& strm, expr* n); void display_expr_smt2(std::ostream& strm, expr* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); void display_ast_smt2(std::ostream& strm, ast* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); From 2749e547cf546608749df79cc18b150618e5eb87 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 18:14:24 -0800 Subject: [PATCH 07/72] fix c example, remove more smtlib1 printing Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 87 +++---------------------- src/api/api_ast.cpp | 7 +- src/ast/ast_smt_pp.cpp | 106 +------------------------------ src/ast/ast_smt_pp.h | 1 - src/ast/proofs/proof_checker.cpp | 2 +- src/smt/theory_arith_pp.h | 2 +- 6 files changed, 15 insertions(+), 190 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index f6d515389..d71771f98 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -395,11 +395,10 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) t_name = Z3_mk_string_symbol(ctx, "T"); - Z3_parse_smtlib_string(ctx, - "(benchmark comm :formula (forall (x T) (y T) (= (f x y) (f y x))))", + q = Z3_parse_smtlib2_string(ctx, + "(assert (forall ((x T) (y T)) (= (f x y) (f y x))))", 1, &t_name, &t, 1, &f_name, &f); - q = Z3_get_smtlib_formula(ctx, 0); printf("assert axiom:\n%s\n", Z3_ast_to_string(ctx, q)); Z3_solver_assert(ctx, s, q); } @@ -1632,35 +1631,6 @@ void error_code_example2() { } } -/** - \brief Demonstrates how to use the SMTLIB parser. - */ -void parser_example1() -{ - Z3_context ctx = mk_context(); - Z3_solver s = mk_solver(ctx); - unsigned i, num_formulas; - - printf("\nparser_example1\n"); - LOG_MSG("parser_example1"); - - - Z3_parse_smtlib_string(ctx, - "(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))", - 0, 0, 0, - 0, 0, 0); - num_formulas = Z3_get_smtlib_num_formulas(ctx); - for (i = 0; i < num_formulas; i++) { - Z3_ast f = Z3_get_smtlib_formula(ctx, i); - printf("formula %d: %s\n", i, Z3_ast_to_string(ctx, f)); - Z3_solver_assert(ctx, s, f); - } - - check(ctx, s, Z3_L_TRUE); - - del_solver(ctx, s); - Z3_del_context(ctx); -} /** \brief Demonstrates how to initialize the parser symbol table. @@ -1690,12 +1660,11 @@ void parser_example2() names[0] = Z3_mk_string_symbol(ctx, "a"); names[1] = Z3_mk_string_symbol(ctx, "b"); - Z3_parse_smtlib_string(ctx, - "(benchmark tst :formula (> a b))", + f = Z3_parse_smtlib2_string(ctx, + "(assert (> a b))", 0, 0, 0, /* 'x' and 'y' declarations are inserted as 'a' and 'b' into the parser symbol table. */ 2, names, decls); - f = Z3_get_smtlib_formula(ctx, 0); printf("formula: %s\n", Z3_ast_to_string(ctx, f)); Z3_solver_assert(ctx, s, f); check(ctx, s, Z3_L_TRUE); @@ -1737,11 +1706,10 @@ void parser_example3() assert_comm_axiom(ctx, s, g); - Z3_parse_smtlib_string(ctx, - "(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (g x 0) (g 0 y)))))", + thm = Z3_parse_smtlib2_string(ctx, + "(assert (forall ((x Int) (y Int)) (=> (= x y) (= (g x 0) (g 0 y)))))", 0, 0, 0, 1, &g_name, &g); - thm = Z3_get_smtlib_formula(ctx, 0); printf("formula: %s\n", Z3_ast_to_string(ctx, thm)); prove(ctx, s, thm, Z3_TRUE); @@ -1749,41 +1717,6 @@ void parser_example3() Z3_del_context(ctx); } -/** - \brief Display the declarations, assumptions and formulas in a SMT-LIB string. -*/ -void parser_example4() -{ - Z3_context ctx; - unsigned i, num_decls, num_assumptions, num_formulas; - - printf("\nparser_example4\n"); - LOG_MSG("parser_example4"); - - ctx = mk_context(); - - Z3_parse_smtlib_string(ctx, - "(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))", - 0, 0, 0, - 0, 0, 0); - num_decls = Z3_get_smtlib_num_decls(ctx); - for (i = 0; i < num_decls; i++) { - Z3_func_decl d = Z3_get_smtlib_decl(ctx, i); - printf("declaration %d: %s\n", i, Z3_func_decl_to_string(ctx, d)); - } - num_assumptions = Z3_get_smtlib_num_assumptions(ctx); - for (i = 0; i < num_assumptions; i++) { - Z3_ast a = Z3_get_smtlib_assumption(ctx, i); - printf("assumption %d: %s\n", i, Z3_ast_to_string(ctx, a)); - } - num_formulas = Z3_get_smtlib_num_formulas(ctx); - for (i = 0; i < num_formulas; i++) { - Z3_ast f = Z3_get_smtlib_formula(ctx, i); - printf("formula %d: %s\n", i, Z3_ast_to_string(ctx, f)); - } - Z3_del_context(ctx); -} - /** \brief Demonstrates how to handle parser errors using Z3 error handling support. */ @@ -1802,9 +1735,9 @@ void parser_example5() { s = mk_solver(ctx); Z3_del_config(cfg); - Z3_parse_smtlib_string(ctx, + Z3_parse_smtlib2_string(ctx, /* the following string has a parsing error: missing parenthesis */ - "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", + "(declare-const x Int) declare-const y Int) (assert (and (> x y) (> x 0)))", 0, 0, 0, 0, 0, 0); e = Z3_get_error_code(ctx); @@ -1817,7 +1750,7 @@ void parser_example5() { err: printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { - printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx)); + printf("Error message: '%s'.\n",Z3_get_parser_error(ctx)); del_solver(ctx, s); Z3_del_context(ctx); } @@ -3065,10 +2998,8 @@ int main() { two_contexts_example1(); error_code_example1(); error_code_example2(); - parser_example1(); parser_example2(); parser_example3(); - parser_example4(); parser_example5(); numeral_example(); ite_example(); diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 76b0eb717..ae23ca100 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -872,12 +872,7 @@ extern "C" { for (unsigned i = 0; i < num_assumptions; ++i) { pp.add_assumption(to_expr(assumptions[i])); } - if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB2_COMPLIANT) { - pp.display_smt2(buffer, to_expr(formula)); - } - else { - pp.display(buffer, to_expr(formula)); - } + pp.display_smt2(buffer, to_expr(formula)); return mk_c(c)->mk_external_string(buffer.str()); Z3_CATCH_RETURN(""); } diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 352c8db98..bad4b1984 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -340,8 +340,7 @@ class smt_printer { } - void pp_arg(expr *arg, app *parent) - { + void pp_arg(expr *arg, app *parent) { pp_marked_expr(arg); } @@ -417,7 +416,7 @@ class smt_printer { else if (m_simplify_implies && m_manager.is_implies(decl) && m_manager.is_implies(n->get_arg(1))) { expr *curr = n; expr *arg; - m_out << "(implies (and"; + m_out << "(=> (and"; while (m_manager.is_implies(curr)) { arg = to_app(curr)->get_arg(0); @@ -476,8 +475,7 @@ class smt_printer { } } - void print_no_lets(expr *e) - { + void print_no_lets(expr *e) { smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names); p(e); } @@ -894,15 +892,6 @@ ast_smt_pp::ast_smt_pp(ast_manager& m): m_simplify_implies(true) {} - -#if 0 -void ast_smt_pp::display_expr(std::ostream& strm, expr* n) { - ptr_vector ql; smt_renaming rn; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, m_simplify_implies, 0); - p(n); -} -#endif - void ast_smt_pp::display_expr_smt2(std::ostream& strm, expr* n, unsigned indent, unsigned num_var_names, char const* const* var_names) { ptr_vector ql; smt_renaming rn; @@ -1022,92 +1011,3 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { p(n); } } - -void ast_smt_pp::display(std::ostream& strm, expr* n) { - ptr_vector ql; - decl_collector decls(m_manager); - smt_renaming rn; - - for (unsigned i = 0; i < m_assumptions.size(); ++i) { - decls.visit(m_assumptions[i].get()); - } - for (unsigned i = 0; i < m_assumptions_star.size(); ++i) { - decls.visit(m_assumptions_star[i].get()); - } - decls.visit(n); - - strm << "(benchmark "; - - if (m_benchmark_name != symbol::null) { - strm << m_benchmark_name << "\n"; - } - else { - strm << "unnamed\n"; - } - if (m_source_info != symbol::null && m_source_info != symbol("")) { - strm << ":source { " << m_source_info << " }\n"; - } - strm << ":status " << m_status << "\n"; - if (m_category != symbol::null && m_category != symbol("")) { - strm << ":category { " << m_category << " }\n"; - } - if (m_logic != symbol::null && m_logic != symbol("")) { - strm << ":logic " << m_logic << "\n"; - } - - if (m_attributes.size() > 0) { - strm << m_attributes.c_str(); - } - - ast_mark sort_mark; - for (unsigned i = 0; i < decls.get_num_sorts(); ++i) { - sort* s = decls.get_sorts()[i]; - if (!(*m_is_declared)(s)) { - smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0); - p.pp_sort_decl(sort_mark, s); - } - } - - for (unsigned i = 0; i < decls.get_num_decls(); ++i) { - func_decl* d = decls.get_func_decls()[i]; - if (!(*m_is_declared)(d)) { - strm << ":extrafuns ("; - smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0); - p(d); - strm << ")\n"; - } - } - - for (unsigned i = 0; i < decls.get_num_preds(); ++i) { - func_decl* d = decls.get_pred_decls()[i]; - if (!(*m_is_declared)(d)) { - strm << ":extrapreds ("; - smt_printer p(strm, m_manager, ql, rn, m_logic, true, false, m_simplify_implies, 0); - p.visit_pred(d); - strm << ")\n"; - } - } - - for (unsigned i = 0; i < m_assumptions.size(); ++i) { - expr * e = m_assumptions[i].get(); - strm << ":assumption\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); - p(e); - strm << "\n"; - } - - for (unsigned i = 0; i < m_assumptions_star.size(); ++i) { - strm << ":assumption-core\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); - p(m_assumptions_star[i].get()); - strm << "\n"; - } - - { - strm << ":formula\n"; - smt_printer p(strm, m_manager, ql, rn, m_logic, false, false, m_simplify_implies, 0); - p(n); - strm << "\n"; - } - strm << ")\n"; -} diff --git a/src/ast/ast_smt_pp.h b/src/ast/ast_smt_pp.h index 41ed06a92..ac2e33140 100644 --- a/src/ast/ast_smt_pp.h +++ b/src/ast/ast_smt_pp.h @@ -75,7 +75,6 @@ public: void set_is_declared(is_declared* id) { m_is_declared = id; } - void display(std::ostream& strm, expr* n); void display_smt2(std::ostream& strm, expr* n); void display_expr_smt2(std::ostream& strm, expr* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); void display_ast_smt2(std::ostream& strm, ast* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 3f9438229..6fd876efc 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -1284,7 +1284,7 @@ void proof_checker::dump_proof(unsigned num_antecedents, expr * const * antecede pp.add_assumption(antecedents[i]); expr_ref n(m); n = m.mk_not(consequent); - pp.display(out, n); + pp.display_smt2(out, n); out.close(); m_proof_lemma_id++; } diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 67fe5a572..997698411 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -526,7 +526,7 @@ namespace smt { } } } - pp.display(out, m.mk_true()); + pp.display_smt2(out, m.mk_true()); } template From 09dc773658b5cd997e4fcdcdc0b8f922aec1a34e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Nov 2017 08:50:35 -0800 Subject: [PATCH 08/72] fix maxsat compilation for maxsat example Signed-off-by: Nikolaj Bjorner --- examples/maxsat/maxsat.c | 72 ++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/examples/maxsat/maxsat.c b/examples/maxsat/maxsat.c index a312e79ad..b5d8a6a8c 100644 --- a/examples/maxsat/maxsat.c +++ b/examples/maxsat/maxsat.c @@ -116,41 +116,6 @@ Z3_ast mk_binary_and(Z3_context ctx, Z3_ast in_1, Z3_ast in_2) } -/** - \brief Get hard constraints from a SMT-LIB file. We assume hard constraints - are formulas preceeded with the keyword :formula. - Return an array containing all formulas read by the last Z3_parse_smtlib_file invocation. - It will store the number of formulas in num_cnstrs. -*/ -Z3_ast * get_hard_constraints(Z3_context ctx, unsigned * num_cnstrs) -{ - Z3_ast * result; - unsigned i; - *num_cnstrs = Z3_get_smtlib_num_formulas(ctx); - result = (Z3_ast *) malloc(sizeof(Z3_ast) * (*num_cnstrs)); - for (i = 0; i < *num_cnstrs; i++) { - result[i] = Z3_get_smtlib_formula(ctx, i); - } - return result; -} - -/** - \brief Get soft constraints from a SMT-LIB file. We assume soft constraints - are formulas preceeded with the keyword :assumption. - Return an array containing all assumptions read by the last Z3_parse_smtlib_file invocation. - It will store the number of formulas in num_cnstrs. -*/ -Z3_ast * get_soft_constraints(Z3_context ctx, unsigned * num_cnstrs) -{ - Z3_ast * result; - unsigned i; - *num_cnstrs = Z3_get_smtlib_num_assumptions(ctx); - result = (Z3_ast *) malloc(sizeof(Z3_ast) * (*num_cnstrs)); - for (i = 0; i < *num_cnstrs; i++) { - result[i] = Z3_get_smtlib_assumption(ctx, i); - } - return result; -} /** \brief Free the given array of cnstrs that was allocated using get_hard_constraints or get_soft_constraints. @@ -610,14 +575,42 @@ int smtlib_maxsat(char * file_name, int approach) { Z3_context ctx; Z3_solver s; + unsigned i; + Z3_optimize opt; unsigned num_hard_cnstrs, num_soft_cnstrs; - Z3_ast * hard_cnstrs, * soft_cnstrs; + Z3_ast * hard_cnstrs, * soft_cnstrs, soft; + Z3_ast_vector hard, objs; unsigned result = 0; ctx = mk_context(); s = mk_solver(ctx); - Z3_parse_smtlib_file(ctx, file_name, 0, 0, 0, 0, 0, 0); - hard_cnstrs = get_hard_constraints(ctx, &num_hard_cnstrs); - soft_cnstrs = get_soft_constraints(ctx, &num_soft_cnstrs); + opt = Z3_mk_optimize(ctx); + Z3_optimize_inc_ref(ctx, opt); + Z3_optimize_from_file(ctx, opt, file_name); + hard = Z3_optimize_get_assertions(ctx, opt); + Z3_ast_vector_inc_ref(ctx, hard); + num_hard_cnstrs = Z3_ast_vector_size(ctx, hard); + hard_cnstrs = (Z3_ast *) malloc(sizeof(Z3_ast) * (num_hard_cnstrs)); + for (i = 0; i < num_hard_cnstrs; i++) { + hard_cnstrs[i] = Z3_ast_vector_get(ctx, hard, i); + } + objs = Z3_optimize_get_objectives(ctx, opt); + Z3_ast_vector_inc_ref(ctx, objs); + num_soft_cnstrs = 0; + soft = Z3_ast_vector_get(ctx, objs, 0); + while (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, soft))) == Z3_OP_ITE) { + ++num_soft_cnstrs; + soft = Z3_get_app_arg(ctx, Z3_to_app(ctx, soft), 1); + } + soft_cnstrs = (Z3_ast *) malloc(sizeof(Z3_ast) * (num_soft_cnstrs)); + num_soft_cnstrs = 0; + soft = Z3_ast_vector_get(ctx, objs, 0); + while (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, soft))) == Z3_OP_ITE) { + soft_cnstrs[num_soft_cnstrs] = Z3_get_app_arg(ctx, Z3_to_app(ctx, soft), 0); + ++num_soft_cnstrs; + soft = Z3_get_app_arg(ctx, Z3_to_app(ctx, soft), 1); + } + + // soft_cnstrs = get_soft_constraints(ctx, &num_soft_cnstrs); switch (approach) { case NAIVE_MAXSAT: result = naive_maxsat(ctx, s, num_hard_cnstrs, hard_cnstrs, num_soft_cnstrs, soft_cnstrs); @@ -633,6 +626,7 @@ int smtlib_maxsat(char * file_name, int approach) free_cnstr_array(hard_cnstrs); free_cnstr_array(soft_cnstrs); Z3_solver_dec_ref(ctx, s); + Z3_optimize_dec_ref(ctx, opt); return result; } From 0a67f6ee9b8593e70472af131a61a0ec24e35c98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Nov 2017 09:00:37 -0800 Subject: [PATCH 09/72] fix maxsat compilation for maxsat example Signed-off-by: Nikolaj Bjorner --- examples/maxsat/maxsat.c | 23 +++++++++-------------- src/api/z3_api.h | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/examples/maxsat/maxsat.c b/examples/maxsat/maxsat.c index b5d8a6a8c..5696f5b89 100644 --- a/examples/maxsat/maxsat.c +++ b/examples/maxsat/maxsat.c @@ -578,8 +578,9 @@ int smtlib_maxsat(char * file_name, int approach) unsigned i; Z3_optimize opt; unsigned num_hard_cnstrs, num_soft_cnstrs; - Z3_ast * hard_cnstrs, * soft_cnstrs, soft; + Z3_ast * hard_cnstrs, * soft_cnstrs; Z3_ast_vector hard, objs; + Z3_app soft; unsigned result = 0; ctx = mk_context(); s = mk_solver(ctx); @@ -595,22 +596,16 @@ int smtlib_maxsat(char * file_name, int approach) } objs = Z3_optimize_get_objectives(ctx, opt); Z3_ast_vector_inc_ref(ctx, objs); - num_soft_cnstrs = 0; - soft = Z3_ast_vector_get(ctx, objs, 0); - while (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, soft))) == Z3_OP_ITE) { - ++num_soft_cnstrs; - soft = Z3_get_app_arg(ctx, Z3_to_app(ctx, soft), 1); - } + + // soft constraints are stored in a single objective which is a sum + // of if-then-else expressions. + soft = Z3_to_app(ctx, Z3_ast_vector_get(ctx, objs, 0)); + num_soft_cnstrs = Z3_get_app_num_args(ctx, soft); soft_cnstrs = (Z3_ast *) malloc(sizeof(Z3_ast) * (num_soft_cnstrs)); - num_soft_cnstrs = 0; - soft = Z3_ast_vector_get(ctx, objs, 0); - while (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, soft))) == Z3_OP_ITE) { - soft_cnstrs[num_soft_cnstrs] = Z3_get_app_arg(ctx, Z3_to_app(ctx, soft), 0); - ++num_soft_cnstrs; - soft = Z3_get_app_arg(ctx, Z3_to_app(ctx, soft), 1); + for (i = 0; i < num_soft_cnstrs; ++i) { + soft_cnstrs[i] = Z3_get_app_arg(ctx, Z3_to_app(ctx, Z3_get_app_arg(ctx, soft, i)), 0); } - // soft_cnstrs = get_soft_constraints(ctx, &num_soft_cnstrs); switch (approach) { case NAIVE_MAXSAT: result = naive_maxsat(ctx, s, num_hard_cnstrs, hard_cnstrs, num_soft_cnstrs, soft_cnstrs); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7edcada37..d620254d1 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4299,7 +4299,7 @@ extern "C" { /** \brief Return the i-th argument of the given application. - \pre i < Z3_get_num_args(c, a) + \pre i < Z3_get_app_num_args(c, a) def_API('Z3_get_app_arg', AST, (_in(CONTEXT), _in(APP), _in(UINT))) */ From 9f567a62151e0dac1b4c19410a4b0593623b1cfc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Nov 2017 19:38:47 -0800 Subject: [PATCH 10/72] fix example file to be smt2 format Signed-off-by: Nikolaj Bjorner --- examples/maxsat/ex.smt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/maxsat/ex.smt b/examples/maxsat/ex.smt index 14ac0db89..d28b27c80 100644 --- a/examples/maxsat/ex.smt +++ b/examples/maxsat/ex.smt @@ -1,11 +1,11 @@ -(benchmark ex - :logic AUFLIA - :extrafuns ((x Int) (y Int) (z Int)) - :assumption (> x 0) - :assumption (<= x -1) - :assumption (or (> x 0) (< y 1)) - :assumption (> y 2) - :assumption (> y 3) - :assumption (<= y -1) - :formula (= z (+ x y))) +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(assert-soft (> x 0)) +(assert-soft (<= x -1)) +(assert-soft (or (> x 0) (< y 1))) +(assert-soft (> y 2)) +(assert-soft (> y 3)) +(assert-soft (<= y -1)) +(assert (= z (+ x y))) \ No newline at end of file From ab58723ffccefee813b8255d8a98a09ab4af607d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Nov 2017 20:52:19 -0800 Subject: [PATCH 11/72] fix dotnet example Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 64 ++++++-------------------------------- 1 file changed, 9 insertions(+), 55 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 64149a553..e5c863b0a 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -173,10 +173,9 @@ namespace test_mapi throw new Exception("function must be binary, and argument types must be equal to return type"); } - string bench = string.Format("(benchmark comm :formula (forall (x {0}) (y {1}) (= ({2} x y) ({3} y x))))", + string bench = string.Format("(assert (forall ((x {0}) (y {1})) (= ({2} x y) ({3} y x))))", t.Name, t.Name, f.Name, f.Name); - ctx.ParseSMTLIBString(bench, new Symbol[] { t.Name }, new Sort[] { t }, new Symbol[] { f.Name }, new FuncDecl[] { f }); - return ctx.SMTLIBFormulas[0]; + return ctx.ParseSMTLIB2String(bench, new Symbol[] { t.Name }, new Sort[] { t }, new Symbol[] { f.Name }, new FuncDecl[] { f }); } /// @@ -965,21 +964,6 @@ namespace test_mapi } } - /// - /// Shows how to read an SMT1 file. - /// - static void SMT1FileTest(string filename) - { - Console.Write("SMT File test "); - - using (Context ctx = new Context(new Dictionary() { { "MODEL", "true" } })) - { - ctx.ParseSMTLIBFile(filename); - - BoolExpr a = ctx.MkAnd(ctx.SMTLIBFormulas); - Console.WriteLine("read formula: " + a); - } - } /// /// Shows how to read an SMT2 file. @@ -1399,11 +1383,10 @@ namespace test_mapi { Console.WriteLine("ParserExample1"); - ctx.ParseSMTLIBString("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); - foreach (BoolExpr f in ctx.SMTLIBFormulas) - Console.WriteLine("formula {0}", f); + var fml = ctx.ParseSMTLIB2String("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); + Console.WriteLine("formula {0}", fml); - Model m = Check(ctx, ctx.MkAnd(ctx.SMTLIBFormulas), Status.SATISFIABLE); + Model m = Check(ctx, fml, Status.SATISFIABLE); } /// @@ -1412,15 +1395,11 @@ namespace test_mapi public static void ParserExample2(Context ctx) { Console.WriteLine("ParserExample2"); - Symbol[] declNames = { ctx.MkSymbol("a"), ctx.MkSymbol("b") }; FuncDecl a = ctx.MkConstDecl(declNames[0], ctx.MkIntSort()); FuncDecl b = ctx.MkConstDecl(declNames[1], ctx.MkIntSort()); FuncDecl[] decls = new FuncDecl[] { a, b }; - - ctx.ParseSMTLIBString("(benchmark tst :formula (> a b))", - null, null, declNames, decls); - BoolExpr f = ctx.SMTLIBFormulas[0]; + BoolExpr f = ctx.ParseSMTLIB2String("(assert (> a b))", null, null, declNames, decls); Console.WriteLine("formula: {0}", f); Check(ctx, f, Status.SATISFIABLE); } @@ -1438,39 +1417,15 @@ namespace test_mapi BoolExpr ca = CommAxiom(ctx, g); - ctx.ParseSMTLIBString("(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (gg x 0) (gg 0 y)))))", + BoolExpr thm = ctx.ParseSMTLIB2String("(assert (forall ((x Int) (y Int)) (implies (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.MkSymbol("gg") }, new FuncDecl[] { g }); - BoolExpr thm = ctx.SMTLIBFormulas[0]; Console.WriteLine("formula: {0}", thm); Prove(ctx, thm, false, ca); } - /// - /// Display the declarations, assumptions and formulas in a SMT-LIB string. - /// - public static void ParserExample4(Context ctx) - { - Console.WriteLine("ParserExample4"); - - ctx.ParseSMTLIBString - ("(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))"); - foreach (var decl in ctx.SMTLIBDecls) - { - Console.WriteLine("Declaration: {0}", decl); - } - foreach (var f in ctx.SMTLIBAssumptions) - { - Console.WriteLine("Assumption: {0}", f); - } - foreach (var f in ctx.SMTLIBFormulas) - { - Console.WriteLine("Formula: {0}", f); - } - } - /// /// Demonstrates how to handle parser errors using Z3 error handling support. /// @@ -1481,9 +1436,9 @@ namespace test_mapi try { - ctx.ParseSMTLIBString( + ctx.ParseSMTLIB2String( /* the following string has a parsing error: missing parenthesis */ - "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))"); + "(declare-const x Int (declare-const y Int)) (assert (> x y))"); } catch (Z3Exception e) { @@ -2213,7 +2168,6 @@ namespace test_mapi BitvectorExample2(ctx); ParserExample1(ctx); ParserExample2(ctx); - ParserExample4(ctx); ParserExample5(ctx); ITEExample(ctx); EvalExample1(ctx); From c18d60a9c5c618b0b6a408090f6b890693759741 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Nov 2017 20:56:36 -0800 Subject: [PATCH 12/72] fix java Signed-off-by: Nikolaj Bjorner --- examples/java/JavaExample.java | 65 ++++++---------------------------- 1 file changed, 10 insertions(+), 55 deletions(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 25076e27c..40fb25a92 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -170,10 +170,9 @@ class JavaExample String bench = "(benchmark comm :formula (forall (x " + t.getName() + ") (y " + t.getName() + ") (= (" + f.getName() + " x y) (" + f.getName() + " y x))))"; - ctx.parseSMTLIBString(bench, new Symbol[] { t.getName() }, + return ctx.parseSMTLIB2String(bench, new Symbol[] { t.getName() }, new Sort[] { t }, new Symbol[] { f.getName() }, new FuncDecl[] { f }); - return ctx.getSMTLIBFormulas()[0]; } // / "Hello world" example: create a Z3 logical context, and delete it. @@ -1028,21 +1027,6 @@ class JavaExample } } - // / Shows how to read an SMT1 file. - - void smt1FileTest(String filename) - { - System.out.print("SMT File test "); - - { - HashMap cfg = new HashMap(); - Context ctx = new Context(cfg); - ctx.parseSMTLIBFile(filename, null, null, null, null); - - BoolExpr a = ctx.mkAnd(ctx.getSMTLIBFormulas()); - System.out.println("read formula: " + a); - } - } // / Shows how to read an SMT2 file. @@ -1459,15 +1443,13 @@ class JavaExample System.out.println("ParserExample1"); Log.append("ParserExample1"); - ctx.parseSMTLIBString( - "(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))", + BoolExpr f = ctx.parseSMTLIB2String( + "(declare-const x Int) (declare-const y Int) (assert (and (> x y) (> x 0)))", null, null, null, null); - for (BoolExpr f : ctx.getSMTLIBFormulas()) - System.out.println("formula " + f); + System.out.println("formula " + f); @SuppressWarnings("unused") - Model m = check(ctx, ctx.mkAnd(ctx.getSMTLIBFormulas()), - Status.SATISFIABLE); + Model m = check(ctx, f, Status.SATISFIABLE); } // / Demonstrates how to initialize the parser symbol table. @@ -1482,9 +1464,8 @@ class JavaExample FuncDecl b = ctx.mkConstDecl(declNames[1], ctx.mkIntSort()); FuncDecl[] decls = new FuncDecl[] { a, b }; - ctx.parseSMTLIBString("(benchmark tst :formula (> a b))", null, null, + BoolExpr f = ctx.parseSMTLIB2String("(assert (> a b))", null, null, declNames, decls); - BoolExpr f = ctx.getSMTLIBFormulas()[0]; System.out.println("formula: " + f); check(ctx, f, Status.SATISFIABLE); } @@ -1502,39 +1483,14 @@ class JavaExample BoolExpr ca = commAxiom(ctx, g); - ctx.parseSMTLIBString( - "(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (gg x 0) (gg 0 y)))))", + BoolExpr thm = ctx.parseSMTLIB2String( + "(assert (forall ((x Int) (y Int)) (=> (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.mkSymbol("gg") }, new FuncDecl[] { g }); - - BoolExpr thm = ctx.getSMTLIBFormulas()[0]; System.out.println("formula: " + thm); prove(ctx, thm, false, ca); } - // / Display the declarations, assumptions and formulas in a SMT-LIB string. - - public void parserExample4(Context ctx) - { - System.out.println("ParserExample4"); - Log.append("ParserExample4"); - - ctx.parseSMTLIBString( - "(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))", - null, null, null, null); - for (FuncDecl decl : ctx.getSMTLIBDecls()) - { - System.out.println("Declaration: " + decl); - } - for (BoolExpr f : ctx.getSMTLIBAssumptions()) - { - System.out.println("Assumption: " + f); - } - for (BoolExpr f : ctx.getSMTLIBFormulas()) - { - System.out.println("Formula: " + f); - } - } // / Demonstrates how to handle parser errors using Z3 error handling // support. @@ -1546,12 +1502,12 @@ class JavaExample try { - ctx.parseSMTLIBString( + ctx.parseSMTLIB2String( /* * the following string has a parsing error: missing * parenthesis */ - "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", + "(declare-const x Int (declare-const y Int)) (assert (> x y))", null, null, null, null); } catch (Z3Exception e) { @@ -2341,7 +2297,6 @@ class JavaExample p.bitvectorExample2(ctx); p.parserExample1(ctx); p.parserExample2(ctx); - p.parserExample4(ctx); p.parserExample5(ctx); p.iteExample(ctx); p.evalExample1(ctx); From b96dacfff2247521564681df8fe2fb9a6b19bbe9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 30 Nov 2017 08:42:01 -0800 Subject: [PATCH 13/72] set version, fix build of test files Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- src/test/expr_rand.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0be2de537..871852c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 6) -set(Z3_VERSION_PATCH 1) +set(Z3_VERSION_PATCH 0) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8f75e97ed..60b3b7756 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 6, 1, 0) + set_version(4, 6, 0, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index f1b20ba8e..f04cfe74f 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -43,7 +43,7 @@ void tst_expr_arith(unsigned num_files) { buffer << "random_arith_" << i << ".smt"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); - pp.display(file, e.get()); + pp.display_smt2(file, e.get()); file.close(); } @@ -86,7 +86,7 @@ void tst_expr_rand(unsigned num_files) { buffer << "random_bv_" << i << ".smt"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); - pp.display(file, e.get()); + pp.display_smt2(file, e.get()); file.close(); } From 4bb0e9b6337fda57e114229f6cb482e67d6900da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 00:52:06 -0800 Subject: [PATCH 14/72] fix test build Signed-off-by: Nikolaj Bjorner --- src/test/expr_rand.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index f1b20ba8e..f04cfe74f 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -43,7 +43,7 @@ void tst_expr_arith(unsigned num_files) { buffer << "random_arith_" << i << ".smt"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); - pp.display(file, e.get()); + pp.display_smt2(file, e.get()); file.close(); } @@ -86,7 +86,7 @@ void tst_expr_rand(unsigned num_files) { buffer << "random_bv_" << i << ".smt"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); - pp.display(file, e.get()); + pp.display_smt2(file, e.get()); file.close(); } From c31ad147473c086ae82155823258dd34a5a031b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 00:52:32 -0800 Subject: [PATCH 15/72] fix test build Signed-off-by: Nikolaj Bjorner --- src/test/expr_rand.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index f04cfe74f..e52bfbc1a 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -40,7 +40,7 @@ void tst_expr_arith(unsigned num_files) { pp.set_logic(symbol("QF_AUFLIA")); std::ostringstream buffer; - buffer << "random_arith_" << i << ".smt"; + buffer << "random_arith_" << i << ".smt2"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); pp.display_smt2(file, e.get()); @@ -83,7 +83,7 @@ void tst_expr_rand(unsigned num_files) { pp.set_logic(symbol("QF_AUFBV")); std::ostringstream buffer; - buffer << "random_bv_" << i << ".smt"; + buffer << "random_bv_" << i << ".smt2"; std::cout << buffer.str() << "\n"; std::ofstream file(buffer.str().c_str()); pp.display_smt2(file, e.get()); From 8357210d3cd9f03bc29c3d87e0a12a29a020afe8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 01:07:41 -0800 Subject: [PATCH 16/72] fix lack of warning/error for unbounded objectives in context of quantifiers #1382 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 19 +++++++++++++++---- src/opt/opt_context.h | 3 ++- src/opt/optsmt.cpp | 8 ++++++++ src/opt/optsmt.h | 2 ++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8d73ea7c8..3d296d92b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -345,12 +345,24 @@ namespace opt { fix_model(mdl); } + bool context::contains_quantifiers() const { + for (expr* f : m_hard_constraints) { + if (has_quantifiers(f)) return true; + } + return false; + } + + 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, m_labels); if (scoped) get_solver().pop(1); if (result == l_true && committed) m_optsmt.commit_assignment(index); + if (result == l_true && m_optsmt.is_unbounded(index, is_max) && contains_quantifiers()) { + throw default_exception("unbounded objectives on quantified constraints is not supported"); + result = l_undef; + } return result; } @@ -646,8 +658,7 @@ namespace opt { expr_fast_mark1 visited; is_bv proc(m); try { - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective & obj = m_objectives[i]; + for (objective& obj : m_objectives) { if (obj.m_type != O_MAXSMT) return false; maxsmt& ms = *m_maxsmts.find(obj.m_id); for (unsigned j = 0; j < ms.size(); ++j) { @@ -658,8 +669,8 @@ namespace opt { for (unsigned i = 0; i < sz; i++) { quick_for_each_expr(proc, visited, get_solver().get_assertion(i)); } - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - quick_for_each_expr(proc, visited, m_hard_constraints[i].get()); + for (expr* f : m_hard_constraints) { + quick_for_each_expr(proc, visited, f); } } catch (is_bv::found) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index ad40db074..1ae60ef87 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -233,13 +233,14 @@ namespace opt { private: lbool execute(objective const& obj, bool committed, bool scoped); - lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max); + lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max); lbool execute_maxsat(symbol const& s, bool committed, bool scoped); lbool execute_lex(); lbool execute_box(); lbool execute_pareto(); lbool adjust_unknown(lbool r); bool scoped_lex(); + bool contains_quantifiers() const; expr_ref to_expr(inf_eps const& n); void to_exprs(inf_eps const& n, expr_ref_vector& es); diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index f8f75fbfd..3258cb33d 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -161,6 +161,14 @@ namespace opt { return l_true; } + bool optsmt::is_unbounded(unsigned obj_index, bool is_maximize) { + if (is_maximize) { + return !m_upper[obj_index].is_finite(); + } + else { + return !m_lower[obj_index].is_finite(); + } + } lbool optsmt::geometric_lex(unsigned obj_index, bool is_maximize) { arith_util arith(m); diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 921352898..93fa3f624 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -49,6 +49,8 @@ namespace opt { lbool lex(unsigned obj_index, bool is_maximize); + bool is_unbounded(unsigned obj_index, bool is_maximize); + unsigned add(app* t); void updt_params(params_ref& p); From a9ebda105c0bfe94242c0cf702655411e78a662a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 08:59:36 -0800 Subject: [PATCH 17/72] remove assertion that gets violated on exception path (declaration of datatypes are not getting removed) Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 3 +++ src/cmd_context/pdecl.cpp | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 035d032bc..a6846eb4d 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1138,8 +1138,11 @@ static void parse_example() { decls.push_back(c.function("a", 0, 0, B)); expr a = c.parse_string("(assert a)", sorts, decls); std::cout << a << "\n"; + + expr b = c.parse_string("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); } + int main() { try { diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 7eac1f347..8a7359e3a 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -852,8 +852,7 @@ pdecl_manager::pdecl_manager(ast_manager & m): pdecl_manager::~pdecl_manager() { dec_ref(m_list); reset_sort_info(); - SASSERT(m_sort2psort.empty()); - SASSERT(m_table.empty()); + SASSERT(m_sort2psort.empty()); } psort * pdecl_manager::mk_psort_cnst(sort * s) { @@ -865,6 +864,8 @@ psort * pdecl_manager::mk_psort_cnst(sort * s) { return r; } +static unsigned r_count = 0; + psort * pdecl_manager::register_psort(psort * n) { TRACE("register_psort", tout << "registering psort...\n"; n->display(tout); tout << "\n";); psort * r = m_table.insert_if_not_there(n); From 0bfea99cffc058424ca07f462b3067da50520a70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 14:43:52 -0800 Subject: [PATCH 18/72] fix issues found in parsing examples Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 2 +- examples/dotnet/Program.cs | 4 ++-- src/api/api_parsers.cpp | 8 ++++++-- src/cmd_context/pdecl.cpp | 1 + 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index a6846eb4d..df977268a 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1139,7 +1139,7 @@ static void parse_example() { expr a = c.parse_string("(assert a)", sorts, decls); std::cout << a << "\n"; - expr b = c.parse_string("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); + // expr b = c.parse_string("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); } diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index e5c863b0a..af3c59099 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -1383,7 +1383,7 @@ namespace test_mapi { Console.WriteLine("ParserExample1"); - var fml = ctx.ParseSMTLIB2String("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); + var fml = ctx.ParseSMTLIB2String("(declare-const x Int) (declare-const y Int) (assert (> x y)) (assert (> x 0))"); Console.WriteLine("formula {0}", fml); Model m = Check(ctx, fml, Status.SATISFIABLE); @@ -1417,7 +1417,7 @@ namespace test_mapi BoolExpr ca = CommAxiom(ctx, g); - BoolExpr thm = ctx.ParseSMTLIB2String("(assert (forall ((x Int) (y Int)) (implies (= x y) (= (gg x 0) (gg 0 y)))))", + BoolExpr thm = ctx.ParseSMTLIB2String("(assert (forall ((x Int) (y Int)) (=> (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.MkSymbol("gg") }, new FuncDecl[] { g }); diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index a7235ef65..d5a98672b 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -52,8 +52,12 @@ extern "C" { ctx->insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); } for (unsigned i = 0; i < num_sorts; ++i) { - psort* ps = ctx->pm().mk_psort_cnst(to_sort(sorts[i])); - ctx->insert(ctx->pm().mk_psort_user_decl(0, to_symbol(sort_names[i]), ps)); + sort* srt = to_sort(sorts[i]); + symbol name(to_symbol(sort_names[i])); + if (!ctx->find_psort_decl(name)) { + psort* ps = ctx->pm().mk_psort_cnst(srt); + ctx->insert(ctx->pm().mk_psort_user_decl(0, name, ps)); + } } std::stringstream errstrm; ctx->set_regular_stream(errstrm); diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 8a7359e3a..d1185544a 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -853,6 +853,7 @@ pdecl_manager::~pdecl_manager() { dec_ref(m_list); reset_sort_info(); SASSERT(m_sort2psort.empty()); + SASSERT(m_table.empty()); } psort * pdecl_manager::mk_psort_cnst(sort * s) { From 5ee30a3cd9d45f005058ad38180d48213ed535fa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Dec 2017 20:00:24 +0100 Subject: [PATCH 19/72] include special functionality in parsers for solvers and opt for additional file formats Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 42 ++++-- src/api/api_solver.cpp | 63 +++++++++ src/api/c++/z3++.h | 39 ++++++ src/api/dotnet/Params.cs | 34 +++-- src/api/dotnet/Solver.cs | 86 +++++++++++- src/api/java/Solver.java | 18 +++ src/api/python/z3/z3.py | 14 ++ src/api/z3_api.h | 14 ++ src/opt/CMakeLists.txt | 1 + src/shell/main.cpp | 14 +- src/shell/opt_frontend.cpp | 264 +------------------------------------ src/util/file_path.h | 38 ++++++ 12 files changed, 324 insertions(+), 303 deletions(-) create mode 100644 src/util/file_path.h diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index ac11e1a33..0d96a6719 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -16,17 +16,19 @@ Revision History: --*/ #include +#include "util/cancel_eh.h" +#include "util/file_path.h" +#include "util/scoped_timer.h" +#include "parsers/smt2/smt2parser.h" +#include "opt/opt_context.h" +#include "opt/opt_cmds.h" +#include "opt/opt_parse.h" #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_stats.h" #include "api/api_context.h" #include "api/api_util.h" #include "api/api_model.h" -#include "opt/opt_context.h" -#include "opt/opt_cmds.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" -#include "parsers/smt2/smt2parser.h" #include "api/api_ast_vector.h" extern "C" { @@ -281,16 +283,27 @@ extern "C" { static void Z3_optimize_from_stream( Z3_context c, Z3_optimize opt, - std::istream& s) { - ast_manager& m = mk_c(c)->m(); + std::istream& s, + char const* ext) { + ast_manager& m = mk_c(c)->m(); + if (ext && std::string("opb") == ext) { + unsigned_vector h; + parse_opb(*to_optimize_ptr(opt), s, h); + return; + } + if (ext && std::string("wcnf") == ext) { + unsigned_vector h; + parse_wcnf(*to_optimize_ptr(opt), s, h); + return; + } scoped_ptr ctx = alloc(cmd_context, false, &m); install_opt_cmds(*ctx.get(), to_optimize_ptr(opt)); - ctx->set_ignore_check(true); std::stringstream errstrm; ctx->set_regular_stream(errstrm); + ctx->set_ignore_check(true); try { if (!parse_smt2_commands(*ctx.get(), s)) { - mk_c(c)->m_parser_error_buffer = errstrm.str(); + mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); return; @@ -303,6 +316,7 @@ extern "C" { SET_ERROR_CODE(Z3_PARSER_ERROR); return; } + ptr_vector::const_iterator it = ctx->begin_assertions(); ptr_vector::const_iterator end = ctx->end_assertions(); for (; it != end; ++it) { @@ -310,6 +324,8 @@ extern "C" { } } + + void Z3_API Z3_optimize_from_string( Z3_context c, Z3_optimize d, @@ -318,7 +334,7 @@ extern "C" { //LOG_Z3_optimize_from_string(c, d, s); std::string str(s); std::istringstream is(str); - Z3_optimize_from_stream(c, d, is); + Z3_optimize_from_stream(c, d, is, nullptr); Z3_CATCH; } @@ -334,7 +350,7 @@ extern "C" { strm << "Could not open file " << s; throw default_exception(strm.str()); } - Z3_optimize_from_stream(c, d, is); + Z3_optimize_from_stream(c, d, is, get_extension(s)); Z3_CATCH; } @@ -347,8 +363,8 @@ extern "C" { mk_c(c)->save_object(v); expr_ref_vector hard(mk_c(c)->m()); to_optimize_ptr(o)->get_hard_constraints(hard); - for (unsigned i = 0; i < hard.size(); i++) { - v->m_ast_vector.push_back(hard[i].get()); + for (expr* h : hard) { + v->m_ast_vector.push_back(h); } RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 2030c5210..0a0039f4c 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -28,11 +28,17 @@ Revision History: #include "solver/tactic2solver.h" #include "util/scoped_ctrl_c.h" #include "util/cancel_eh.h" +#include "util/file_path.h" #include "util/scoped_timer.h" #include "tactic/portfolio/smt_strategic_solver.h" #include "smt/smt_solver.h" #include "smt/smt_implied_equalities.h" #include "solver/smt_logics.h" +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" +#include "sat/dimacs.h" +#include "sat/sat_solver.h" +#include "sat/tactic/goal2sat.h" extern "C" { @@ -121,6 +127,63 @@ extern "C" { Z3_CATCH_RETURN(0); } + void solver_from_stream(Z3_context c, Z3_solver s, std::istream& is) { + scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); + ctx->set_ignore_check(true); + + if (!parse_smt2_commands(*ctx.get(), is)) { + ctx = nullptr; + SET_ERROR_CODE(Z3_PARSER_ERROR); + return; + } + + bool initialized = to_solver(s)->m_solver.get() != 0; + if (!initialized) + init_solver(c, s); + ptr_vector::const_iterator it = ctx->begin_assertions(); + ptr_vector::const_iterator end = ctx->end_assertions(); + for (; it != end; ++it) { + to_solver_ref(s)->assert_expr(*it); + } + // to_solver_ref(s)->set_model_converter(ctx->get_model_converter()); + } + + void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string c_str) { + Z3_TRY; + LOG_Z3_solver_from_string(c, s, c_str); + std::string str(c_str); + std::istringstream is(str); + solver_from_stream(c, s, is); + Z3_CATCH; + } + + void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name) { + Z3_TRY; + LOG_Z3_solver_from_file(c, s, file_name); + char const* ext = get_extension(file_name); + std::ifstream is(file_name); + if (!is) { + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + } + else if (ext && std::string("dimacs") == ext) { + ast_manager& m = to_solver_ref(s)->get_manager(); + sat::solver solver(to_solver_ref(s)->get_params(), m.limit(), nullptr); + parse_dimacs(is, solver); + sat2goal s2g; + model_converter_ref mc; + atom2bool_var a2b(m); + goal g(m); + s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); + for (unsigned i = 0; i < g.size(); ++i) { + to_solver_ref(s)->assert_expr(g.form(i)); + } + } + else { + solver_from_stream(c, s, is); + } + Z3_CATCH; + } + 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/c++/z3++.h b/src/api/c++/z3++.h index 236750bdf..d8087c4ee 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1536,6 +1536,35 @@ namespace z3 { m_vector = s.m_vector; return *this; } + bool contains(T const& x) const { + for (auto y : *this) if (eq(x, y)) return true; + return false; + } + + class iterator { + ast_vector_tpl const* m_vector; + unsigned m_index; + public: + iterator(ast_vector_tpl const* v, unsigned i): m_vector(v), m_index(i) {} + iterator(iterator& other): m_vector(other.m_vector), m_index(other.m_index) {} + iterator operator=(iterator const& other) { m_vector = other.m_vector; m_index = other.m_index; return *this; } + + bool operator==(iterator const& other) { + return other.m_index == m_index; + }; + bool operator!=(iterator const& other) { + return other.m_index != m_index; + }; + iterator& operator++() { + ++m_index; + return *this; + } + iterator operator++(int) { iterator tmp = *this; ++m_index; return tmp; } + T * operator->() const { return &(operator*()); } + T operator*() const { return (*m_vector)[m_index]; } + }; + iterator begin() const { return iterator(this, 0); } + iterator end() const { return iterator(this, size()); } friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } }; @@ -1911,6 +1940,11 @@ namespace z3 { return *this; } void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); } + void set(char const * k, bool v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, unsigned v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, double v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, symbol const & v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, char const* v) { params p(ctx()); p.set(k, v); set(p); } void push() { Z3_solver_push(ctx(), m_solver); check_error(); } void pop(unsigned n = 1) { Z3_solver_pop(ctx(), m_solver, n); check_error(); } void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); } @@ -1923,6 +1957,10 @@ namespace z3 { void add(expr const & e, char const * p) { add(e, ctx().bool_const(p)); } + void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); ctx().check_parser_error(); } + void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); ctx().check_parser_error(); } + check_result check() { Z3_lbool r = Z3_solver_check(ctx(), m_solver); check_error(); return to_check_result(r); } check_result check(unsigned n, expr * const assumptions) { array _assumptions(n); @@ -2003,6 +2041,7 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } + void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs index 23b037c78..37d73d5b1 100644 --- a/src/api/dotnet/Params.cs +++ b/src/api/dotnet/Params.cs @@ -31,98 +31,108 @@ namespace Microsoft.Z3 /// /// Adds a parameter setting. /// - public void Add(Symbol name, bool value) + public Params Add(Symbol name, bool value) { Contract.Requires(name != null); Native.Z3_params_set_bool(Context.nCtx, NativeObject, name.NativeObject, (value) ? 1 : 0); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, uint value) + public Params Add(Symbol name, uint value) { Contract.Requires(name != null); Native.Z3_params_set_uint(Context.nCtx, NativeObject, name.NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, double value) + public Params Add(Symbol name, double value) { - Contract.Requires(name != null); - + Contract.Requires(name != null); + Native.Z3_params_set_double(Context.nCtx, NativeObject, name.NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, string value) + public Params Add(Symbol name, string value) { Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, Context.MkSymbol(value).NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, Symbol value) + public Params Add(Symbol name, Symbol value) { Contract.Requires(name != null); Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, value.NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, bool value) + public Params Add(string name, bool value) { Native.Z3_params_set_bool(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, (value) ? 1 : 0); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, uint value) + public Params Add(string name, uint value) { Native.Z3_params_set_uint(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, double value) + public Params Add(string name, double value) { Native.Z3_params_set_double(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, Symbol value) + public Params Add(string name, Symbol value) { Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value.NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, string value) + public Params Add(string name, string value) { Contract.Requires(name != null); Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, Context.MkSymbol(value).NativeObject); + return this; } /// diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index dff2677df..a176e790b 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -57,6 +57,49 @@ namespace Microsoft.Z3 } } + /// + /// Sets parameter on the solver + /// + public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + + + /// /// Retrieves parameter descriptions for solver. /// @@ -140,11 +183,11 @@ namespace Microsoft.Z3 /// using the Boolean constants in ps. /// /// - /// This API is an alternative to with assumptions for extracting unsat cores. + /// This API is an alternative to with assumptions for extracting unsat cores. /// Both APIs can be used in the same solver. The unsat core will contain a combination /// of the Boolean variables provided using /// and the Boolean literals - /// provided using with assumptions. + /// provided using with assumptions. /// public void AssertAndTrack(BoolExpr[] constraints, BoolExpr[] ps) { @@ -165,11 +208,11 @@ namespace Microsoft.Z3 /// using the Boolean constant p. /// /// - /// This API is an alternative to with assumptions for extracting unsat cores. + /// This API is an alternative to with assumptions for extracting unsat cores. /// Both APIs can be used in the same solver. The unsat core will contain a combination /// of the Boolean variables provided using /// and the Boolean literals - /// provided using with assumptions. + /// provided using with assumptions. /// public void AssertAndTrack(BoolExpr constraint, BoolExpr p) { @@ -181,6 +224,22 @@ namespace Microsoft.Z3 Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraint.NativeObject, p.NativeObject); } + /// + /// Load solver assertions from a file. + /// + public void FromFile(string file) + { + Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); + } + + /// + /// Load solver assertions from a string. + /// + public void FromString(string str) + { + Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); + } + /// /// The number of assertions in the solver. /// @@ -225,6 +284,25 @@ namespace Microsoft.Z3 return lboolToStatus(r); } + /// + /// Checks whether the assertions in the solver are consistent or not. + /// + /// + /// + /// + /// + /// + public Status Check(IEnumerable assumptions) + { + Z3_lbool r; + BoolExpr[] asms = assumptions.ToArray(); + if (asms.Length == 0) + r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); + else + r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)asms.Length, AST.ArrayToNative(asms)); + return lboolToStatus(r); + } + /// /// Retrieve fixed assignments to the set of variables in the form of consequences. /// Each consequence is an implication of the form diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index 19f3b01da..5bd4e65ba 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -1,3 +1,4 @@ + /** Copyright (c) 2012-2014 Microsoft Corporation @@ -120,6 +121,23 @@ public class Solver extends Z3Object { } } + /** + * Load solver assertions from a file. + */ + public void fromFile(String file) + { + Native.solverFromFile(getContext().nCtx(), getNativeObject(), file); + } + + /** + * Load solver assertions from a string. + */ + public void fromString(String str) + { + Native.solverFromString(getContext().nCtx(), getNativeObject(), str); + } + + /** * Assert multiple constraints into the solver, and track them (in the * unsat) core diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 2304491c8..237f35433 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6324,6 +6324,20 @@ class Solver(Z3PPObject): sz = len(consequences) consequences = [ consequences[i] for i in range(sz) ] return CheckSatResult(r), consequences + + def from_file(self, filename): + """Parse assertions from a file""" + try: + Z3_solver_from_file(self.ctx.ref(), self.solver, filename) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) + + def from_string(self, s): + """Parse assertions from a string""" + try: + Z3_solver_from_string(self.ctx.ref(), self.solver, s) + except Z3Exception as e: + _handle_parse_error(e, self.ctx) def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d620254d1..064476b9b 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6038,6 +6038,20 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s); + /** + \brief load solver assertions from a file. + + def_API('Z3_solver_from_file', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) + */ + void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name); + + /** + \brief load solver assertions from a string. + + def_API('Z3_solver_from_string', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) + */ + void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string file_name); + /** \brief Check whether the assertions in a given solver are consistent or not. diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index 05a62b6c2..28a14be2e 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(opt opt_cmds.cpp opt_context.cpp opt_pareto.cpp + opt_parse.cpp optsmt.cpp opt_solver.cpp pb_sls.cpp diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 8b719681c..f0e640d66 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -35,6 +35,7 @@ Revision History: #include "util/error_codes.h" #include "util/gparams.h" #include "util/env_params.h" +#include "util/file_path.h" #include "shell/lp_frontend.h" typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; @@ -286,19 +287,6 @@ void parse_cmd_line_args(int argc, char ** argv) { } } -char const * get_extension(char const * file_name) { - if (file_name == 0) - return 0; - char const * last_dot = 0; - for (;;) { - char const * tmp = strchr(file_name, '.'); - if (tmp == 0) { - return last_dot; - } - last_dot = tmp + 1; - file_name = last_dot; - } -} int STD_CALL main(int argc, char ** argv) { try{ diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index e1aff8669..8154cbde4 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -13,6 +13,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/gparams.h" #include "util/timeout.h" #include "ast/reg_decl_plugins.h" +#include "opt/opt_parse.h" extern bool g_display_statistics; static bool g_first_interrupt = true; @@ -20,262 +21,6 @@ static opt::context* g_opt = 0; static double g_start_time = 0; static unsigned_vector g_handles; -class opt_stream_buffer { - std::istream & m_stream; - int m_val; - unsigned m_line; -public: - opt_stream_buffer(std::istream & s): - m_stream(s), - m_line(0) { - m_val = m_stream.get(); - } - int operator *() const { return m_val;} - void operator ++() { m_val = m_stream.get(); } - int ch() const { return m_val; } - void next() { m_val = m_stream.get(); } - bool eof() const { return ch() == EOF; } - unsigned line() const { return m_line; } - void skip_whitespace() { - while ((ch() >= 9 && ch() <= 13) || ch() == 32) { - if (ch() == 10) ++m_line; - next(); - } - } - void skip_space() { - while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) { - next(); - } - } - void skip_line() { - while(true) { - if (eof()) { - return; - } - if (ch() == '\n') { - ++m_line; - next(); - return; - } - next(); - } - } - - bool parse_token(char const* token) { - skip_whitespace(); - char const* t = token; - while (ch() == *t) { - next(); - ++t; - } - return 0 == *t; - } - - int parse_int() { - int val = 0; - bool neg = false; - skip_whitespace(); - - if (ch() == '-') { - neg = true; - next(); - } - else if (ch() == '+') { - next(); - } - if (ch() < '0' || ch() > '9') { - std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\" )\n"; - exit(3); - } - while (ch() >= '0' && ch() <= '9') { - val = val*10 + (ch() - '0'); - next(); - } - return neg ? -val : val; - } - - unsigned parse_unsigned() { - skip_space(); - if (ch() == '\n') { - return UINT_MAX; - } - unsigned val = 0; - while (ch() >= '0' && ch() <= '9') { - val = val*10 + (ch() - '0'); - next(); - } - return val; - } -}; - -class wcnf { - opt::context& opt; - ast_manager& m; - opt_stream_buffer& in; - - app_ref read_clause(unsigned& weight) { - int parsed_lit; - int var; - weight = in.parse_unsigned(); - app_ref result(m), p(m); - expr_ref_vector ors(m); - while (true) { - parsed_lit = in.parse_int(); - if (parsed_lit == 0) - break; - var = abs(parsed_lit); - p = m.mk_const(symbol(var), m.mk_bool_sort()); - if (parsed_lit < 0) p = m.mk_not(p); - ors.push_back(p); - } - result = to_app(mk_or(m, ors.size(), ors.c_ptr())); - return result; - } - - void parse_spec(unsigned& num_vars, unsigned& num_clauses, unsigned& max_weight) { - in.parse_token("wcnf"); - num_vars = in.parse_unsigned(); - num_clauses = in.parse_unsigned(); - max_weight = in.parse_unsigned(); - } - -public: - - wcnf(opt::context& opt, opt_stream_buffer& in): opt(opt), m(opt.get_manager()), in(in) { - opt.set_clausal(true); - } - - void parse() { - unsigned num_vars = 0, num_clauses = 0, max_weight = 0; - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == 'c') { - in.skip_line(); - } - else if (*in == 'p') { - ++in; - parse_spec(num_vars, num_clauses, max_weight); - } - else { - unsigned weight = 0; - app_ref cls = read_clause(weight); - if (weight >= max_weight) { - opt.add_hard_constraint(cls); - } - else { - unsigned id = opt.add_soft_constraint(cls, rational(weight), symbol::null); - if (g_handles.empty()) { - g_handles.push_back(id); - } - } - } - } - } -}; - - -class opb { - opt::context& opt; - ast_manager& m; - opt_stream_buffer& in; - arith_util arith; - - app_ref parse_id() { - bool negated = in.parse_token("~"); - if (!in.parse_token("x")) { - std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\")\n"; - exit(3); - } - app_ref p(m); - int id = in.parse_int(); - p = m.mk_const(symbol(id), m.mk_bool_sort()); - if (negated) p = m.mk_not(p); - in.skip_whitespace(); - return p; - } - - app_ref parse_ids() { - app_ref result = parse_id(); - while (*in == '~' || *in == 'x') { - result = m.mk_and(result, parse_id()); - } - return result; - } - - rational parse_coeff_r() { - in.skip_whitespace(); - svector num; - bool pos = true; - if (*in == '-') pos = false, ++in; - if (*in == '+') ++in; - if (!pos) num.push_back('-'); - in.skip_whitespace(); - while ('0' <= *in && *in <='9') num.push_back(*in), ++in; - num.push_back(0); - return rational(num.c_ptr()); - } - - app_ref parse_coeff() { - return app_ref(arith.mk_numeral(parse_coeff_r(), true), m); - } - - app_ref parse_term() { - app_ref c = parse_coeff(); - app_ref e = parse_ids(); - return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); - } - - void parse_objective() { - app_ref t = parse_term(); - while (!in.parse_token(";") && !in.eof()) { - t = arith.mk_add(t, parse_term()); - } - g_handles.push_back(opt.add_objective(t, false)); - } - - void parse_constraint() { - app_ref t = parse_term(); - while (!in.eof()) { - if (in.parse_token(">=")) { - t = arith.mk_ge(t, parse_coeff()); - in.parse_token(";"); - break; - } - if (in.parse_token("=")) { - t = m.mk_eq(t, parse_coeff()); - in.parse_token(";"); - break; - } - t = arith.mk_add(t, parse_term()); - } - opt.add_hard_constraint(t); - } -public: - opb(opt::context& opt, opt_stream_buffer& in): - opt(opt), m(opt.get_manager()), - in(in), arith(m) {} - - void parse() { - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == '*') { - in.skip_line(); - } - else if (in.parse_token("min:")) { - parse_objective(); - } - else { - parse_constraint(); - } - } - } -}; static void display_results() { @@ -335,14 +80,11 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { g_opt = &opt; params_ref p = gparams::get_module("opt"); opt.updt_params(p); - opt_stream_buffer _in(in); if (is_wcnf) { - wcnf wcnf(opt, _in); - wcnf.parse(); + parse_wcnf(opt, in, g_handles); } else { - opb opb(opt, _in); - opb.parse(); + parse_opb(opt, in, g_handles); } try { lbool r = opt.optimize(); diff --git a/src/util/file_path.h b/src/util/file_path.h new file mode 100644 index 000000000..8a2d053d8 --- /dev/null +++ b/src/util/file_path.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + file_path.h + +Abstract: + + File path functions. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#ifndef FILE_PATH_H_ +#define FILE_PATH_H_ + +inline char const * get_extension(char const * file_name) { + if (file_name == 0) + return 0; + char const * last_dot = 0; + for (;;) { + char const * tmp = strchr(file_name, '.'); + if (tmp == 0) { + return last_dot; + } + last_dot = tmp + 1; + file_name = last_dot; + } +} + +#endif /* FILE_PATH_H_ */ + + From a83af22841afb848eb0c339b2878eded602baf6b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Dec 2017 20:00:45 +0100 Subject: [PATCH 20/72] include special functionality in parsers for solvers and opt for additional file formats Signed-off-by: Nikolaj Bjorner --- src/opt/opt_parse.cpp | 317 ++++++++++++++++++++++++++++++++++++++++++ src/opt/opt_parse.h | 28 ++++ 2 files changed, 345 insertions(+) create mode 100644 src/opt/opt_parse.cpp create mode 100644 src/opt/opt_parse.h diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp new file mode 100644 index 000000000..2cba7561f --- /dev/null +++ b/src/opt/opt_parse.cpp @@ -0,0 +1,317 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + opt_parse.cpp + +Abstract: + + Parse utilities for optimization. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#include "opt/opt_context.h" +#include "opt/opt_parse.h" + + +class opt_stream_buffer { + std::istream & m_stream; + int m_val; + unsigned m_line; +public: + opt_stream_buffer(std::istream & s): + m_stream(s), + m_line(0) { + m_val = m_stream.get(); + } + int operator *() const { return m_val;} + void operator ++() { m_val = m_stream.get(); } + int ch() const { return m_val; } + void next() { m_val = m_stream.get(); } + bool eof() const { return ch() == EOF; } + unsigned line() const { return m_line; } + void skip_whitespace(); + void skip_space(); + void skip_line(); + bool parse_token(char const* token); + int parse_int(); + unsigned parse_unsigned(); +}; + + +void opt_stream_buffer::skip_whitespace() { + while ((ch() >= 9 && ch() <= 13) || ch() == 32) { + if (ch() == 10) ++m_line; + next(); + } +} + +void opt_stream_buffer::skip_space() { + while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) { + next(); + } +} +void opt_stream_buffer::skip_line() { + while(true) { + if (eof()) { + return; + } + if (ch() == '\n') { + ++m_line; + next(); + return; + } + next(); + } +} + +bool opt_stream_buffer::parse_token(char const* token) { + skip_whitespace(); + char const* t = token; + while (ch() == *t) { + next(); + ++t; + } + return 0 == *t; +} + +unsigned opt_stream_buffer::parse_unsigned() { + skip_space(); + if (ch() == '\n') { + return UINT_MAX; + } + unsigned val = 0; + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + return val; +} + +int opt_stream_buffer::parse_int() { + int val = 0; + bool neg = false; + skip_whitespace(); + + if (ch() == '-') { + neg = true; + next(); + } + else if (ch() == '+') { + next(); + } + if (ch() < '0' || ch() > '9') { + std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\" )\n"; + exit(3); + } + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + return neg ? -val : val; +} + + +class wcnf { + opt::context& opt; + ast_manager& m; + opt_stream_buffer& in; + unsigned_vector& m_handles; + + app_ref read_clause(unsigned& weight) { + int parsed_lit; + int var; + weight = in.parse_unsigned(); + app_ref result(m), p(m); + expr_ref_vector ors(m); + while (true) { + parsed_lit = in.parse_int(); + if (parsed_lit == 0) + break; + var = abs(parsed_lit); + p = m.mk_const(symbol(var), m.mk_bool_sort()); + if (parsed_lit < 0) p = m.mk_not(p); + ors.push_back(p); + } + result = to_app(mk_or(m, ors.size(), ors.c_ptr())); + return result; + } + + void parse_spec(unsigned& num_vars, unsigned& num_clauses, unsigned& max_weight) { + in.parse_token("wcnf"); + num_vars = in.parse_unsigned(); + num_clauses = in.parse_unsigned(); + max_weight = in.parse_unsigned(); + } + +public: + + wcnf(opt::context& opt, opt_stream_buffer& in, unsigned_vector& h): opt(opt), m(opt.get_manager()), in(in), m_handles(h) { + opt.set_clausal(true); + } + + void parse() { + unsigned num_vars = 0, num_clauses = 0, max_weight = 0; + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == 'c') { + in.skip_line(); + } + else if (*in == 'p') { + ++in; + parse_spec(num_vars, num_clauses, max_weight); + } + else { + unsigned weight = 0; + app_ref cls = read_clause(weight); + if (weight >= max_weight) { + opt.add_hard_constraint(cls); + } + else { + unsigned id = opt.add_soft_constraint(cls, rational(weight), symbol::null); + if (m_handles.empty()) { + m_handles.push_back(id); + } + } + } + } + } +}; + + +class opb { + opt::context& opt; + ast_manager& m; + opt_stream_buffer& in; + unsigned_vector& m_handles; + arith_util arith; + + app_ref parse_id() { + bool negated = in.parse_token("~"); + if (!in.parse_token("x")) { + std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\" expected \"x\")\n"; + exit(3); + } + app_ref p(m); + int id = in.parse_int(); + p = m.mk_const(symbol(id), m.mk_bool_sort()); + if (negated) p = m.mk_not(p); + in.skip_whitespace(); + return p; + } + + app_ref parse_ids() { + app_ref result = parse_id(); + while (*in == '~' || *in == 'x') { + result = m.mk_and(result, parse_id()); + } + return result; + } + + rational parse_coeff_r() { + in.skip_whitespace(); + svector num; + bool pos = true; + if (*in == '-') pos = false, ++in; + if (*in == '+') ++in; + if (!pos) num.push_back('-'); + in.skip_whitespace(); + while ('0' <= *in && *in <='9') num.push_back(*in), ++in; + num.push_back(0); + return rational(num.c_ptr()); + } + + app_ref parse_coeff() { + return app_ref(arith.mk_numeral(parse_coeff_r(), true), m); + } + + app_ref parse_term() { + app_ref c = parse_coeff(); + app_ref e = parse_ids(); + return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); + } + + void parse_objective(bool is_min) { + app_ref t = parse_term(); + while (!in.parse_token(";") && !in.eof()) { + if (is_min) { + t = arith.mk_add(t, parse_term()); + } + else { + t = arith.mk_sub(t, parse_term()); + } + } + m_handles.push_back(opt.add_objective(t, false)); + } + + void parse_constraint() { + app_ref t = parse_term(); + while (!in.eof()) { + if (in.parse_token(">=")) { + t = arith.mk_ge(t, parse_coeff()); + in.parse_token(";"); + break; + } + if (in.parse_token("=")) { + t = m.mk_eq(t, parse_coeff()); + in.parse_token(";"); + break; + } + if (in.parse_token("<=")) { + t = arith.mk_le(t, parse_coeff()); + in.parse_token(";"); + break; + } + t = arith.mk_add(t, parse_term()); + } + opt.add_hard_constraint(t); + } +public: + opb(opt::context& opt, opt_stream_buffer& in, unsigned_vector& h): + opt(opt), m(opt.get_manager()), + in(in), m_handles(h), arith(m) {} + + void parse() { + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == '*') { + in.skip_line(); + } + else if (in.parse_token("min:")) { + parse_objective(true); + } + else if (in.parse_token("max:")) { + parse_objective(false); + } + else { + parse_constraint(); + } + } + } +}; + +void parse_wcnf(opt::context& opt, std::istream& is, unsigned_vector& h) { + opt_stream_buffer _is(is); + wcnf w(opt, _is, h); + w.parse(); +} + +void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h) { + opt_stream_buffer _is(is); + opb opb(opt, _is, h); + opb.parse(); +} + + diff --git a/src/opt/opt_parse.h b/src/opt/opt_parse.h new file mode 100644 index 000000000..b058efcac --- /dev/null +++ b/src/opt/opt_parse.h @@ -0,0 +1,28 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + opt_parse.h + +Abstract: + + Parse utilities for optimization. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#ifndef OPT_PARSE_H_ +#define OPT_PARSE_H_ + +void parse_wcnf(opt::context& opt, std::istream& is, unsigned_vector& h); + +void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h); + +#endif /* OPT_PARSE_H_ */ + + From fb470a1868f3990b9c2220a0b482ee4642f1e796 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Dec 2017 15:32:20 +0530 Subject: [PATCH 21/72] include path Signed-off-by: Nikolaj Bjorner --- src/util/file_path.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/file_path.h b/src/util/file_path.h index 8a2d053d8..c34c8b408 100644 --- a/src/util/file_path.h +++ b/src/util/file_path.h @@ -18,6 +18,7 @@ Revision History: --*/ #ifndef FILE_PATH_H_ #define FILE_PATH_H_ +#include inline char const * get_extension(char const * file_name) { if (file_name == 0) From 5f8c97532ce6eb8b26c66a18caca53bd8596680c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Dec 2017 18:10:48 +0530 Subject: [PATCH 22/72] circumvent build errors introduced when using the ast_vector_tpl iterator Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index d8087c4ee..03fdfc39d 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1537,7 +1537,7 @@ namespace z3 { return *this; } bool contains(T const& x) const { - for (auto y : *this) if (eq(x, y)) return true; + for (T y : *this) if (eq(x, y)) return true; return false; } @@ -1957,7 +1957,8 @@ namespace z3 { void add(expr const & e, char const * p) { add(e, ctx().bool_const(p)); } - void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + // fails for some compilers: + // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); ctx().check_parser_error(); } void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); ctx().check_parser_error(); } @@ -2041,7 +2042,8 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } - void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + // fails for some compilers: + // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } From 60af4a5820e05391096aacb92c9a9ca3675a7753 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Dec 2017 19:12:51 +0530 Subject: [PATCH 23/72] deal with ambiguity Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index af3c59099..71364013b 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -1945,7 +1945,7 @@ namespace test_mapi BoolExpr p2 = ctx.MkBoolConst("P2"); BoolExpr p3 = ctx.MkBoolConst("P3"); BoolExpr p4 = ctx.MkBoolConst("P4"); - BoolExpr[] assumptions = new BoolExpr[] { ctx.MkNot(p1), ctx.MkNot(p2), ctx.MkNot(p3), ctx.MkNot(p4) }; + Expr[] assumptions = new Expr[] { ctx.MkNot(p1), ctx.MkNot(p2), ctx.MkNot(p3), ctx.MkNot(p4) }; BoolExpr f1 = ctx.MkAnd(new BoolExpr[] { pa, pb, pc }); BoolExpr f2 = ctx.MkAnd(new BoolExpr[] { pa, ctx.MkNot(pb), pc }); BoolExpr f3 = ctx.MkOr(ctx.MkNot(pa), ctx.MkNot(pc)); From 2770c8f884c292c480804a074c18c23c77fc5b79 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Dec 2017 08:15:23 +0530 Subject: [PATCH 24/72] disable C++11 dependency to fix the travis build Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 03fdfc39d..8ff2be239 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1536,10 +1536,13 @@ namespace z3 { m_vector = s.m_vector; return *this; } + /* + Disabled pending C++98 build upgrade bool contains(T const& x) const { for (T y : *this) if (eq(x, y)) return true; return false; } + */ class iterator { ast_vector_tpl const* m_vector; From 39d1ad3edb51e9d50788aa6c0533c741e81d9a28 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Dec 2017 05:15:53 +0530 Subject: [PATCH 25/72] fix #1390 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 5 +++-- src/cmd_context/pdecl.cpp | 2 -- src/parsers/smt2/smt2parser.cpp | 10 +++++++--- src/smt/theory_seq.cpp | 1 - 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 73fb2c212..23ac62a66 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -111,9 +111,10 @@ namespace api { m_last_obj = 0; u_map::iterator it = m_allocated_objects.begin(); while (it != m_allocated_objects.end()) { - DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", it->m_key, typeid(*it->m_value).name());); + api::object* val = it->m_value; + DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", it->m_key, typeid(*val).name());); m_allocated_objects.remove(it->m_key); - dealloc(it->m_value); + dealloc(val); it = m_allocated_objects.begin(); } } diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index d1185544a..f75fbfa29 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -865,8 +865,6 @@ psort * pdecl_manager::mk_psort_cnst(sort * s) { return r; } -static unsigned r_count = 0; - psort * pdecl_manager::register_psort(psort * n) { TRACE("register_psort", tout << "registering psort...\n"; n->display(tout); tout << "\n";); psort * r = m_table.insert_if_not_there(n); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index fd592f7c7..a06438c73 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -867,7 +867,7 @@ namespace smt2 { throw parser_exception("invalid datatype declaration, too many data-type bodies defined"); } symbol dt_name = m_dt_names[i]; - parse_datatype_dec(new_ct_decls); + parse_datatype_dec(nullptr, new_ct_decls); d = pm().mk_pdatatype_decl(m_dt_name2arity.find(dt_name), dt_name, new_ct_decls.size(), new_ct_decls.c_ptr()); } else { @@ -942,7 +942,7 @@ namespace smt2 { pdatatype_decl_ref d(pm()); pconstructor_decl_ref_buffer new_ct_decls(pm()); - parse_datatype_dec(new_ct_decls); + parse_datatype_dec(&dt_name, new_ct_decls); d = pm().mk_pdatatype_decl(m_sort_id2param_idx.size(), dt_name, new_ct_decls.size(), new_ct_decls.c_ptr()); check_missing(d, line, pos); @@ -956,12 +956,16 @@ namespace smt2 { // datatype_dec ::= ( constructor_dec+ ) | ( par ( symbol+ ) ( constructor_dec+ ) ) - void parse_datatype_dec(pconstructor_decl_ref_buffer & ct_decls) { + void parse_datatype_dec(symbol* dt_name, pconstructor_decl_ref_buffer & ct_decls) { check_lparen_next("invalid datatype declaration, '(' expected"); if (curr_id() == m_par) { next(); parse_sort_decl_params(); check_lparen_next("invalid constructor declaration after par, '(' expected"); + unsigned sz = m_sort_id2param_idx.size(); + if (sz > 0 && dt_name) { + m_ctx.insert(pm().mk_psort_dt_decl(sz, *dt_name)); + } parse_constructor_decls(ct_decls); check_rparen_next("invalid datatype declaration, ')' expected"); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ca6ab048c..9830a16b4 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3661,7 +3661,6 @@ void theory_seq::add_extract_axiom(expr* e) { literal ls_le_i = mk_simplified_literal(m_autil.mk_le(mk_sub(i, ls), zero)); literal li_ge_ls = mk_simplified_literal(m_autil.mk_ge(ls_minus_i_l, zero)); literal l_ge_zero = mk_simplified_literal(m_autil.mk_ge(l, zero)); - literal l_le_zero = mk_simplified_literal(m_autil.mk_le(l, zero)); literal ls_le_0 = mk_simplified_literal(m_autil.mk_le(ls, zero)); add_axiom(~i_ge_0, ~ls_le_i, mk_seq_eq(xey, s)); From 92059942e63b4605e1434dd70a49829420be7d18 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Thu, 7 Dec 2017 00:48:20 +0000 Subject: [PATCH 26/72] [CMake] Use C++11 when building C++ API example. This is a change requested by @NikolajBjorner ( https://github.com/Z3Prover/z3/commit/5f8c97532ce6eb8b26c66a18caca53bd8596680c#commitcomment-26049417 ). --- examples/c++/CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index d60604924..0a41d6a93 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -13,6 +13,22 @@ find_package(Z3 # use this option. NO_DEFAULT_PATH ) + +################################################################################ +# Z3 C++ API bindings require C++11 +################################################################################ +if ("${CMAKE_VERSION}" VERSION_LESS "3.1") + # Legacy CMake support + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + else() + message(FATAL_ERROR "Setting C++ version to C++11 not supported for \"${CMAKE_CXX_COMPILER_ID}\"") + endif() +else () + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif () + message(STATUS "Z3_FOUND: ${Z3_FOUND}") message(STATUS "Found Z3 ${Z3_VERSION_STRING}") message(STATUS "Z3_DIR: ${Z3_DIR}") From 1941a539996f32e4dcb6add072b9db6cca971915 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Thu, 7 Dec 2017 00:53:54 +0000 Subject: [PATCH 27/72] [Release Notes] Note that C++11 is required to build Z3 and is also required by the C++ API bindings. --- RELEASE_NOTES | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index ec05160da..e85e3d8d6 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,7 +1,11 @@ RELEASE NOTES -Version 4.5.x +Version 4.6.0 ============= +- New requirements: + - C++11 capable compiler to build Z3. + - C++ API now requires C++11 or newer. + - New features (including): - A new string solver from University of Waterloo - A new linear real arithmetic solver From 8e1ab23c3d976030487adcb52bc4136e5b83fbfb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Dec 2017 18:43:29 +0530 Subject: [PATCH 28/72] remove deprecated functions from ML API. #1393 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 50 ----------------------------------------------- src/api/ml/z3.mli | 37 ----------------------------------- 2 files changed, 87 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 46fe5bd6d..ce305bb4e 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1975,56 +1975,6 @@ struct (List.length assumptions) assumptions formula - let parse_smtlib_string (ctx:context) (str:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = - let csn = List.length sort_names in - let cs = List.length sorts in - let cdn = List.length decl_names in - let cd = List.length decls in - if (csn <> cs || cdn <> cd) then - raise (Error "Argument size mismatch") - else - Z3native.parse_smtlib_string ctx str - cs sort_names sorts cd decl_names decls - - let parse_smtlib_file (ctx:context) (file_name:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = - let csn = (List.length sort_names) in - let cs = (List.length sorts) in - let cdn = (List.length decl_names) in - let cd = (List.length decls) in - if (csn <> cs || cdn <> cd) then - raise (Error "Argument size mismatch") - else - Z3native.parse_smtlib_file ctx file_name - cs sort_names sorts cd decl_names decls - - let get_num_smtlib_formulas (ctx:context) = Z3native.get_smtlib_num_formulas ctx - - let get_smtlib_formulas (ctx:context) = - let n = get_num_smtlib_formulas ctx in - let f i = Z3native.get_smtlib_formula ctx i in - mk_list f n - - let get_num_smtlib_assumptions (ctx:context) = Z3native.get_smtlib_num_assumptions ctx - - let get_smtlib_assumptions (ctx:context) = - let n = get_num_smtlib_assumptions ctx in - let f i = Z3native.get_smtlib_assumption ctx i in - mk_list f n - - let get_num_smtlib_decls (ctx:context) = Z3native.get_smtlib_num_decls ctx - - let get_smtlib_decls (ctx:context) = - let n = get_num_smtlib_decls ctx in - let f i = Z3native.get_smtlib_decl ctx i in - mk_list f n - - let get_num_smtlib_sorts (ctx:context) = Z3native.get_smtlib_num_sorts ctx - - let get_smtlib_sorts (ctx:context) = - let n = get_num_smtlib_sorts ctx in - let f i = Z3native.get_smtlib_sort ctx i in - mk_list f n - let parse_smtlib2_string (ctx:context) (str:string) (sort_names:Symbol.symbol list) (sorts:Sort.sort list) (decl_names:Symbol.symbol list) (decls:func_decl list) = let csn = List.length sort_names in let cs = List.length sorts in diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 4f10b275a..9f4cd9cd9 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -3441,43 +3441,6 @@ sig @return A string representation of the benchmark. *) val benchmark_to_smtstring : context -> string -> string -> string -> string -> Expr.expr list -> Expr.expr -> string - (** Parse the given string using the SMT-LIB parser. - - The symbol table of the parser can be initialized using the given sorts and declarations. - The symbols in the arrays in the third and fifth argument - don't need to match the names of the sorts and declarations in the arrays in the fourth - and sixth argument. This is a useful feature since we can use arbitrary names to - reference sorts and declarations. *) - val parse_smtlib_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> unit - - (** Parse the given file using the SMT-LIB parser. - {!parse_smtlib_string} *) - val parse_smtlib_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> unit - - (** The number of SMTLIB formulas parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_formulas : context -> int - - (** The formulas parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_formulas : context -> Expr.expr list - - (** The number of SMTLIB assumptions parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_assumptions : context -> int - - (** The assumptions parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_assumptions : context -> Expr.expr list - - (** The number of SMTLIB declarations parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_decls : context -> int - - (** The declarations parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_decls : context -> FuncDecl.func_decl list - - (** The number of SMTLIB sorts parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_num_smtlib_sorts : context -> int - - (** The sort declarations parsed by the last call to [ParseSMTLIBString] or [ParseSMTLIBFile]. *) - val get_smtlib_sorts : context -> Sort.sort list - (** Parse the given string using the SMT-LIB2 parser. {!parse_smtlib_string} From 3f19c12a12de86c48fbd139af228490df3d1b5c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Dec 2017 05:48:34 +0530 Subject: [PATCH 29/72] add obj_ref_map to make it easier to maintain reference counts with a map of objects Signed-off-by: Nikolaj Bjorner --- src/util/obj_ref_hashtable.h | 111 +++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/util/obj_ref_hashtable.h diff --git a/src/util/obj_ref_hashtable.h b/src/util/obj_ref_hashtable.h new file mode 100644 index 000000000..6bd4f1556 --- /dev/null +++ b/src/util/obj_ref_hashtable.h @@ -0,0 +1,111 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + obj_ref_hashtable.h + +Abstract: + + corresponding obj_map with reference count managment. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-12-8 + +Revision History: + +--*/ +#ifndef OBJ_REF_HASHTABLE_H_ +#define OBJ_REF_HASHTABLE_H_ + +#include "util/obj_hashtable.h" + +template +class obj_ref_map { + M& m; + obj_map m_table; +public: + obj_ref_map(M& m):m(m) {} + + ~obj_ref_map() { reset(); } + + void reset() { + for (auto& kv : m_table) { + m.dec_ref(kv.m_key); + } + m_table.reset(); + } + + void finalize() { + reset(); + m_table.finalize(); + } + + bool empty() const { return m_table.empty(); } + + unsigned size() const { return m_table.size(); } + + unsigned capacity() const { return m_table.capacity(); } + + iterator begin() const { return m_table.begin(); } + + iterator end() const { return m_table.end(); } + + void insert(Key * const k, Value const & v) { + if (!m_table.contains(k)) m.inc_ref(k); + m_table.insert(k, v); + } + + void insert(Key * const k, Value && v) { + if (!m_table.contains(k)) m.inc_ref(k); + m_table.insert(k, v); + } + + key_data const & insert_if_not_there(Key * k, Value const & v) { + if (!m_table.contains(k)) m.inc_ref(k); + return m_table.insert_if_not_there(k, v); + } + + obj_map_entry * insert_if_not_there2(Key * k, Value const & v) { + if (!m_table.contains(k)) m.inc_ref(k); + return m_table.insert_if_not_there2(k, v); + } + + obj_map_entry * find_core(Key * k) const { return m_table.find_core(k); } + + bool find(Key * const k, Value & v) const { return m_table.find(k, v); } + + value const & find(key * k) const { return m_table.find(k); } + + value & find(key * k) { return m_table.find(k); } + + value const & operator[](key * k) const { return find(k); } + + value & operator[](key * k) { return find(k); } + + iterator find_iterator(Key * k) const { return m_table.find_iterator(k); } + + bool contains(Key * k) const { return m_table.contains(k); } + + void remove(Key * k) { + if (m_table.contains(k)) { + m_table.remove(k); + m.dec_ref(k); + } + } + + void erase(Key * k) { remove(k); } + + unsigned long long get_num_collision() const { return m_table.get_num_collision(); } + + void swap(obj_ref_map & other) { + m_table.swap(other.m_table); + } + + +}; + + +#endif /* OBJ_REF_HASHTABLE_H_ */ + From a5d5dfdf86c507e300a11b37f161bb9587e988e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Dec 2017 09:23:57 +0530 Subject: [PATCH 30/72] fix setup for non-linear real arithmetic per QF_UFNRA regresssions Signed-off-by: Nikolaj Bjorner --- src/ast/static_features.cpp | 14 +++----------- src/smt/smt_setup.cpp | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index 3db4d02a2..9f52ea9a5 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -111,16 +111,6 @@ void static_features::flush_cache() { m_expr2formula_depth.reset(); } -#if 0 -bool static_features::is_non_linear(expr * e) const { - if (!is_arith_expr(e)) - return false; - if (is_numeral(e)) - return true; - if (m_autil.is_add(e)) - return true; // the non -} -#endif bool static_features::is_diff_term(expr const * e, rational & r) const { // lhs can be 'x' or '(+ k x)' @@ -301,10 +291,12 @@ void static_features::update_core(expr * e) { m_num_interpreted_constants++; } if (fid == m_afid) { + // std::cout << mk_pp(e, m_manager) << "\n"; switch (to_app(e)->get_decl_kind()) { case OP_MUL: - if (!is_numeral(to_app(e)->get_arg(0))) + if (!is_numeral(to_app(e)->get_arg(0)) || to_app(e)->get_num_args() > 2) { m_num_non_linear++; + } break; case OP_DIV: case OP_IDIV: diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 631805b4d..bbc91e4c6 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -968,7 +968,7 @@ namespace smt { if (st.num_theories() == 2 && st.has_uf() && is_arith(st)) { if (!st.m_has_real) setup_QF_UFLIA(st); - else if (!st.m_has_int) + else if (!st.m_has_int && st.m_num_non_linear == 0) setup_QF_UFLRA(); else setup_unknown(); From c8d9be0bbf363dac3430a1a0397800c0d9685055 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Dec 2017 14:22:25 +0530 Subject: [PATCH 31/72] fix build of obj_ref_hashtable Signed-off-by: Nikolaj Bjorner --- src/util/obj_ref_hashtable.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/obj_ref_hashtable.h b/src/util/obj_ref_hashtable.h index 6bd4f1556..3d6bbf883 100644 --- a/src/util/obj_ref_hashtable.h +++ b/src/util/obj_ref_hashtable.h @@ -26,6 +26,12 @@ class obj_ref_map { M& m; obj_map m_table; public: + typedef typename obj_map iterator; + typedef Key key; + typedef Value value; + typedef typename obj_map::key_data key_data; + typedef typename obj_map::obj_map_entry obj_map_entry; + obj_ref_map(M& m):m(m) {} ~obj_ref_map() { reset(); } From faebbc5384dae4425d03fa743587303a83839296 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Dec 2017 16:17:04 +0530 Subject: [PATCH 32/72] add shortcuts for concatenation and equality propagation Signed-off-by: Nikolaj Bjorner --- src/qe/nlqsat.cpp | 168 ----------------------------------------- src/smt/theory_seq.cpp | 48 ++++++------ src/smt/theory_seq.h | 6 +- 3 files changed, 32 insertions(+), 190 deletions(-) diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 1f9c89f89..ab5095328 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -886,174 +886,6 @@ namespace qe { tactic * translate(ast_manager & m) { return alloc(nlqsat, m, m_mode, m_params); } - -#if 0 - - /** - - Algorithm: - I := true - while there is M, such that M |= ~B & I: - find P, such that M => P => exists y . ~B & I - ; forall y B => ~P - C := core of P with respect to A - ; A => ~ C => ~ P - I := I & ~C - - - Alternative Algorithm: - R := false - while there is M, such that M |= A & ~R: - find I, such that M => I => forall y . B - R := R | I - - */ - - lbool interpolate(expr* a, expr* b, expr_ref& result) { - SASSERT(m_mode == interp_t); - - reset(); - app_ref enableA(m), enableB(m); - expr_ref A(m), B(m), fml(m); - expr_ref_vector fmls(m), answer(m); - - // varsB are private to B. - nlsat::var_vector vars; - uint_set fvars; - private_vars(a, b, vars, fvars); - - enableA = m.mk_const(symbol("#A"), m.mk_bool_sort()); - enableB = m.mk_not(enableA); - A = m.mk_implies(enableA, a); - B = m.mk_implies(enableB, m.mk_not(b)); - fml = m.mk_and(A, B); - hoist(fml); - - - - nlsat::literal _enableB = nlsat::literal(m_a2b.to_var(enableB), false); - nlsat::literal _enableA = ~_enableB; - - while (true) { - m_mode = qsat_t; - // enable B - m_assumptions.reset(); - m_assumptions.push_back(_enableB); - lbool is_sat = check_sat(); - - switch (is_sat) { - case l_undef: - return l_undef; - case l_true: - break; - case l_false: - result = mk_and(answer); - return l_true; - } - - // disable B, enable A - m_assumptions.reset(); - m_assumptions.push_back(_enableA); - // add blocking clause to solver. - - nlsat::scoped_literal_vector core(m_solver); - - m_mode = elim_t; - - mbp(vars, fvars, core); - - // minimize core. - nlsat::literal_vector _core(core.size(), core.c_ptr()); - _core.push_back(_enableA); - is_sat = m_solver.check(_core); // TBD: only for quantifier-free A. Generalize output of elim_t to be a core. - switch (is_sat) { - case l_undef: - return l_undef; - case l_true: - UNREACHABLE(); - case l_false: - core.reset(); - core.append(_core.size(), _core.c_ptr()); - break; - } - negate_clause(core); - // keep polarity of enableA, such that clause is only - // used when checking satisfiability of B. - for (unsigned i = 0; i < core.size(); ++i) { - if (core[i].var() == _enableA.var()) core.set(i, ~core[i]); - } - add_clause(core); // Invariant is added as assumption for B. - answer.push_back(clause2fml(core)); // TBD: remove answer literal. - } - } - - /** - \brief extract variables that are private to a (not used in b). - vars cover the real variables, and fvars cover the Boolean variables. - - TBD: We want fvars to be the complement such that returned core contains - Shared boolean variables, but not the ones private to B. - */ - void private_vars(expr* a, expr* b, nlsat::var_vector& vars, uint_set& fvars) { - app_ref_vector varsA(m), varsB(m); - obj_hashtable varsAS; - pred_abs abs(m); - abs.get_free_vars(a, varsA); - abs.get_free_vars(b, varsB); - insert_set(varsAS, varsA); - for (unsigned i = 0; i < varsB.size(); ++i) { - if (varsAS.contains(varsB[i].get())) { - varsB[i] = varsB.back(); - varsB.pop_back(); - --i; - } - } - for (unsigned j = 0; j < varsB.size(); ++j) { - app* v = varsB[j].get(); - if (m_a2b.is_var(v)) { - fvars.insert(m_a2b.to_var(v)); - } - else if (m_t2x.is_var(v)) { - vars.push_back(m_t2x.to_var(v)); - } - } - } - - lbool maximize(app* _x, expr* _fml, scoped_anum& result, bool& unbounded) { - expr_ref fml(_fml, m); - reset(); - hoist(fml); - nlsat::literal_vector lits; - lbool is_sat = l_true; - nlsat::var x = m_t2x.to_var(_x); - m_mode = qsat_t; - while (is_sat == l_true) { - is_sat = check_sat(); - if (is_sat == l_true) { - // m_asms is minimized set of literals that satisfy formula. - nlsat::explain& ex = m_solver.get_explain(); - polynomial::manager& pm = m_solver.pm(); - anum_manager& am = m_solver.am(); - ex.maximize(x, m_asms.size(), m_asms.c_ptr(), result, unbounded); - if (unbounded) { - break; - } - // TBD: assert the new bound on x using the result. - bool is_even = false; - polynomial::polynomial_ref pr(pm); - pr = pm.mk_polynomial(x); - rational r; - am.get_upper(result, r); - // result is algebraic numeral, but polynomials are not defined over extension field. - polynomial::polynomial* p = pr; - nlsat::bool_var b = m_solver.mk_ineq_atom(nlsat::atom::GT, 1, &p, &is_even); - nlsat::literal bound(b, false); - m_solver.mk_clause(1, &bound); - } - } - return is_sat; - } -#endif }; }; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 9830a16b4..597348589 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -397,15 +397,13 @@ bool theory_seq::branch_binary_variable(eq const& e) { expr_ref Y1(mk_skolem(symbol("seq.left"), x, y), m); expr_ref Y2(mk_skolem(symbol("seq.right"), x, y), m); ys.push_back(Y1); - expr_ref ysY1(m_util.str.mk_concat(ys.size(), ys.c_ptr()), m); - expr_ref xsE(m_util.str.mk_concat(xs.size(), xs.c_ptr()), m); - expr_ref Y1Y2(m_util.str.mk_concat(Y1, Y2), m); - literal_vector lits; - lits.push_back(~lit); + expr_ref ysY1(mk_concat(ys)); + expr_ref xsE(mk_concat(xs)); + expr_ref Y1Y2(mk_concat(Y1, Y2)); dependency* dep = e.dep(); - propagate_eq(dep, lits, x, ysY1, true); - propagate_eq(dep, lits, y, Y1Y2, true); - propagate_eq(dep, lits, Y2, xsE, true); + propagate_eq(dep, ~lit, x, ysY1); + propagate_eq(dep, ~lit, y, Y1Y2); + propagate_eq(dep, ~lit, Y2, xsE); } else { ctx.mark_as_relevant(lit); @@ -471,9 +469,7 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector literal lit = mk_eq(m_autil.mk_int(lX), m_util.str.mk_length(X), false); if (l_true == ctx.get_assignment(lit)) { expr_ref R(m_util.str.mk_concat(lX, units.c_ptr()), m); - literal_vector lits; - lits.push_back(lit); - propagate_eq(dep, lits, X, R, true); + propagate_eq(dep, lit, X, R); TRACE("seq", tout << "propagate " << mk_pp(X, m) << " " << R << "\n";); } else { @@ -506,11 +502,10 @@ bool theory_seq::branch_variable_mb() { for (unsigned j = 0; j < len2.size(); ++j) l2 += len2[j]; if (l1 != l2) { TRACE("seq", tout << "lengths are not compatible\n";); - expr_ref l = mk_concat(e.ls().size(), e.ls().c_ptr()); - expr_ref r = mk_concat(e.rs().size(), e.rs().c_ptr()); + expr_ref l = mk_concat(e.ls()); + expr_ref r = mk_concat(e.rs()); expr_ref lnl(m_util.str.mk_length(l), m), lnr(m_util.str.mk_length(r), m); - literal_vector lits; - propagate_eq(e.dep(), lits, lnl, lnr, false); + propagate_eq(e.dep(), lnl, lnr, false); change = true; continue; } @@ -626,8 +621,8 @@ bool theory_seq::split_lengths(dependency* dep, SASSERT(is_var(Y)); expr_ref Y1(mk_skolem(symbol("seq.left"), X, b, Y), m); expr_ref Y2(mk_skolem(symbol("seq.right"), X, b, Y), m); - expr_ref bY1(m_util.str.mk_concat(b, Y1), m); - expr_ref Y1Y2(m_util.str.mk_concat(Y1, Y2), m); + expr_ref bY1 = mk_concat(b, Y1); + expr_ref Y1Y2 = mk_concat(Y1, Y2); propagate_eq(dep, lits, X, bY1, true); propagate_eq(dep, lits, Y, Y1Y2, true); } @@ -1317,6 +1312,18 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { enforce_length_coherence(n1, n2); } +void theory_seq::propagate_eq(dependency* dep, expr* e1, expr* e2, bool add_eq) { + literal_vector lits; + propagate_eq(dep, lits, e1, e2, add_eq); +} + +void theory_seq::propagate_eq(dependency* dep, literal lit, expr* e1, expr* e2, bool add_to_eqs) { + literal_vector lits; + lits.push_back(lit); + propagate_eq(dep, lits, e1, e2, add_to_eqs); +} + + void theory_seq::enforce_length_coherence(enode* n1, enode* n2) { expr* o1 = n1->get_owner(); expr* o2 = n2->get_owner(); @@ -1662,19 +1669,18 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect } SASSERT(0 < l1 && l1 < ls.size()); SASSERT(0 < r1 && r1 < rs.size()); - expr_ref l(m_util.str.mk_concat(l1, ls1), m); - expr_ref r(m_util.str.mk_concat(r1, rs1), m); + expr_ref l = mk_concat(l1, ls1); + expr_ref r = mk_concat(r1, rs1); expr_ref lenl(m_util.str.mk_length(l), m); expr_ref lenr(m_util.str.mk_length(r), m); literal lit = mk_eq(lenl, lenr, false); if (ctx.get_assignment(lit) == l_true) { - literal_vector lits; expr_ref_vector lhs(m), rhs(m); lhs.append(l2, ls2); rhs.append(r2, rs2); deps = mk_join(deps, lit); m_eqs.push_back(eq(m_eq_id++, lhs, rhs, deps)); - propagate_eq(deps, lits, l, r, true); + propagate_eq(deps, l, r, true); TRACE("seq", tout << "propagate eq\nlhs: " << lhs << "\nrhs: " << rhs << "\n";); return true; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index d4686c835..46f803f5b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -410,6 +410,8 @@ namespace smt { expr_ref mk_empty(sort* s) { return expr_ref(m_util.str.mk_empty(s), m); } expr_ref mk_concat(unsigned n, expr*const* es) { return expr_ref(m_util.str.mk_concat(n, es), m); } expr_ref mk_concat(expr_ref_vector const& es, sort* s) { if (es.empty()) return mk_empty(s); return mk_concat(es.size(), es.c_ptr()); } + expr_ref mk_concat(expr_ref_vector const& es) { SASSERT(!es.empty()); return mk_concat(es.size(), es.c_ptr()); } + expr_ref mk_concat(ptr_vector const& es) { SASSERT(!es.empty()); return mk_concat(es.size(), es.c_ptr()); } expr_ref mk_concat(expr* e1, expr* e2) { return expr_ref(m_util.str.mk_concat(e1, e2), m); } expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(m_util.str.mk_concat(e1, e2, e3), m); } bool solve_nqs(unsigned i); @@ -436,7 +438,9 @@ namespace smt { void propagate_lit(dependency* dep, unsigned n, literal const* lits, literal lit); void propagate_eq(dependency* dep, enode* n1, enode* n2); void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs); - void propagate_eq(dependency* dep, literal_vector const& lits, expr* e1, expr* e2, bool add_to_eqs); + void propagate_eq(dependency* dep, literal_vector const& lits, expr* e1, expr* e2, bool add_to_eqs = true); + void propagate_eq(dependency* dep, expr* e1, expr* e2, bool add_to_eqs = true); + void propagate_eq(dependency* dep, literal lit, expr* e1, expr* e2, bool add_to_eqs = true); void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); u_map m_branch_start; From 9d2c86f214304d224b7c439bc3bfd43da002dbdc Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 8 Dec 2017 20:31:22 -0500 Subject: [PATCH 33/72] fix incorrect clause in argumentsValid subterm of substr reduction --- src/smt/theory_str.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 7936b581c..022a2ad73 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1450,7 +1450,7 @@ namespace smt { // pos < strlen(base) // --> pos + -1*strlen(base) < 0 argumentsValid_terms.push_back(mk_not(m, m_autil.mk_ge( - m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)), + m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, mk_strlen(substrBase))), zero))); // len >= 0 From 2e186633ee17f9ee3c8265f976321cb0cd8f44b3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 11 Dec 2017 14:59:25 +0000 Subject: [PATCH 34/72] Turned assertion failure into proper error message. --- src/ast/ast.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index e7d808b2b..3824325b3 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1289,7 +1289,7 @@ decl_kind user_sort_plugin::register_name(symbol s) { decl_plugin * user_sort_plugin::mk_fresh() { user_sort_plugin * p = alloc(user_sort_plugin); - for (symbol const& s : m_sort_names) + for (symbol const& s : m_sort_names) p->register_name(s); return p; } @@ -1415,7 +1415,7 @@ ast_manager::~ast_manager() { p->finalize(); } for (decl_plugin* p : m_plugins) { - if (p) + if (p) dealloc(p); } m_plugins.reset(); @@ -1454,13 +1454,13 @@ ast_manager::~ast_manager() { mark_array_ref(mark, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns()); mark_array_ref(mark, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns()); break; - } - } + } + } for (ast * n : m_ast_table) { if (!mark.is_marked(n)) { roots.push_back(n); } - } + } SASSERT(!roots.empty()); for (unsigned i = 0; i < roots.size(); ++i) { ast* a = roots[i]; @@ -1683,7 +1683,7 @@ ast * ast_manager::register_node_core(ast * n) { bool contains = m_ast_table.contains(n); CASSERT("nondet_bug", contains || slow_not_contains(n)); #endif - + ast * r = m_ast_table.insert_if_not_there(n); SASSERT(r->m_hash == h); if (r != n) { @@ -2358,8 +2358,9 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * unsigned num_patterns, expr * const * patterns, unsigned num_no_patterns, expr * const * no_patterns) { SASSERT(body); - SASSERT(num_patterns == 0 || num_no_patterns == 0); SASSERT(num_decls > 0); + if (num_patterns != 0 && num_no_patterns != 0) + throw ast_exception("simultaneous patterns and no-patterns not supported"); DEBUG_CODE({ for (unsigned i = 0; i < num_patterns; ++i) { TRACE("ast", tout << i << " " << mk_pp(patterns[i], *this) << "\n";); @@ -2763,7 +2764,7 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs, expr * n1, expr * n2) { - if (num_proofs == 0) + if (num_proofs == 0) return nullptr; if (num_proofs == 1) return proofs[0]; From 49678065bd133721445bb7ef7be6ac03d826dd36 Mon Sep 17 00:00:00 2001 From: Ivan Gotovchits Date: Wed, 13 Dec 2017 14:37:19 -0500 Subject: [PATCH 35/72] fixes compilation flags for OCaml plugins The `-linkall` option is needed for a plugin to be standalone, otherwise it will miss those dependencies that are not used. --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b155fd7c2..03256125c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1990,7 +1990,7 @@ class MLComponent(Component): out.write('%s.cmxa: %s %s %s %s.cma\n' % (z3mls, cmxs, stubso, z3dllso, z3mls)) out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmxs, LIBZ3)) out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls)) - out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls)) + out.write('\t%s -linkall -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls)) out.write('\n') out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls)) From 5a479fca76d6e249490c7a9b42d9431318ddb6c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Dec 2017 13:48:24 -0800 Subject: [PATCH 36/72] generalize model finder code to be independent of conjunction elimination Signed-off-by: Nikolaj Bjorner --- src/smt/smt_model_finder.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 11202d58a..28a65f898 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -2272,10 +2272,9 @@ namespace smt { process_literal(atom, pol == NEG); } - void process_or(app * n, polarity p) { - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - visit_formula(n->get_arg(i), p); + void process_and_or(app * n, polarity p) { + for (expr* arg : *n) + visit_formula(arg, p); } void process_ite(app * n, polarity p) { @@ -2306,13 +2305,13 @@ namespace smt { if (is_app(curr)) { if (to_app(curr)->get_family_id() == m_manager.get_basic_family_id() && m_manager.is_bool(curr)) { switch (static_cast(to_app(curr)->get_decl_kind())) { - case OP_AND: case OP_IMPLIES: case OP_XOR: UNREACHABLE(); // simplifier eliminated ANDs, IMPLIEs, and XORs break; case OP_OR: - process_or(to_app(curr), pol); + case OP_AND: + process_and_or(to_app(curr), pol); break; case OP_NOT: visit_formula(to_app(curr)->get_arg(0), neg(pol)); From 58c6cb87c3bc26824fd2386e2eeb74bb3a826537 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 11:48:22 -0800 Subject: [PATCH 37/72] small improvements to QF_NIA tactic Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_nl.h | 1 + src/tactic/smtlogics/qfnia_tactic.cpp | 35 +++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 230b6de77..87b811e8f 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -711,6 +711,7 @@ namespace smt { if (ctx.is_relevant(get_enode(*it)) && !check_monomial_assignment(*it, computed_epsilon)) { TRACE("non_linear_failed", tout << "check_monomial_assignment failed for:\n" << mk_ismt2_pp(var2expr(*it), get_manager()) << "\n"; display_var(tout, *it);); + return false; } } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 3fb733ca4..f0a4ceb57 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -26,8 +26,10 @@ Notes: #include "tactic/bv/max_bv_sharing_tactic.h" #include "sat/tactic/sat_tactic.h" #include "tactic/arith/nla2bv_tactic.h" +#include "tactic/arith/elim01_tactic.h" #include "tactic/core/ctx_simplify_tactic.h" #include "tactic/core/cofactor_term_ite_tactic.h" +#include "nlsat/tactic/qfnra_nlsat_tactic.h" static tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) { params_ref p = p_ref; @@ -61,8 +63,6 @@ static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { ctx_simp_p.set_uint("max_depth", 30); ctx_simp_p.set_uint("max_steps", 5000000); - params_ref simp_p = p_ref; - simp_p.set_bool("hoist_mul", true); params_ref elim_p = p_ref; elim_p.set_uint("max_memory",20); @@ -73,21 +73,42 @@ static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { using_params(mk_ctx_simplify_tactic(m), ctx_simp_p), using_params(mk_simplify_tactic(m), pull_ite_p), mk_elim_uncnstr_tactic(m), - skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p)), - using_params(mk_simplify_tactic(m), simp_p)); + mk_elim01_tactic(m), + skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p))); } static tactic * mk_qfnia_sat_solver(ast_manager & m, params_ref const & p) { params_ref nia2sat_p = p; - nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + params_ref simp_p = p; + simp_p.set_bool("hoist_mul", true); // hoist multipliers to create smaller circuits. - return and_then(mk_nla2bv_tactic(m, nia2sat_p), + return and_then(using_params(mk_simplify_tactic(m), simp_p), + mk_nla2bv_tactic(m, nia2sat_p), mk_qfnia_bv_solver(m, p), mk_fail_if_undecided_tactic()); } +static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { + params_ref nia2sat_p = p; + nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + params_ref simp_p = p; + simp_p.set_bool("som", true); // expand into sums of monomials + simp_p.set_bool("factor", false); + + + return and_then(using_params(mk_simplify_tactic(m), simp_p), + try_for(mk_qfnra_nlsat_tactic(m, simp_p), 10000), + mk_fail_if_undecided_tactic()); +} + tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { + params_ref simp_p = p; + simp_p.set_bool("som", true); // expand into sums of monomials + return and_then(mk_qfnia_premable(m, p), or_else(mk_qfnia_sat_solver(m, p), - mk_smt_tactic())); + mk_qfnia_nlsat_solver(m, p), + and_then(using_params(mk_simplify_tactic(m), simp_p), + mk_smt_tactic()))); } From e5fa35e969283027e6ca4b75a5dc5ee493c2e5e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:07:17 -0800 Subject: [PATCH 38/72] add integer branch and bound to nlsat Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_interval_set.cpp | 4 +- src/nlsat/nlsat_interval_set.h | 2 +- src/nlsat/nlsat_solver.cpp | 70 ++++++++++++++++++++++++--- src/tactic/smtlogics/qfnia_tactic.cpp | 2 +- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 2028095f4..090f94eeb 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -672,14 +672,14 @@ namespace nlsat { return new_set; } - void interval_set_manager::peek_in_complement(interval_set const * s, anum & w, bool randomize) { + void interval_set_manager::peek_in_complement(interval_set const * s, bool is_int, anum & w, bool randomize) { SASSERT(!is_full(s)); if (s == 0) { if (randomize) { int num = m_rand() % 2 == 0 ? 1 : -1; #define MAX_RANDOM_DEN_K 4 int den_k = (m_rand() % MAX_RANDOM_DEN_K); - int den = 1 << den_k; + int den = is_int ? 1 : (1 << den_k); scoped_mpq _w(m_am.qm()); m_am.qm().set(_w, num, den); m_am.set(w, _w); diff --git a/src/nlsat/nlsat_interval_set.h b/src/nlsat/nlsat_interval_set.h index 24b2ab37f..363d48de9 100644 --- a/src/nlsat/nlsat_interval_set.h +++ b/src/nlsat/nlsat_interval_set.h @@ -108,7 +108,7 @@ namespace nlsat { \pre !is_full(s) */ - void peek_in_complement(interval_set const * s, anum & w, bool randomize); + void peek_in_complement(interval_set const * s, bool is_int, anum & w, bool randomize); }; typedef obj_ref interval_set_ref; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index c5e9babae..0ccaa2f2c 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -903,15 +903,18 @@ namespace nlsat { */ lbool value(literal l) { lbool val = assigned_value(l); - if (val != l_undef) + if (val != l_undef) { return val; + } bool_var b = l.var(); atom * a = m_atoms[b]; - if (a == 0) + if (a == 0) { return l_undef; + } var max = a->max_var(); - if (!m_assignment.is_assigned(max)) + if (!m_assignment.is_assigned(max)) { return l_undef; + } val = to_lbool(m_evaluator.eval(a, l.sign())); TRACE("value_bug", tout << "value of: "; display(tout, l); tout << " := " << val << "\n"; tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n"; @@ -1168,7 +1171,7 @@ namespace nlsat { void select_witness() { scoped_anum w(m_am); SASSERT(!m_ism.is_full(m_infeasible[m_xk])); - m_ism.peek_in_complement(m_infeasible[m_xk], w, m_randomize); + m_ism.peek_in_complement(m_infeasible[m_xk], m_is_int[m_xk], w, m_randomize); TRACE("nlsat", tout << "infeasible intervals: "; m_ism.display(tout, m_infeasible[m_xk]); tout << "\n"; tout << "assigning "; m_display_var(tout, m_xk); tout << "(x" << m_xk << ") -> " << w << "\n";); @@ -1232,6 +1235,61 @@ namespace nlsat { } } + lbool search_check() { + lbool r = l_undef; + while (true) { + r = search(); + if (r != l_true) break; + random_gen r(++m_random_seed); + unsigned start = r(num_vars()); + for (var y = 0; y < num_vars(); y++) { + var x = (y + start) % num_vars(); + if (m_is_int[x] && m_assignment.is_assigned(x) && !m_am.is_int(m_assignment.value(x))) { + scoped_anum v(m_am), vlo(m_am), vhi(m_am); + rational lo, hi; + bool is_even = false; + v = m_assignment.value(x); + init_search(); + m_am.int_lt(v, vlo); + m_am.int_gt(v, vhi); + if (!m_am.is_int(vlo)) break; + if (!m_am.is_int(vhi)) break; + m_am.to_rational(vlo, lo); + m_am.to_rational(vhi, hi); + + // derive tight bounds. + while (true) { + lo++; + if (!m_am.gt(v, lo.to_mpq())) { lo--; break; } + } + while (true) { + hi--; + if (!m_am.lt(v, hi.to_mpq())) { hi++; break; } + } + + polynomial_ref p(m_pm); + rational one(1); + m_lemma.reset(); + p = m_pm.mk_linear(1, &one, &x, -lo); + poly* p1 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::GT, 1, &p1, &is_even)); + p = m_pm.mk_linear(1, &one, &x, -hi); + poly* p2 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); + + // perform branch and bound + clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); + if (cls) { + TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); + } + r = l_undef; + break; + } + } + } + return r; + } + lbool check() { TRACE("nlsat_smt2", display_smt2(tout);); TRACE("nlsat_fd", tout << "is_full_dimensional: " << is_full_dimensional() << "\n";); @@ -1250,7 +1308,7 @@ namespace nlsat { reordered = true; } sort_watched_clauses(); - lbool r = search(); + lbool r = search_check(); CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout);); if (reordered) restore_order(); @@ -1929,7 +1987,7 @@ namespace nlsat { for (var x = 0; x < num; x++) { p.push_back(x); } - random_gen r(m_random_seed); + random_gen r(++m_random_seed); shuffle(p.size(), p.c_ptr(), r); reorder(p.size(), p.c_ptr()); } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index f0a4ceb57..b4f25243a 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -107,7 +107,7 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { simp_p.set_bool("som", true); // expand into sums of monomials return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_sat_solver(m, p), + or_else(// mk_qfnia_sat_solver(m, p), mk_qfnia_nlsat_solver(m, p), and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()))); From 1dac5bd45973c5954f29db23fbb77c429ddf7395 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:07:52 -0800 Subject: [PATCH 39/72] remove comment out Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qfnia_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index b4f25243a..f0a4ceb57 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -107,7 +107,7 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { simp_p.set_bool("som", true); // expand into sums of monomials return and_then(mk_qfnia_premable(m, p), - or_else(// mk_qfnia_sat_solver(m, p), + or_else(mk_qfnia_sat_solver(m, p), mk_qfnia_nlsat_solver(m, p), and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()))); From ab39f06df7833f1f3a47efbac2e7e8db3741c5d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:22:49 -0800 Subject: [PATCH 40/72] fix crashes in nlsat Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 9 ++++++--- src/tactic/smtlogics/qfnia_tactic.cpp | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 0ccaa2f2c..0e3bf8c95 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -734,8 +734,10 @@ namespace nlsat { void undo_set_updt(interval_set * old_set) { SASSERT(m_xk != null_var); var x = m_xk; - m_ism.dec_ref(m_infeasible[x]); - m_infeasible[x] = old_set; + if (x < m_infeasible.size() && m_infeasible[x]) { + m_ism.dec_ref(m_infeasible[x]); + m_infeasible[x] = old_set; + } } void undo_new_stage() { @@ -757,7 +759,8 @@ namespace nlsat { void undo_updt_eq(atom * a) { SASSERT(m_xk != null_var); - m_var2eq[m_xk] = a; + if (m_var2eq.size() > m_xk) + m_var2eq[m_xk] = a; } template diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index f0a4ceb57..3b890b632 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -107,8 +107,8 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { simp_p.set_bool("som", true); // expand into sums of monomials return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_sat_solver(m, p), - mk_qfnia_nlsat_solver(m, p), + or_else(mk_qfnia_nlsat_solver(m, p), + mk_qfnia_sat_solver(m, p), and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()))); } From 1c3d385c253b94b1932adf769a0059d1fad58b65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:24:13 -0800 Subject: [PATCH 41/72] fix crashes in nlsat Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 0e3bf8c95..da4f9646d 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -734,7 +734,7 @@ namespace nlsat { void undo_set_updt(interval_set * old_set) { SASSERT(m_xk != null_var); var x = m_xk; - if (x < m_infeasible.size() && m_infeasible[x]) { + if (x < m_infeasible.size()) { m_ism.dec_ref(m_infeasible[x]); m_infeasible[x] = old_set; } From 397cdfc608229a745879aa34ac191b56a79b3c6b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 06:38:56 -0800 Subject: [PATCH 42/72] avoid crash on nl Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 6 ++---- src/tactic/portfolio/default_tactic.cpp | 2 +- src/tactic/smtlogics/quant_tactics.cpp | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index da4f9646d..8f61fffac 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -732,7 +732,7 @@ namespace nlsat { } void undo_set_updt(interval_set * old_set) { - SASSERT(m_xk != null_var); + if (m_xk == null_var) return; var x = m_xk; if (x < m_infeasible.size()) { m_ism.dec_ref(m_infeasible[x]); @@ -741,8 +741,7 @@ namespace nlsat { } void undo_new_stage() { - SASSERT(m_xk != null_var); - if (m_xk == 0) { + if (m_xk == 0 || m_xk == null_var) { m_xk = null_var; } else { @@ -758,7 +757,6 @@ namespace nlsat { } void undo_updt_eq(atom * a) { - SASSERT(m_xk != null_var); if (m_var2eq.size() > m_xk) m_var2eq[m_xk] = a; } diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 420cb961a..09052869b 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -41,8 +41,8 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_qflra_probe(), mk_qflra_tactic(m), cond(mk_is_qfnra_probe(), mk_qfnra_tactic(m), cond(mk_is_qfnia_probe(), mk_qfnia_tactic(m), - cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_lira_probe(), mk_lira_tactic(m, p), + cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), //cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), mk_smt_tactic()))))))))))), diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 400089a0c..8438d1a32 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -24,7 +24,6 @@ Revision History: #include "qe/qe_tactic.h" #include "qe/qe_lite.h" #include "qe/qsat.h" -#include "qe/nlqsat.h" #include "tactic/core/ctx_simplify_tactic.h" #include "smt/tactic/smt_tactic.h" #include "tactic/core/elim_term_ite_tactic.h" From 21f685fa5a4a6f20e27bb0eb86828c0e553138dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 06:54:02 -0800 Subject: [PATCH 43/72] fix nlsat regression Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 87 +++++++++++++-------------- src/tactic/smtlogics/qfnia_tactic.cpp | 2 +- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 8f61fffac..c088c406b 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -732,19 +732,19 @@ namespace nlsat { } void undo_set_updt(interval_set * old_set) { - if (m_xk == null_var) return; + if (m_xk == null_var) return; var x = m_xk; - if (x < m_infeasible.size()) { - m_ism.dec_ref(m_infeasible[x]); - m_infeasible[x] = old_set; - } + if (x < m_infeasible.size()) { + m_ism.dec_ref(m_infeasible[x]); + m_infeasible[x] = old_set; + } } void undo_new_stage() { - if (m_xk == 0 || m_xk == null_var) { + if (m_xk == 0) { m_xk = null_var; } - else { + else if (m_xk != null_var) { m_xk--; m_assignment.reset(m_xk); } @@ -757,7 +757,7 @@ namespace nlsat { } void undo_updt_eq(atom * a) { - if (m_var2eq.size() > m_xk) + if (m_var2eq.size() > m_xk) m_var2eq[m_xk] = a; } @@ -1241,50 +1241,47 @@ namespace nlsat { while (true) { r = search(); if (r != l_true) break; - random_gen r(++m_random_seed); - unsigned start = r(num_vars()); - for (var y = 0; y < num_vars(); y++) { - var x = (y + start) % num_vars(); - if (m_is_int[x] && m_assignment.is_assigned(x) && !m_am.is_int(m_assignment.value(x))) { - scoped_anum v(m_am), vlo(m_am), vhi(m_am); - rational lo, hi; - bool is_even = false; - v = m_assignment.value(x); - init_search(); - m_am.int_lt(v, vlo); - m_am.int_gt(v, vhi); - if (!m_am.is_int(vlo)) break; - if (!m_am.is_int(vhi)) break; - m_am.to_rational(vlo, lo); - m_am.to_rational(vhi, hi); + vector lows; + vector vars; + for (var x = 0; x < num_vars(); x++) { + if (m_is_int[x] && m_assignment.is_assigned(x) && !m_am.is_int(m_assignment.value(x))) { + scoped_anum v(m_am), vlo(m_am); + v = m_assignment.value(x); + rational lo; + m_am.int_lt(v, vlo); + if (!m_am.is_int(vlo)) continue; // derive tight bounds. while (true) { lo++; if (!m_am.gt(v, lo.to_mpq())) { lo--; break; } } - while (true) { - hi--; - if (!m_am.lt(v, hi.to_mpq())) { hi++; break; } - } - - polynomial_ref p(m_pm); - rational one(1); - m_lemma.reset(); - p = m_pm.mk_linear(1, &one, &x, -lo); - poly* p1 = p.get(); - m_lemma.push_back(~mk_ineq_literal(atom::GT, 1, &p1, &is_even)); - p = m_pm.mk_linear(1, &one, &x, -hi); - poly* p2 = p.get(); - m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); + lows.push_back(lo); + vars.push_back(x); + } + } + if (lows.empty()) break; - // perform branch and bound - clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); - if (cls) { - TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); - } - r = l_undef; - break; + init_search(); + for (unsigned i = 0; i < lows.size(); ++i) { + rational lo = lows[i]; + rational hi = lo + rational::one(); + var x = vars[i]; + bool is_even = false; + polynomial_ref p(m_pm); + rational one(1); + m_lemma.reset(); + p = m_pm.mk_linear(1, &one, &x, -lo); + poly* p1 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::GT, 1, &p1, &is_even)); + p = m_pm.mk_linear(1, &one, &x, -hi); + poly* p2 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); + + // perform branch and bound + clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); + if (cls) { + TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); } } } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 3b890b632..5374ba1c1 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -98,7 +98,7 @@ static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { return and_then(using_params(mk_simplify_tactic(m), simp_p), - try_for(mk_qfnra_nlsat_tactic(m, simp_p), 10000), + try_for(mk_qfnra_nlsat_tactic(m, simp_p), 3000), mk_fail_if_undecided_tactic()); } From c3add4eeda15dd44d8afe7423b0037dec34e9c8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 06:56:36 -0800 Subject: [PATCH 44/72] add back missing initialization of lo Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index c088c406b..e1dadf12b 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1251,6 +1251,7 @@ namespace nlsat { rational lo; m_am.int_lt(v, vlo); if (!m_am.is_int(vlo)) continue; + m_am.to_rational(vlo, lo); // derive tight bounds. while (true) { lo++; From b0aaa4c6d7a739eb5e8e56a73e0486df46483222 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 14:18:30 +0000 Subject: [PATCH 45/72] Updated release notes --- RELEASE_NOTES | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index e85e3d8d6..4f10cad26 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -2,6 +2,7 @@ RELEASE NOTES Version 4.6.0 ============= + - New requirements: - C++11 capable compiler to build Z3. - C++ API now requires C++11 or newer. @@ -14,6 +15,10 @@ Version 4.6.0 issuing the command (get-objectives). Pareto front objectives are accessed by issuing multiple (check-sat) calls until it returns unsat. +- Removed features: + - Removed support for SMT-LIB 1.x + + Version 4.5.0 ============= @@ -49,10 +54,9 @@ Version 4.5.0 over compound formulas, introduce a fresh predicate whose arguments are the relevant free variables in the formula and add a rule that uses the fresh predicate in the head and formula in the body. - - minimization of unsat cores is avaialble as an option for the SAT and SMT cores. + - Minimization of unsat cores is available as an option for the SAT and SMT cores. By setting smt.core.minimize=true resp. sat.core.minimize=true - cores produced by these modules are minimized. - + cores produced by these modules are minimized. - A multitude of bugs has been fixed. From 63951b815dec78bf4b49e9e39a1fef8b5e739939 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 18:58:21 +0000 Subject: [PATCH 46/72] Bumped version number. --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 871852c04..0be2de537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 6) -set(Z3_VERSION_PATCH 0) +set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 60b3b7756..8f75e97ed 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 6, 0, 0) + set_version(4, 6, 1, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') From c3c06d756c9fe7a1e9ed06600cb500014977bf99 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 20:11:18 +0000 Subject: [PATCH 47/72] Documentation fixes. --- doc/mk_api_doc.py | 7 +++++-- src/api/ml/z3.mli | 4 +--- src/api/z3_api.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index a944f2c65..a1a9e64bd 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -226,12 +226,14 @@ try: website_dox_substitutions = {} bullet_point_prefix='\n - ' if Z3PY_ENABLED: + print("Python documentation enabled") website_dox_substitutions['PYTHON_API'] = ( '{prefix}Python API ' '(also available in pydoc format)' ).format( prefix=bullet_point_prefix) else: + print("Python documentation disabled") website_dox_substitutions['PYTHON_API'] = '' if DOTNET_ENABLED: website_dox_substitutions['DOTNET_API'] = ( @@ -250,7 +252,7 @@ try: website_dox_substitutions['JAVA_API'] = '' if ML_ENABLED: website_dox_substitutions['OCAML_API'] = ( - 'ML/OCaml API' + '{prefix}ML/OCaml API' ).format( prefix=bullet_point_prefix) else: @@ -316,7 +318,7 @@ try: if ML_ENABLED: ml_output_dir = os.path.join(OUTPUT_DIRECTORY, 'html', 'ml') mk_dir(ml_output_dir) - if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, doc_path('../src/api/ml/z3enums.mli'), doc_path('../src/api/ml/z3.mli')]) != 0: + if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, '%s/api/ml/z3enums.mli' % BUILD_DIR, '%s/api/ml/z3.mli' % BUILD_DIR]) != 0: print("ERROR: ocamldoc failed.") exit(1) print("Generated ML/OCaml documentation.") @@ -326,3 +328,4 @@ except Exception: exctype, value = sys.exc_info()[:2] print("ERROR: failed to generate documentation: %s" % value) exit(1) + diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 9f4cd9cd9..80923a0c7 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -3443,12 +3443,10 @@ sig (** Parse the given string using the SMT-LIB2 parser. - {!parse_smtlib_string} @return A conjunction of assertions in the scope (up to push/pop) at the end of the string. *) val parse_smtlib2_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr - (** Parse the given file using the SMT-LIB2 parser. - {!parse_smtlib2_string} *) + (** Parse the given file using the SMT-LIB2 parser. *) val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr end diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 064476b9b..007bc3ab6 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1331,7 +1331,7 @@ typedef enum { - Z3_IOB: Index out of bounds. - Z3_INVALID_ARG: Invalid argument was provided. - Z3_PARSER_ERROR: An error occurred when parsing a string or file. - - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. + - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib2_string or #Z3_parse_smtlib2_file. - Z3_INVALID_PATTERN: Invalid pattern was used to build a quantifier. - Z3_MEMOUT_FAIL: A memory allocation failure was encountered. - Z3_FILE_ACCESS_ERRROR: A file could not be accessed. From 399b27fda3874a3897e8af8d531758e54b71f818 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 12:20:44 -0800 Subject: [PATCH 48/72] add Python facility for int2bv, fix #1398 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 237f35433..3bf48b611 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -3568,6 +3568,14 @@ def BV2Int(a, is_signed=False): ## investigate problem with bv2int return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), is_signed), ctx) +def Int2BV(a, num_bits): + """Return the z3 expression Int2BV(a, num_bits). + It is a bit-vector of width num_bits and represents the + modulo of a by 2^num_bits + """ + ctx = a.ctx + return BitVecRef(Z3_mk_int2bv(ctx.ref(), num_bits, a.as_ast()), ctx) + def BitVecSort(sz, ctx=None): """Return a Z3 bit-vector sort of the given size. If `ctx=None`, then the global context is used. From d695767f61f752ca8aecfe53792dd0fd1b90ec1e Mon Sep 17 00:00:00 2001 From: bannsec Date: Mon, 18 Dec 2017 21:48:54 +0000 Subject: [PATCH 49/72] Allowing slices and negative index in assertions --- src/api/python/z3/z3.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 3bf48b611..4cc401156 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5140,9 +5140,18 @@ class AstVector(Z3PPObject): >>> A[1] y """ - if i >= self.__len__(): - raise IndexError - return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + if isinstance(i, int): + if i < 0: + i += self.__len__() + + if i >= self.__len__(): + raise IndexError + return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + elif isinstance(i, slice): + return [_to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, ii), self.ctx) for ii in range(*i.indices(self.__len__()))] + def __setitem__(self, i, v): """Update AST at position `i`. From 13ee8da65968d3f111666032f27813eee51e9e66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 15:57:16 -0800 Subject: [PATCH 50/72] add virtual destructor to see if this helps ASan error Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 8704f4444..488e16ae9 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -151,6 +151,7 @@ namespace nlsat { class solver_exception : public default_exception { public: solver_exception(char const * msg):default_exception(msg) {} + virtual ~solver_exception() {} }; class assignment; From 517b0812021129377590f2fc2afcbd263461a3ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 21:13:03 -0800 Subject: [PATCH 51/72] remove custom exception, perhaps this handles exception issue Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_types.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 488e16ae9..db3b6ffa5 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -148,11 +148,7 @@ namespace nlsat { typedef algebraic_numbers::anum anum; typedef algebraic_numbers::manager anum_manager; - class solver_exception : public default_exception { - public: - solver_exception(char const * msg):default_exception(msg) {} - virtual ~solver_exception() {} - }; + typedef default_exception solver_exception; class assignment; From 36204fafa09f601052044052e1477b7ad3264005 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Dec 2017 20:27:08 -0800 Subject: [PATCH 52/72] alternate strategies for QF_NIA Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qflia_tactic.cpp | 1 - src/tactic/smtlogics/qfnia_tactic.cpp | 14 +++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index de542f3c4..23ae179e2 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -24,7 +24,6 @@ Notes: #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "smt/tactic/smt_tactic.h" -// include"mip_tactic.h" #include "tactic/arith/add_bounds_tactic.h" #include "tactic/arith/pb2bv_tactic.h" #include "tactic/arith/lia2pb_tactic.h" diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 5374ba1c1..d967660ce 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -102,13 +102,17 @@ static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { mk_fail_if_undecided_tactic()); } -tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { +static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { params_ref simp_p = p; simp_p.set_bool("som", true); // expand into sums of monomials + return and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()); +} + +tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_nlsat_solver(m, p), - mk_qfnia_sat_solver(m, p), - and_then(using_params(mk_simplify_tactic(m), simp_p), - mk_smt_tactic()))); + or_else(mk_qfnia_sat_solver(m, p), + try_for(mk_qfnia_smt_solver(m, p), 2000), + mk_qfnia_nlsat_solver(m, p), + mk_qfnia_smt_solver(m, p))); } From 5bc4c9809e232d63f46018b200cb930bca993ce5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Dec 2017 12:50:11 -0800 Subject: [PATCH 53/72] initialize additional assumptions after setup_context is called the first time Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 59 +++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3b69d4846..a87042e2b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3202,10 +3202,8 @@ namespace smt { }); validate_unsat_core(); // theory validation of unsat core - ptr_vector::iterator th_it = m_theory_set.begin(); - ptr_vector::iterator th_end = m_theory_set.end(); - for (; th_it != th_end; ++th_it) { - lbool theory_result = (*th_it)->validate_unsat_core(m_unsat_core); + for (theory* th : m_theory_set) { + lbool theory_result = th->validate_unsat_core(m_unsat_core); if (theory_result == l_undef) { return l_undef; } @@ -3296,10 +3294,8 @@ namespace smt { #ifndef _EXTERNAL_RELEASE if (m_fparams.m_display_installed_theories) { std::cout << "(theories"; - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - std::cout << " " << (*it)->get_name(); + for (theory* th : m_theory_set) { + std::cout << " " << th->get_name(); } std::cout << ")" << std::endl; } @@ -3316,17 +3312,13 @@ namespace smt { m_fparams.m_relevancy_lemma = false; // setup all the theories - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) - (*it)->setup(); + for (theory* th : m_theory_set) + th->setup(); } void context::add_theory_assumptions(expr_ref_vector & theory_assumptions) { - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - (*it)->add_theory_assumptions(theory_assumptions); + for (theory* th : m_theory_set) { + th->add_theory_assumptions(theory_assumptions); } } @@ -3342,18 +3334,7 @@ namespace smt { if (!check_preamble(reset_cancel)) return l_undef; - expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); - if (!already_did_theory_assumptions) { - add_theory_assumptions(all_assumptions); - } - - unsigned num_assumptions = all_assumptions.size(); - expr * const * assumptions = all_assumptions.c_ptr(); - - if (!validate_assumptions(num_assumptions, assumptions)) - return l_undef; TRACE("check_bug", tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n";); - TRACE("unsat_core_bug", for (unsigned i = 0; i < num_assumptions; i++) { tout << mk_pp(assumptions[i], m_manager) << "\n";}); pop_to_base_lvl(); TRACE("before_search", display(tout);); SASSERT(at_base_level()); @@ -3363,6 +3344,18 @@ namespace smt { } else { setup_context(false); + expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); + if (!already_did_theory_assumptions) { + add_theory_assumptions(all_assumptions); + } + + unsigned num_assumptions = all_assumptions.size(); + expr * const * assumptions = all_assumptions.c_ptr(); + + if (!validate_assumptions(num_assumptions, assumptions)) + return l_undef; + TRACE("unsat_core_bug", tout << all_assumptions << "\n";); + internalize_assertions(); TRACE("after_internalize_assertions", display(tout);); if (m_asserted_formulas.inconsistent()) { @@ -3551,10 +3544,9 @@ namespace smt { pop_scope(m_scope_lvl - curr_lvl); SASSERT(at_search_level()); } - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end && !inconsistent(); ++it) - (*it)->restart_eh(); + for (theory* th : m_theory_set) { + if (!inconsistent()) th->restart_eh(); + } TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); if (!inconsistent()) { m_qmanager->restart_eh(); @@ -4070,10 +4062,7 @@ namespace smt { bool include = false; if (at_lbls) { // include if there is a label with the '@' sign. - buffer::const_iterator it = lbls.begin(); - buffer::const_iterator end = lbls.end(); - for (; it != end; ++it) { - symbol const & s = *it; + for (symbol const& s : lbls) { if (s.contains('@')) { include = true; break; From d86e8f02d7808fed783a5eedc4d8f5255008c6f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Dec 2017 10:09:10 -0800 Subject: [PATCH 54/72] fix get-objectives error #1419 message (get-objectives) Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3d296d92b..0daf98320 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1235,6 +1235,9 @@ namespace opt { } void context::display_assignment(std::ostream& out) { + if (m_scoped_state.m_objectives.size() != m_objectives.size()) { + throw default_exception("check-sat has not been called with latest objectives"); + } out << "(objectives\n"; for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { objective const& obj = m_scoped_state.m_objectives[i]; From 79a9dfd8fdd1ff3072fc571286217f788147084c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Dec 2017 20:35:33 -0800 Subject: [PATCH 55/72] adding pre-processing to nlsat for equations Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 4 +- src/math/polynomial/polynomial.cpp | 93 +++- src/math/polynomial/polynomial.h | 35 +- src/nlsat/nlsat_clause.h | 2 + src/nlsat/nlsat_solver.cpp | 631 +++++++++++++++++------- src/nlsat/nlsat_solver.h | 2 +- src/nlsat/nlsat_types.h | 2 + src/nlsat/tactic/nlsat_tactic.cpp | 8 +- src/nlsat/tactic/qfnra_nlsat_tactic.cpp | 4 + src/qe/nlqsat.cpp | 2 +- src/tactic/core/solve_eqs_tactic.cpp | 135 +++-- 11 files changed, 696 insertions(+), 222 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 4b24ea5e6..4850b52a8 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -370,7 +370,7 @@ public: app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); } app * mk_gt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GT, arg1, arg2); } - app * mk_add(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } + app * mk_add(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_ADD, num_args, args); } app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } @@ -378,7 +378,7 @@ public: app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } - app * mk_mul(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } + app * mk_mul(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_MUL, num_args, args); } app * mk_uminus(expr * arg) const { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_DIV, arg1, arg2); } app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_IDIV, arg1, arg2); } diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index d6d392148..51d8489e3 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -150,7 +150,6 @@ namespace polynomial { return r; } - /** \brief Monomials (power products) */ @@ -192,7 +191,7 @@ namespace polynomial { }; static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz * sizeof(power); } - + monomial(unsigned id, unsigned sz, power const * pws, unsigned h): m_ref_count(0), m_id(id), @@ -257,9 +256,7 @@ namespace polynomial { if (m_size < SMALL_MONOMIAL) { // use linear search for small monomials // search backwards since we usually ask for the degree of "big" variables - unsigned i = last; - while (i > 0) { - --i; + for (unsigned i = last; i-- > 0; ) { if (get_var(i) == x) return i; } @@ -798,9 +795,8 @@ namespace polynomial { dec_ref(m_unit); CTRACE("polynomial", !m_monomials.empty(), tout << "monomials leaked\n"; - monomial_table::iterator it = m_monomials.begin(); monomial_table::iterator end = m_monomials.end(); - for (; it != end; ++it) { - (*it)->display(tout); tout << "\n"; + for (auto * m : m_monomials) { + m->display(tout); tout << "\n"; }); SASSERT(m_monomials.empty()); if (m_own_allocator) @@ -1510,6 +1506,8 @@ namespace polynomial { unsigned id() const { return m_id; } unsigned size() const { return m_size; } monomial * m(unsigned idx) const { SASSERT(idx < size()); return m_ms[idx]; } + monomial *const* begin() const { return m_ms; } + monomial *const* end() const { return m_ms + size(); } numeral const & a(unsigned idx) const { SASSERT(idx < size()); return m_as[idx]; } numeral & a(unsigned idx) { SASSERT(idx < size()); return m_as[idx]; } numeral const * as() const { return m_as; } @@ -1773,11 +1771,9 @@ namespace polynomial { } bool manager::is_linear(polynomial const * p) { - unsigned sz = p->size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_linear(p->m(0))) + for (monomial* m : *p) + if (!is_linear(m)) return false; - } return true; } @@ -2396,6 +2392,7 @@ namespace polynomial { return mm().is_valid(x); } + void add_del_eh(del_eh * eh) { eh->m_next = m_del_eh; m_del_eh = eh; @@ -6101,6 +6098,33 @@ namespace polynomial { }); } + lbool sign(monomial* m, numeral const& c, svector const& sign_of_vars) { + unsigned sz = size(m); + lbool sign1 = m_manager.is_pos(c) ? l_true : l_false; + for (unsigned i = 0; i < sz; ++i) { + var v = get_var(m, i); + unsigned d = degree(m, i); + lbool sign2 = sign_of_vars.get(v, l_undef); + if (sign2 == l_undef) + return l_undef; + else if (1 == (d % 2) && sign2 == l_false) { + sign1 = sign1 == l_true ? l_false : l_true; + } + } + return sign1; + } + + lbool sign(polynomial const * p, svector const& sign_of_vars) { + unsigned sz = size(p); + if (sz == 0) return l_undef; + lbool sign1 = sign(p->m(0), p->a(0), sign_of_vars); + for (unsigned i = 1; sign1 != l_undef && i < sz; ++i) { + if (sign(p->m(i), p->a(i), sign_of_vars) != sign1) + return l_undef; + } + return sign1; + } + bool is_pos(polynomial const * p) { bool found_unit = false; unsigned sz = p->size(); @@ -6372,6 +6396,31 @@ namespace polynomial { R.add(new_a, mk_monomial(new_m)); } return R.mk(); + } + + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + unsigned md = degree(r, x); + if (md == 0) { + result = const_cast(r); + return; + } + result = 0; + polynomial_ref p1(pm()), q1(pm()); + polynomial_ref_buffer ps(pm()); + unsigned sz = r->size(); + for (unsigned i = 0; i < sz; i++) { + monomial * m0 = r->m(i); + unsigned dm = m0->degree_of(x); + SASSERT(md >= dm); + monomial_ref m1(div_x(m0, x), pm()); + pw(p, dm, p1); + pw(q, md - dm, q1); + p1 = mul(r->a(i), m1, p1 * q1); + if (result) + result = add(result, p1); + else + result = p1; + } } @@ -6918,6 +6967,18 @@ namespace polynomial { return m_imp->m().set_zp(p); } + bool manager::is_var(polynomial const* p, var& v) { + return p->size() == 1 && is_var(p->m(0), v) && m_imp->m().is_one(p->a(0)); + } + + bool manager::is_var(monomial const* m, var& v) { + return m->size() == 1 && m->degree(0) == 1 && (v = m->get_var(0), true); + } + + bool manager::is_var_num(polynomial const* p, var& v, scoped_numeral& n) { + return p->size() == 2 && m_imp->m().is_one(p->a(0)) && is_var(p->m(0), v) && is_unit(p->m(1)) && (n = p->a(1), true); + } + small_object_allocator & manager::allocator() const { return m_imp->mm().allocator(); } @@ -7271,6 +7332,10 @@ namespace polynomial { void manager::psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S) { m_imp->psc_chain(p, q, x, S); } + + lbool manager::sign(polynomial const * p, svector const& sign_of_vars) { + return m_imp->sign(p, sign_of_vars); + } bool manager::is_pos(polynomial const * p) { return m_imp->is_pos(p); @@ -7307,6 +7372,10 @@ namespace polynomial { polynomial * manager::substitute(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs) { return m_imp->substitute(p, xs_sz, xs, vs); } + + void manager::substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + m_imp->substitute(r, x, p, q, result); + } void manager::factor(polynomial const * p, factors & r, factor_params const & params) { m_imp->factor(p, r, params); diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 43b3c1138..b09af94bc 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -29,6 +29,7 @@ Notes: #include "util/params.h" #include "util/mpbqi.h" #include "util/rlimit.h" +#include "util/lbool.h" class small_object_allocator; @@ -98,7 +99,7 @@ namespace polynomial { }; struct display_var_proc { - virtual void operator()(std::ostream & out, var x) const { out << "x" << x; } + virtual std::ostream& operator()(std::ostream & out, var x) const { return out << "x" << x; } }; class polynomial; @@ -306,12 +307,27 @@ namespace polynomial { \brief Return true if m is linear (i.e., it is of the form 1 or x). */ static bool is_linear(monomial const * m); - + /** \brief Return true if all monomials in p are linear. */ static bool is_linear(polynomial const * p); + /** + \brief Return true if the monomial is a variable. + */ + static bool is_var(monomial const* p, var& v); + + /** + \brief Return true if the polynomial is a variable. + */ + bool is_var(polynomial const* p, var& v); + + /** + \brief Return true if the polynomial is of the form x + k + */ + bool is_var_num(polynomial const* p, var& v, scoped_numeral& n); + /** \brief Return the degree of variable x in p. */ @@ -860,7 +876,13 @@ namespace polynomial { \brief Return true if p is a square, and store its square root in r. */ bool sqrt(polynomial const * p, polynomial_ref & r); - + + + /** + \brief obtain the sign of the polynomial given sign of variables. + */ + lbool sign(polynomial const* p, svector const& sign_of_vars); + /** \brief Return true if p is always positive for any assignment of its variables. @@ -936,6 +958,13 @@ namespace polynomial { return substitute(p, 1, &x, &v); } + /** + \brief Apply substiution [x -> p/q] in r. + That is, given r \in Z[x, y_1, .., y_m] return + polynomial q^k * r(p/q, y_1, .., y_m), where k is the maximal degree of x in r. + */ + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result); + /** \brief Factorize the given polynomial p and store its factors in r. */ diff --git a/src/nlsat/nlsat_clause.h b/src/nlsat/nlsat_clause.h index 898c32449..93dfb0e80 100644 --- a/src/nlsat/nlsat_clause.h +++ b/src/nlsat/nlsat_clause.h @@ -44,6 +44,8 @@ namespace nlsat { bool is_learned() const { return m_learned; } literal * begin() { return m_lits; } literal * end() { return m_lits + m_size; } + literal const * begin() const { return m_lits; } + literal const * end() const { return m_lits + m_size; } literal const * c_ptr() const { return m_lits; } void inc_activity() { m_activity++; } void set_activity(unsigned v) { m_activity = v; } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index e1dadf12b..4cba6d123 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -18,19 +18,20 @@ Author: Revision History: --*/ +#include "util/z3_exception.h" +#include "util/chashtable.h" +#include "util/id_gen.h" +#include "util/map.h" +#include "util/dependency.h" +#include "util/permutation.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/polynomial_cache.h" #include "nlsat/nlsat_solver.h" #include "nlsat/nlsat_clause.h" #include "nlsat/nlsat_assignment.h" #include "nlsat/nlsat_justification.h" #include "nlsat/nlsat_evaluator.h" #include "nlsat/nlsat_explain.h" -#include "math/polynomial/algebraic_numbers.h" -#include "util/z3_exception.h" -#include "util/chashtable.h" -#include "util/id_gen.h" -#include "util/dependency.h" -#include "math/polynomial/polynomial_cache.h" -#include "util/permutation.h" #include "nlsat/nlsat_params.hpp" #define NLSAT_EXTRA_VERBOSE @@ -68,6 +69,7 @@ namespace nlsat { reslimit& m_rlimit; small_object_allocator m_allocator; + bool m_incremental; unsynch_mpq_manager m_qm; pmanager m_pm; cache m_cache; @@ -78,6 +80,8 @@ namespace nlsat { interval_set_manager & m_ism; ineq_atom_table m_ineq_atoms; root_atom_table m_root_atoms; + svector m_patch_var; + polynomial_ref_vector m_patch_num, m_patch_denom; id_gen m_cid_gen; clause_vector m_clauses; // set of clauses @@ -108,11 +112,12 @@ namespace nlsat { m_perm(perm), m_proc(0) { } - virtual void operator()(std::ostream & out, var x) const { + std::ostream& operator()(std::ostream & out, var x) const { if (m_proc == 0) m_default_display_var(out, x); else (*m_proc)(out, m_perm[x]); + return out; } }; perm_display_var_proc m_display_var; @@ -158,9 +163,10 @@ namespace nlsat { unsigned m_stages; unsigned m_irrational_assignments; // number of irrational witnesses - imp(solver& s, reslimit& rlim, params_ref const & p): + imp(solver& s, reslimit& rlim, params_ref const & p, bool incremental): m_rlimit(rlim), m_allocator("nlsat"), + m_incremental(incremental), m_pm(rlim, m_qm, &m_allocator), m_cache(m_pm), m_am(rlim, m_qm, p, &m_allocator), @@ -168,6 +174,8 @@ namespace nlsat { m_assignment(m_am), m_evaluator(s, m_assignment, m_pm, m_allocator), m_ism(m_evaluator.ism()), + m_patch_num(m_pm), + m_patch_denom(m_pm), m_num_bool_vars(0), m_display_var(m_perm), m_explain(s, m_assignment, m_cache, m_atoms, m_var2eq, m_evaluator), @@ -330,9 +338,7 @@ namespace nlsat { */ bool_var max_bvar(clause const & cls) const { bool_var b = null_bool_var; - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = cls[i]; + for (literal l : cls) { if (b == null_bool_var || l.var() > b) b = l.var(); } @@ -367,9 +373,7 @@ namespace nlsat { if (x == null_var) return 0; unsigned max = 0; - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = c[i]; + for (literal l : c) { atom const * a = m_atoms[l.var()]; if (a == 0) continue; @@ -496,13 +500,12 @@ namespace nlsat { // Delete atoms with ref_count == 0 void del_unref_atoms() { - unsigned sz = m_atoms.size(); - for (unsigned i = 0; i < sz; i++) { - del(m_atoms[i]); + for (auto* a : m_atoms) { + del(a); } } - bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + ineq_atom* mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even, bool& is_new) { SASSERT(sz >= 1); SASSERT(k == atom::LT || k == atom::GT || k == atom::EQ); int sign = 1; @@ -522,23 +525,36 @@ namespace nlsat { void * mem = m_allocator.allocate(ineq_atom::get_obj_size(sz)); if (sign < 0) k = atom::flip(k); - ineq_atom * new_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); + ineq_atom * tmp_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); TRACE("nlsat_table_bug", ineq_atom::hash_proc h; - tout << "mk_ineq_atom hash: " << h(new_atom) << "\n"; display(tout, *new_atom, m_display_var); tout << "\n";); - ineq_atom * old_atom = m_ineq_atoms.insert_if_not_there(new_atom); - CTRACE("nlsat_table_bug", old_atom->max_var() != max, display(tout, *old_atom, m_display_var); tout << "\n";); - SASSERT(old_atom->max_var() == max); - if (old_atom != new_atom) { - deallocate(new_atom); - return old_atom->bvar(); + tout << "mk_ineq_atom hash: " << h(tmp_atom) << "\n"; display(tout, *tmp_atom, m_display_var); tout << "\n";); + ineq_atom * atom = m_ineq_atoms.insert_if_not_there(tmp_atom); + CTRACE("nlsat_table_bug", atom->max_var() != max, display(tout, *atom, m_display_var); tout << "\n";); + SASSERT(atom->max_var() == max); + is_new = (atom == tmp_atom); + if (is_new) { + for (unsigned i = 0; i < sz; i++) { + m_pm.inc_ref(atom->p(i)); + } } - bool_var b = mk_bool_var_core(); - m_atoms[b] = new_atom; - new_atom->m_bool_var = b; - for (unsigned i = 0; i < sz; i++) { - m_pm.inc_ref(new_atom->p(i)); + else { + deallocate(tmp_atom); + } + return atom; + } + + bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + bool is_new = false; + ineq_atom* atom = mk_ineq_atom(k, sz, ps, is_even, is_new); + if (!is_new) { + return atom->bvar(); + } + else { + bool_var b = mk_bool_var_core(); + m_atoms[b] = atom; + atom->m_bool_var = b; + return b; } - return b; } literal mk_ineq_literal(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { @@ -619,10 +635,14 @@ namespace nlsat { deallocate(cls); } + void del_clause(clause * cls, clause_vector& clauses) { + clauses.erase(cls); + del_clause(cls); + } + void del_clauses(ptr_vector & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) - del_clause(cs[i]); + for (clause* cp : cs) + del_clause(cp); } void del_clauses() { @@ -927,10 +947,9 @@ namespace nlsat { \brief Return true if the given clause is already satisfied in the current partial interpretation. */ bool is_satisfied(clause const & cls) const { - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - if (const_cast(this)->value(cls[i]) == l_true) { - TRACE("value_bug:", tout << cls[i] << " := true\n";); + for (literal l : cls) { + if (const_cast(this)->value(l) == l_true) { + TRACE("value_bug:", tout << l << " := true\n";); return true; } } @@ -1023,7 +1042,7 @@ namespace nlsat { SASSERT(x != null_var); if (m_var2eq[x] != 0 && degree(m_var2eq[x]) <= degree(a)) return; // we only update m_var2eq if the new equality has smaller degree - TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x); tout << " (x" << x << ") "; + TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x) << " (x" << x << ") "; tout << "scope-lvl: " << scope_lvl() << "\n"; display(tout, literal(b, false)); tout << "\n";); save_updt_eq_trail(m_var2eq[x]); m_var2eq[x] = a; @@ -1045,10 +1064,9 @@ namespace nlsat { interval_set_ref first_undef_set(m_ism); // infeasible region of the first undefined literal interval_set * xk_set = m_infeasible[m_xk]; // current set of infeasible interval for current variable SASSERT(!m_ism.is_full(xk_set)); - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { + for (unsigned idx = 0; idx < cls.size(); ++idx) { + literal l = cls[idx]; checkpoint(); - literal l = cls[i]; if (value(l) == l_false) continue; SASSERT(value(l) == l_undef); @@ -1085,7 +1103,7 @@ namespace nlsat { } num_undef++; if (first_undef == UINT_MAX) { - first_undef = i; + first_undef = idx; first_undef_set = curr_set; } } @@ -1131,9 +1149,7 @@ namespace nlsat { Return 0, if the set was satisfied, or the violating clause otherwise */ clause * process_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause * c = cs[i]; + for (clause* c : cs) { if (!process_clause(*c, false)) return c; } @@ -1175,7 +1191,7 @@ namespace nlsat { m_ism.peek_in_complement(m_infeasible[m_xk], m_is_int[m_xk], w, m_randomize); TRACE("nlsat", tout << "infeasible intervals: "; m_ism.display(tout, m_infeasible[m_xk]); tout << "\n"; - tout << "assigning "; m_display_var(tout, m_xk); tout << "(x" << m_xk << ") -> " << w << "\n";); + tout << "assigning "; m_display_var(tout, m_xk) << "(x" << m_xk << ") -> " << w << "\n";); TRACE("nlsat_root", tout << "value as root object: "; m_am.display_root(tout, w); tout << "\n";); if (!m_am.is_rational(w)) m_irrational_assignments++; @@ -1205,6 +1221,7 @@ namespace nlsat { TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";); if (m_bk == null_bool_var && m_xk >= num_vars()) { TRACE("nlsat", tout << "found model\n"; display_assignment(tout);); + fix_patch(); return l_true; // all variables were assigned, and all clauses were satisfied. } TRACE("nlsat", tout << "processing variable "; @@ -1295,6 +1312,13 @@ namespace nlsat { init_search(); m_explain.set_full_dimensional(is_full_dimensional()); bool reordered = false; + +#if 0 + // disabled + if (!m_incremental) + simplify(); +#endif + if (!can_reorder()) { } @@ -1497,9 +1521,9 @@ namespace nlsat { TRACE("nlsat_mathematica", display_mathematica_lemma(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr());); TRACE("nlsat_proof_sk", tout << "theory lemma\n"; display_abst(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); TRACE("nlsat_resolve", - tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk); tout << "\n"; + tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk) << "\n"; tout << "new valid clause:\n"; - display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); + display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()) << "\n";); DEBUG_CODE({ unsigned sz = m_lazy_clause.size(); @@ -1633,15 +1657,10 @@ namespace nlsat { TRACE("nlsat_proof", tout << "STARTING RESOLUTION\n";); TRACE("nlsat_proof_sk", tout << "STARTING RESOLUTION\n";); m_conflicts++; - TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n"; + TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause) << "\n"; tout << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << ""; tout << "\n"; tout << "scope_lvl: " << scope_lvl() << "\n"; tout << "current assignment\n"; display_assignment(tout);); - - // static unsigned counter = 0; - // counter++; - // if (counter > 6) - // exit(0); m_num_marks = 0; m_lemma.reset(); @@ -1750,7 +1769,7 @@ namespace nlsat { SASSERT(m_xk == new_max_var); new_cls = mk_clause(sz, m_lemma.c_ptr(), true, m_lemma_assumptions.get()); TRACE("nlsat", tout << "new_level: " << scope_lvl() << "\nnew_stage: " << new_max_var << " "; - if (new_max_var != null_var) m_display_var(tout, new_max_var); tout << "\n";); + if (new_max_var != null_var) m_display_var(tout, new_max_var) << "\n";); } else { SASSERT(scope_lvl() >= 1); @@ -1931,11 +1950,12 @@ namespace nlsat { collect(*(cs[i])); } - void display(std::ostream & out, display_var_proc const & proc) { + std::ostream& display(std::ostream & out, display_var_proc const & proc) { unsigned sz = m_num_occs.size(); for (unsigned i = 0; i < sz; i++) { proc(out, i); out << " -> " << m_max_degree[i] << " : " << m_num_occs[i] << "\n"; } + return out; } }; @@ -2169,12 +2189,10 @@ namespace nlsat { } void reattach_arith_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause & c = *cs[i]; - var x = max_var(c); + for (clause* cp : cs) { + var x = max_var(*cp); if (x != null_var) - m_watches[x].push_back(&c); + m_watches[x].push_back(cp); } } @@ -2251,18 +2269,16 @@ namespace nlsat { } bool is_full_dimensional(clause const & c) const { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(c[i])) + for (literal l : c) { + if (!is_full_dimensional(l)) return false; } return true; } bool is_full_dimensional(clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(*(cs[i]))) + for (clause* c : cs) { + if (!is_full_dimensional(*c)) return false; } return true; @@ -2272,13 +2288,271 @@ namespace nlsat { return is_full_dimensional(m_clauses); } + + // ----------------------- + // + // Simplification + // + // ----------------------- + + // solve simple equalities + // TBD WU-Reit decomposition? + + /** + \brief isolate variables in unit equalities. + Assume a clause is c == v*p + q + and the context implies p > 0 + + replace v by -q/p + remove clause c, + The for other occurrences of v, + replace v*r + v*v*r' > 0 by + by p*p*v*r + p*p*v*v*r' > 0 + by p*q*r + q*q*r' > 0 + + The method ignores lemmas and assumes constraints don't use roots. + */ + + void simplify() { + polynomial_ref p(m_pm), q(m_pm); + var v; + init_var_signs(); + SASSERT(m_learned.empty()); + bool change = true; + while (change) { + change = false; + for (clause* c : m_clauses) { + if (solve_var(*c, v, p, q)) { + q = -q; + m_patch_var.push_back(v); + m_patch_num.push_back(q); + m_patch_denom.push_back(p); + del_clause(c, m_clauses); + substitute_var(v, p, q); + change = true; + break; + } + } + } + } + + void fix_patch() { + for (unsigned i = m_patch_var.size(); i-- > 0; ) { + var v = m_patch_var[i]; + poly* q = m_patch_num.get(i); + poly* p = m_patch_denom.get(i); + scoped_anum pv(m_am), qv(m_am), val(m_am); + m_pm.eval(p, m_assignment, pv); + m_pm.eval(q, m_assignment, qv); + val = qv / pv; + TRACE("nlsat", + m_display_var(tout << "patch ", v) << "\n"; + if (m_assignment.is_assigned(v)) m_am.display(tout << "previous value: ", m_assignment.value(v)); tout << "\n"; + m_am.display(tout << "updated value: ", val); tout << "\n"; + ); + m_assignment.set_core(v, val); + } + } + + void substitute_var(var x, poly* p, poly* q) { + polynomial_ref pr(m_pm); + polynomial_ref_vector ps(m_pm); + u_map b2l; + svector even; + unsigned num_atoms = m_atoms.size(); + for (unsigned j = 0; j < num_atoms; ++j) { + atom* a = m_atoms[j]; + if (a && a->is_ineq_atom()) { + ineq_atom const& a1 = *to_ineq_atom(a); + unsigned sz = a1.size(); + ps.reset(); + even.reset(); + bool change = false; + for (unsigned i = 0; i < sz; ++i) { + poly * po = a1.p(i); + m_pm.substitute(po, x, q, p, pr); + ps.push_back(pr); + even.push_back(a1.is_even(i)); + change |= pr != po; + if (m_pm.is_zero(pr)) { + ps.reset(); + even.reset(); + change = true; + break; + } + } + if (!change) continue; + literal l = mk_ineq_literal(a1.get_kind(), ps.size(), ps.c_ptr(), even.c_ptr()); + if (a1.m_bool_var != l.var()) { + b2l.insert(a1.m_bool_var, l); + inc_ref(l); + } + } + } + update_clauses(b2l); + for (auto const& kv : b2l) { + dec_ref(kv.m_value); + } + } + + + void update_clauses(u_map const& b2l) { + literal_vector lits; + clause_vector to_delete; + unsigned n = m_clauses.size(); + for (unsigned i = 0; i < n; ++i) { + clause* c = m_clauses[i]; + lits.reset(); + bool changed = false; + bool is_tautology = false; + for (literal l : *c) { + literal lit = null_literal; + if (b2l.find(l.var(), lit)) { + lit = l.sign() ? ~lit : lit; + if (lit == true_literal) { + is_tautology = true; + } + else if (lit != false_literal) { + lits.push_back(lit); + } + changed = true; + } + else { + lits.push_back(l); + } + } + if (changed) { + to_delete.push_back(c); + if (!is_tautology) { + mk_clause(lits.size(), lits.c_ptr(), c->is_learned(), static_cast<_assumption_set>(c->assumptions())); + } + } + } + for (clause* c : to_delete) { + del_clause(c, m_clauses); + } + } + + bool is_unit_ineq(clause const& c) const { + return + c.size() == 1 && + m_atoms[c[0].var()] && + m_atoms[c[0].var()]->is_ineq_atom(); + } + + bool is_unit_eq(clause const& c) const { + return + is_unit_ineq(c) && + !c[0].sign() && + m_atoms[c[0].var()]->is_eq(); + } + + /** + \brief determine whether the clause is a comparison v > k or v < k', where k >= 0 or k' <= 0. + */ + lbool is_cmp0(clause const& c, var& v) { + if (!is_unit_ineq(c)) return l_undef; + literal lit = c[0]; + ineq_atom const& a = *to_ineq_atom(m_atoms[lit.var()]); + bool sign = lit.sign(); + poly * p0; + if (!is_single_poly(a, p0)) return l_undef; + if (m_pm.is_var(p0, v)) { + if (!sign && a.get_kind() == atom::GT) { + return l_true; + } + if (!sign && a.get_kind() == atom::LT) { + return l_false; + } + return l_undef; + } + polynomial::scoped_numeral n(m_pm.m()); + if (m_pm.is_var_num(p0, v, n)) { + // x - k > 0 + if (!sign && a.get_kind() == atom::GT && m_pm.m().is_nonneg(n)) { + return l_true; + } + // x + k < 0 + if (!sign && a.get_kind() == atom::LT && m_pm.m().is_nonpos(n)) { + return l_false; + } + // !(x + k > 0) + if (sign && a.get_kind() == atom::GT && m_pm.m().is_pos(n)) { + return l_false; + } + // !(x - k < 0) + if (sign && a.get_kind() == atom::LT && m_pm.m().is_neg(n)) { + return l_true; + } + } + return l_undef; + } + + bool is_single_poly(ineq_atom const& a, poly*& p) { + unsigned sz = a.size(); + return sz == 1 && a.is_odd(0) && (p = a.p(0), true); + } + + svector m_var_signs; + + void init_var_signs() { + m_var_signs.reset(); + for (clause* cp : m_clauses) { + clause& c = *cp; + var x = 0; + lbool cmp = is_cmp0(c, x); + switch (cmp) { + case l_true: + m_var_signs.setx(x, l_true, l_undef); + break; + case l_false: + m_var_signs.setx(x, l_false, l_undef); + break; + default: + break; + } + } + } + + /** + \brief returns true then c is an equality that is equivalent to v*p + q, + and p > 0, v does not occur in p, q. + */ + bool solve_var(clause& c, var& v, polynomial_ref& p, polynomial_ref& q) { + poly* p0; + if (!is_unit_eq(c)) return false; + ineq_atom & a = *to_ineq_atom(m_atoms[c[0].var()]); + if (!is_single_poly(a, p0)) return false; + var mx = max_var(p0); + if (mx >= m_is_int.size()) return false; + for (var x = 0; x <= mx; ++x) { + if (m_is_int[x]) continue; + if (1 == m_pm.degree(p0, x)) { + p = m_pm.coeff(p0, x, 1, q); + switch (m_pm.sign(p, m_var_signs)) { + case l_true: + v = x; + return true; + case l_false: + v = x; + p = -p; + q = -q; + return true; + default: + break; + } + } + } + return false; + } + // ----------------------- // // Pretty printing // // ----------------------- - void display_num_assignment(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display_num_assignment(std::ostream & out, display_var_proc const & proc) const { for (var x = 0; x < num_vars(); x++) { if (m_assignment.is_assigned(x)) { proc(out, x); @@ -2287,9 +2561,10 @@ namespace nlsat { out << "\n"; } } + return out; } - void display_bool_assignment(std::ostream & out) const { + std::ostream& display_bool_assignment(std::ostream & out) const { unsigned sz = m_atoms.size(); for (bool_var b = 0; b < sz; b++) { if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) { @@ -2300,6 +2575,7 @@ namespace nlsat { for (bool_var b = 0; b < sz; b++) { out << "b" << b << " -> " << m_bvalues[b] << " " << m_atoms[b] << "\n"; }); + return out; } bool display_mathematica_assignment(std::ostream & out) const { @@ -2317,16 +2593,17 @@ namespace nlsat { return !first; } - void display_num_assignment(std::ostream & out) const { - display_num_assignment(out, m_display_var); + std::ostream& display_num_assignment(std::ostream & out) const { + return display_num_assignment(out, m_display_var); } - void display_assignment(std::ostream& out) const { + std::ostream& display_assignment(std::ostream& out) const { display_bool_assignment(out); display_num_assignment(out); + return out; } - void display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { + std::ostream& display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (use_star && i > 0) @@ -2346,9 +2623,10 @@ namespace nlsat { case atom::EQ: out << " = 0"; break; default: UNREACHABLE(); break; } + return out; } - - void display_mathematica(std::ostream & out, ineq_atom const & a) const { + + std::ostream& display_mathematica(std::ostream & out, ineq_atom const & a) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) @@ -2370,9 +2648,10 @@ namespace nlsat { case atom::EQ: out << " == 0"; break; default: UNREACHABLE(); break; } + return out; } - void display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { switch (a.get_kind()) { case atom::LT: out << "(< "; break; case atom::GT: out << "(> "; break; @@ -2398,9 +2677,10 @@ namespace nlsat { if (sz > 1) out << ")"; out << " 0)"; + return out; } - void display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { proc(out, a.x()); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2413,21 +2693,22 @@ namespace nlsat { out << "root[" << a.i() << "]("; m_pm.display(out, a.p(), proc); out << ")"; + return out; } struct mathematica_var_proc : public display_var_proc { var m_x; public: mathematica_var_proc(var x):m_x(x) {} - virtual void operator()(std::ostream & out, var x) const { + virtual std::ostream& operator()(std::ostream & out, var x) const { if (m_x == x) - out << "#1"; + return out << "#1"; else - out << "x" << x; + return out << "x" << x; } }; - void display_mathematica(std::ostream & out, root_atom const & a) const { + std::ostream& display_mathematica(std::ostream & out, root_atom const & a) const { out << "x" << a.x(); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2440,65 +2721,74 @@ namespace nlsat { out << "Root["; m_pm.display(out, a.p(), mathematica_var_proc(a.x()), true); out << " &, " << a.i() << "]"; + return out; } - void display_smt2(std::ostream & out, root_atom const & a) const { + std::ostream& display_smt2(std::ostream & out, root_atom const & a) const { NOT_IMPLEMENTED_YET(); + return out; } - void display(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, atom const & a, display_var_proc const & proc) const { if (a.is_ineq_atom()) - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); else - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); } - void display_mathematica(std::ostream & out, atom const & a) const { - if (a.is_ineq_atom()) - display_mathematica(out, static_cast(a)); - else - display_mathematica(out, static_cast(a)); + std::ostream& display(std::ostream & out, atom const & a) const { + return display(out, a, m_display_var); } - void display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display_mathematica(std::ostream & out, atom const & a) const { if (a.is_ineq_atom()) - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); else - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); } - void display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + if (a.is_ineq_atom()) + return display_smt2(out, static_cast(a), proc); + else + return display_smt2(out, static_cast(a), proc); + } + + std::ostream& display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display(out, *(m_atoms[b]), proc); + return out; } - void display_atom(std::ostream & out, bool_var b) const { - display_atom(out, b, m_display_var); + std::ostream& display_atom(std::ostream & out, bool_var b) const { + return display_atom(out, b, m_display_var); } - void display_mathematica_atom(std::ostream & out, bool_var b) const { + std::ostream& display_mathematica_atom(std::ostream & out, bool_var b) const { if (b == 0) out << "(0 < 1)"; else if (m_atoms[b] == 0) out << "b" << b; else display_mathematica(out, *(m_atoms[b])); + return out; } - void display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display_smt2(out, *(m_atoms[b]), proc); + return out; } - void display(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2511,13 +2801,14 @@ namespace nlsat { else { display_atom(out, l.var(), proc); } + return out; } - void display(std::ostream & out, literal l) const { - display(out, l, m_display_var); + std::ostream& display(std::ostream & out, literal l) const { + return display(out, l, m_display_var); } - void display_mathematica(std::ostream & out, literal l) const { + std::ostream& display_mathematica(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2530,9 +2821,10 @@ namespace nlsat { else { display_mathematica_atom(out, l.var()); } + return out; } - void display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "(not "; @@ -2542,41 +2834,43 @@ namespace nlsat { else { display_smt2_atom(out, l.var(), proc); } + return out; } - void display_assumptions(std::ostream & out, _assumption_set s) const { - + std::ostream& display_assumptions(std::ostream & out, _assumption_set s) const { + return out; } - void display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display(out, ls[i], proc); } + return out; } - void display(std::ostream & out, unsigned num, literal const * ls) { - display(out, num, ls, m_display_var); + std::ostream& display(std::ostream & out, unsigned num, literal const * ls) { + return display(out, num, ls, m_display_var); + } + + std::ostream& display(std::ostream & out, scoped_literal_vector const & cs) { + return display(out, cs.size(), cs.c_ptr(), m_display_var); } - void display(std::ostream & out, scoped_literal_vector const & cs) { - display(out, cs.size(), cs.c_ptr(), m_display_var); - } - - void display(std::ostream & out, clause const & c, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, clause const & c, display_var_proc const & proc) const { if (c.assumptions() != 0) { display_assumptions(out, static_cast<_assumption_set>(c.assumptions())); out << " |- "; } - display(out, c.size(), c.c_ptr(), proc); + return display(out, c.size(), c.c_ptr(), proc); } - void display(std::ostream & out, clause const & c) const { - display(out, c, m_display_var); + std::ostream& display(std::ostream & out, clause const & c) const { + return display(out, c, m_display_var); } - void display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { if (num == 0) { out << "false"; } @@ -2591,13 +2885,14 @@ namespace nlsat { } out << ")"; } + return out; } - void display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { - display_smt2(out, c.size(), c.c_ptr(), proc); + std::ostream& display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { + return display_smt2(out, c.size(), c.c_ptr(), proc); } - void display_abst(std::ostream & out, literal l) const { + std::ostream& display_abst(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2609,25 +2904,27 @@ namespace nlsat { else { out << "b" << l.var(); } + return out; } - void display_abst(std::ostream & out, unsigned num, literal const * ls) const { + std::ostream& display_abst(std::ostream & out, unsigned num, literal const * ls) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display_abst(out, ls[i]); } + return out; } - void display_abst(std::ostream & out, scoped_literal_vector const & cs) const { - display_abst(out, cs.size(), cs.c_ptr()); + std::ostream& display_abst(std::ostream & out, scoped_literal_vector const & cs) const { + return display_abst(out, cs.size(), cs.c_ptr()); } - void display_abst(std::ostream & out, clause const & c) const { - display_abst(out, c.size(), c.c_ptr()); + std::ostream& display_abst(std::ostream & out, clause const & c) const { + return display_abst(out, c.size(), c.c_ptr()); } - void display_mathematica(std::ostream & out, clause const & c) const { + std::ostream& display_mathematica(std::ostream & out, clause const & c) const { out << "("; unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { @@ -2636,12 +2933,13 @@ namespace nlsat { display_mathematica(out, c[i]); } out << ")"; + return out; } // Debugging support: // Display generated lemma in Mathematica format. // Mathematica must reduce lemma to True (modulo resource constraints). - void display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { + std::ostream& display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { out << "Resolve[ForAll[{"; // var definition for (unsigned i = 0; i < num_vars(); i++) { @@ -2662,71 +2960,69 @@ namespace nlsat { display_mathematica(out, ls[i]); } out << "], Reals]\n"; // end of exists + return out; } - void display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display(out, *(cs[i]), proc); - out << "\n"; + std::ostream& display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { + for (clause* c : cs) { + display(out, *c, proc) << "\n"; } + return out; } - void display(std::ostream & out, clause_vector const & cs) const { - display(out, cs, m_display_var); + std::ostream& display(std::ostream & out, clause_vector const & cs) const { + return display(out, cs, m_display_var); } - void display_mathematica(std::ostream & out, clause_vector const & cs) const { + std::ostream& display_mathematica(std::ostream & out, clause_vector const & cs) const { unsigned sz = cs.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) out << ",\n"; - out << " "; - display_mathematica(out, *(cs[i])); + display_mathematica(out << " ", *(cs[i])); } + return out; } - void display_abst(std::ostream & out, clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display_abst(out, *(cs[i])); - out << "\n"; + std::ostream& display_abst(std::ostream & out, clause_vector const & cs) const { + for (clause* c : cs) { + display_abst(out, *c) << "\n"; } + return out; } - void display(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, display_var_proc const & proc) const { display(out, m_clauses, proc); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display(out, m_learned, proc); + display(out << "Lemmas:\n", m_learned, proc); } + return out; } - void display_mathematica(std::ostream & out) const { - out << "{\n"; - display_mathematica(out, m_clauses); - out << "}\n"; + std::ostream& display_mathematica(std::ostream & out) const { + return display_mathematica(out << "{\n", m_clauses) << "}\n"; } - void display_abst(std::ostream & out) const { + std::ostream& display_abst(std::ostream & out) const { display_abst(out, m_clauses); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display_abst(out, m_learned); + display_abst(out << "Lemmas:\n", m_learned); } + return out; } - void display(std::ostream & out) const { + std::ostream& display(std::ostream & out) const { display(out, m_display_var); - display_assignment(out); + return display_assignment(out); } - void display_vars(std::ostream & out) const { + std::ostream& display_vars(std::ostream & out) const { for (unsigned i = 0; i < num_vars(); i++) { out << i << " -> "; m_display_var(out, i); out << "\n"; } + return out; } - void display_smt2_arith_decls(std::ostream & out) const { + std::ostream& display_smt2_arith_decls(std::ostream & out) const { unsigned sz = m_is_int.size(); for (unsigned i = 0; i < sz; i++) { if (m_is_int[i]) @@ -2734,31 +3030,32 @@ namespace nlsat { else out << "(declare-fun x" << i << " () Real)\n"; } + return out; } - void display_smt2_bool_decls(std::ostream & out) const { + std::ostream& display_smt2_bool_decls(std::ostream & out) const { unsigned sz = m_atoms.size(); for (unsigned i = 0; i < sz; i++) { if (m_atoms[i] == 0) out << "(declare-fun b" << i << " () Bool)\n"; } + return out; } - void display_smt2(std::ostream & out) const { + std::ostream& display_smt2(std::ostream & out) const { display_smt2_bool_decls(out); display_smt2_arith_decls(out); out << "(assert (and true\n"; - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; i++) { - display_smt2(out, *(m_clauses[i])); - out << "\n"; + for (clause* c : m_clauses) { + display_smt2(out, *c) << "\n"; } out << "))\n(check-sat)" << std::endl; + return out; } }; - solver::solver(reslimit& rlim, params_ref const & p) { - m_imp = alloc(imp, *this, rlim, p); + solver::solver(reslimit& rlim, params_ref const & p, bool incremental) { + m_imp = alloc(imp, *this, rlim, p, incremental); } solver::~solver() { diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index ac503c603..c632a0334 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -35,7 +35,7 @@ namespace nlsat { struct imp; imp * m_imp; public: - solver(reslimit& rlim, params_ref const & p); + solver(reslimit& rlim, params_ref const & p, bool incremental); ~solver(); /** diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index db3b6ffa5..647a5e3ee 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -47,6 +47,8 @@ namespace nlsat { typedef polynomial::var_vector var_vector; typedef polynomial::manager pmanager; typedef polynomial::polynomial poly; + typedef polynomial::monomial monomial; + typedef polynomial::numeral numeral; const var null_var = polynomial::null_var; const var true_bool_var = 0; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 510f503e7..9de7215e3 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -32,11 +32,11 @@ class nlsat_tactic : public tactic { ast_manager & m; expr_ref_vector m_var2expr; expr_display_var_proc(ast_manager & _m):m(_m), m_var2expr(_m) {} - virtual void operator()(std::ostream & out, nlsat::var x) const { + virtual std::ostream& operator()(std::ostream & out, nlsat::var x) const { if (x < m_var2expr.size()) - out << mk_ismt2_pp(m_var2expr.get(x), m); + return out << mk_ismt2_pp(m_var2expr.get(x), m); else - out << "x!" << x; + return out << "x!" << x; } }; @@ -51,7 +51,7 @@ class nlsat_tactic : public tactic { m(_m), m_params(p), m_display_var(_m), - m_solver(m.limit(), p) { + m_solver(m.limit(), p, false) { } void updt_params(params_ref const & p) { diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index 22f64af47..47b9e0505 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -48,11 +48,15 @@ tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { purify_p), mk_propagate_values_tactic(m, p), mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), mk_elim_uncnstr_tactic(m, p), mk_elim_term_ite_tactic(m, p)), and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection factor, mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), using_params(mk_simplify_tactic(m, p), main_p), mk_tseitin_cnf_core_tactic(m, p), diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index ab5095328..e28f6ae4f 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -782,7 +782,7 @@ namespace qe { m(m), m_mode(mode), m_params(p), - m_solver(m.limit(), p), + m_solver(m.limit(), p, true), m_nftactic(0), m_rmodel(m_solver.am()), m_rmodel0(m_solver.am()), diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 65d474182..5df523ff7 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -44,6 +44,7 @@ class solve_eqs_tactic : public tactic { expr_sparse_mark m_candidate_set; ptr_vector m_candidates; ptr_vector m_vars; + expr_sparse_mark m_nonzero; ptr_vector m_ordered_vars; bool m_produce_proofs; bool m_produce_unsat_cores; @@ -55,8 +56,7 @@ class solve_eqs_tactic : public tactic { m_r_owner(r == 0 || owner), m_a_util(m), m_num_steps(0), - m_num_eliminated_vars(0) - { + m_num_eliminated_vars(0) { updt_params(p); if (m_r == 0) m_r = mk_default_expr_replacer(m); @@ -78,7 +78,7 @@ class solve_eqs_tactic : public tactic { void checkpoint() { if (m().canceled()) throw tactic_exception(m().limit().get_cancel_msg()); - cooperate("solve-eqs"); + cooperate("solve-eqs"); } // Check if the number of occurrences of t is below the specified threshold :solve-eqs-max-occs @@ -106,7 +106,8 @@ class solve_eqs_tactic : public tactic { } } bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { - if (trivial_solve1(lhs, rhs, var, def, pr)) return true; + if (trivial_solve1(lhs, rhs, var, def, pr)) + return true; if (trivial_solve1(rhs, lhs, var, def, pr)) { if (m_produce_proofs) { pr = m().mk_commutativity(m().mk_eq(lhs, rhs)); @@ -187,6 +188,77 @@ class solve_eqs_tactic : public tactic { } return false; } + + void add_pos(expr* f) { + expr* lhs = nullptr, *rhs = nullptr; + rational val; + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_not(f, f)) { + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_eq(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_zero()) { + m_nonzero.mark(lhs); + } + } + } + + bool is_nonzero(expr* e) { + return m_nonzero.is_marked(e); + } + + bool isolate_var(app* arg, app_ref& var, expr_ref& div, unsigned i, app* lhs, expr* rhs) { + if (!m_a_util.is_mul(arg)) return false; + unsigned n = arg->get_num_args(); + for (unsigned j = 0; j < n; ++j) { + expr* e = arg->get_arg(j); + bool ok = is_uninterp_const(e) && check_occs(e) && !occurs(e, rhs) && !occurs_except(e, lhs, i); + if (!ok) continue; + var = to_app(e); + for (unsigned k = 0; ok && k < n; ++k) { + expr* arg_k = arg->get_arg(k); + ok = k == j || (!occurs(var, arg_k) && is_nonzero(arg_k)); + } + if (!ok) continue; + ptr_vector args; + for (unsigned k = 0; k < n; ++k) { + if (k != j) args.push_back(arg->get_arg(k)); + } + div = m_a_util.mk_mul(args.size(), args.c_ptr()); + return true; + } + return false; + } + + bool solve_nl(app * lhs, expr * rhs, expr* eq, app_ref& var, expr_ref & def, proof_ref & pr) { + SASSERT(m_a_util.is_add(lhs)); + if (m_a_util.is_int(lhs)) return false; + unsigned num = lhs->get_num_args(); + expr_ref div(m()); + for (unsigned i = 0; i < num; i++) { + expr * arg = lhs->get_arg(i); + if (is_app(arg) && isolate_var(to_app(arg), var, div, i, lhs, rhs)) { + ptr_vector args; + for (unsigned k = 0; k < num; ++k) { + if (k != i) args.push_back(lhs->get_arg(k)); + } + def = m_a_util.mk_sub(rhs, m_a_util.mk_add(args.size(), args.c_ptr())); + def = m_a_util.mk_div(def, div); + if (m_produce_proofs) + pr = m().mk_rewrite(eq, m().mk_eq(var, def)); + return true; + } + } + return false; + } bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { SASSERT(m_a_util.is_add(lhs)); @@ -204,7 +276,8 @@ class solve_eqs_tactic : public tactic { break; } else if (m_a_util.is_mul(arg, a, v) && - is_uninterp_const(v) && !m_candidate_vars.is_marked(v) && + is_uninterp_const(v) && + !m_candidate_vars.is_marked(v) && m_a_util.is_numeral(a, a_val) && !a_val.is_zero() && (!is_int || a_val.is_minus_one()) && @@ -252,16 +325,20 @@ class solve_eqs_tactic : public tactic { return (m_a_util.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, var, def, pr)) || (m_a_util.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, var, def, pr)); +#if 0 + // better done inside of nlsat + (m_a_util.is_add(lhs) && solve_nl(to_app(lhs), rhs, eq, var, def, pr)) || + (m_a_util.is_add(rhs) && solve_nl(to_app(rhs), lhs, eq, var, def, pr)); +#endif } bool solve(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) { - if (m().is_eq(f)) { - if (trivial_solve(to_app(f)->get_arg(0), to_app(f)->get_arg(1), var, def, pr)) + expr* arg1 = 0, *arg2 = 0; + if (m().is_eq(f, arg1, arg2)) { + if (trivial_solve(arg1, arg2, var, def, pr)) return true; if (m_theory_solver) { - expr * lhs = to_app(f)->get_arg(0); - expr * rhs = to_app(f)->get_arg(1); - if (solve_arith(lhs, rhs, f, var, def, pr)) + if (solve_arith(arg1, arg2, f, var, def, pr)) return true; } return false; @@ -321,11 +398,14 @@ class solve_eqs_tactic : public tactic { m_candidate_set.reset(); m_candidates.reset(); m_vars.reset(); - + m_nonzero.reset(); app_ref var(m()); expr_ref def(m()); proof_ref pr(m()); unsigned size = g.size(); + for (unsigned idx = 0; idx < size; idx++) { + add_pos(g.form(idx)); + } for (unsigned idx = 0; idx < size; idx++) { checkpoint(); expr * f = g.form(idx); @@ -347,10 +427,8 @@ class solve_eqs_tactic : public tactic { TRACE("solve_eqs", tout << "candidate vars:\n"; - ptr_vector::iterator it = m_vars.begin(); - ptr_vector::iterator end = m_vars.end(); - for (; it != end; ++it) { - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_vars) { + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); } @@ -374,12 +452,9 @@ class solve_eqs_tactic : public tactic { typedef std::pair frame; svector todo; - ptr_vector::const_iterator it = m_vars.begin(); - ptr_vector::const_iterator end = m_vars.end(); - unsigned num; - for (; it != end; ++it) { + unsigned num = 0; + for (app* v : m_vars) { checkpoint(); - app * v = *it; if (!m_candidate_vars.is_marked(v)) continue; todo.push_back(frame(v, 0)); @@ -483,20 +558,19 @@ class solve_eqs_tactic : public tactic { } // cleanup - it = m_vars.begin(); - for (unsigned idx = 0; it != end; ++it, ++idx) { - if (!m_candidate_vars.is_marked(*it)) { + unsigned idx = 0; + for (expr* v : m_vars) { + if (!m_candidate_vars.is_marked(v)) { m_candidate_set.mark(m_candidates[idx], false); } + ++idx; } TRACE("solve_eqs", tout << "ordered vars:\n"; - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - SASSERT(m_candidate_vars.is_marked(*it)); - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_ordered_vars) { + SASSERT(m_candidate_vars.is_marked(v)); + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); m_candidate_vars.reset(); @@ -609,10 +683,7 @@ class solve_eqs_tactic : public tactic { if (m_produce_models) { if (mc.get() == 0) mc = alloc(gmc, m()); - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - app * v = *it; + for (app* v : m_ordered_vars) { expr * def = 0; proof * pr; expr_dependency * dep; From b78c538e021763ef6608801bfa84d593964a63f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Dec 2017 22:58:41 -0800 Subject: [PATCH 56/72] fix build of test Signed-off-by: Nikolaj Bjorner --- src/test/nlsat.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index ecf73843f..19add1fab 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -272,7 +272,7 @@ static void tst4() { static void tst5() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -330,7 +330,7 @@ static nlsat::literal mk_eq(nlsat::solver& s, nlsat::poly* p) { static void tst6() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -390,7 +390,7 @@ static void tst6() { static void tst7() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); nlsat::pmanager & pm = s.pm(); nlsat::var x0, x1, x2, a, b, c, d; a = s.mk_var(false); @@ -443,7 +443,7 @@ static void tst7() { static void tst8() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -492,7 +492,7 @@ static void tst8() { static void tst9() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -624,7 +624,7 @@ static bool satisfies_root(nlsat::solver& s, nlsat::atom::kind k, nlsat::poly* p static void tst10() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); From 8dadd30db5e1f09739bcb877e9dc5fb3240b1cf9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 17:11:43 -0800 Subject: [PATCH 57/72] add __copy__, __deepcopy__ as alias to translate on same context #1427. Add generalized Gaussian elimination as an option to first-pass NL solver Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 24 +++++++++++++++++++ .../bit_blaster/bit_blaster_tpl_def.h | 1 - src/nlsat/nlsat_params.pyg | 1 + src/nlsat/nlsat_solver.cpp | 7 +++--- src/tactic/smtlogics/qfnra_tactic.cpp | 6 +++-- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4cc401156..20c521df6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -365,6 +365,12 @@ class AstRef(Z3PPObject): _z3_assert(isinstance(target, Context), "argument must be a Z3 context") return _to_ast_ref(Z3_translate(self.ctx.ref(), self.as_ast(), target.ref()), target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def hash(self): """Return a hashcode for the `self`. @@ -5048,6 +5054,12 @@ class Goal(Z3PPObject): _z3_assert(isinstance(target, Context), "target must be a context") return Goal(goal=Z3_goal_translate(self.ctx.ref(), self.goal, target.ref()), ctx=target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def simplify(self, *arguments, **keywords): """Return a new simplified goal. @@ -5230,6 +5242,12 @@ class AstVector(Z3PPObject): """ return AstVector(Z3_ast_vector_translate(self.ctx.ref(), self.vector, other_ctx.ref()), other_ctx) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def __repr__(self): return obj_to_string(self) @@ -6430,6 +6448,12 @@ class Solver(Z3PPObject): solver = Z3_solver_translate(self.ctx.ref(), self.solver, target.ref()) return Solver(solver, target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + 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/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index a80994f6c..cf7e7c951 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -1193,7 +1193,6 @@ bool bit_blaster_tpl::mk_const_case_multiplier(unsigned sz, expr * const * return false; } SASSERT(out_bits.empty()); - ptr_buffer na_bits; na_bits.append(sz, a_bits); ptr_buffer nb_bits; diff --git a/src/nlsat/nlsat_params.pyg b/src/nlsat/nlsat_params.pyg index 6b1577113..0f2e03069 100644 --- a/src/nlsat/nlsat_params.pyg +++ b/src/nlsat/nlsat_params.pyg @@ -10,6 +10,7 @@ def_module_params('nlsat', ('randomize', BOOL, True, "randomize selection of a witness in nlsat."), ('max_conflicts', UINT, UINT_MAX, "maximum number of conflicts."), ('shuffle_vars', BOOL, False, "use a random variable order."), + ('inline_vars', BOOL, False, "inline variables that can be isolated from equations"), ('seed', UINT, 0, "random seed."), ('factor', BOOL, True, "factor polynomials produced during conflict resolution.") )) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 4cba6d123..448aa624d 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -154,6 +154,7 @@ namespace nlsat { bool m_randomize; bool m_random_order; unsigned m_random_seed; + bool m_inline_vars; unsigned m_max_conflicts; // statistics @@ -210,6 +211,7 @@ namespace nlsat { m_max_conflicts = p.max_conflicts(); m_random_order = p.shuffle_vars(); m_random_seed = p.seed(); + m_inline_vars = p.inline_vars(); m_ism.set_seed(m_random_seed); m_explain.set_simplify_cores(m_simplify_cores); m_explain.set_minimize_cores(min_cores); @@ -1313,11 +1315,8 @@ namespace nlsat { m_explain.set_full_dimensional(is_full_dimensional()); bool reordered = false; -#if 0 - // disabled - if (!m_incremental) + if (!m_incremental && m_inline_vars) simplify(); -#endif if (!can_reorder()) { diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index 63c09c19c..cc01950a2 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -33,7 +33,9 @@ static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigne } tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { - params_ref p1 = p; + params_ref p0 = p; + p0.set_bool("inline_vars", true); + params_ref p1 = p; p1.set_uint("seed", 11); p1.set_bool("factor", false); params_ref p2 = p; @@ -42,7 +44,7 @@ tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { return and_then(mk_simplify_tactic(m, p), mk_propagate_values_tactic(m, p), - or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000), + or_else(try_for(mk_qfnra_nlsat_tactic(m, p0), 5000), try_for(mk_qfnra_nlsat_tactic(m, p1), 10000), mk_qfnra_sat_solver(m, p, 4), and_then(try_for(mk_smt_tactic(), 5000), mk_fail_if_undecided_tactic()), From f0a30ded7db8aa1e93cf91840ae2469e51c5deb5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 19:25:09 -0800 Subject: [PATCH 58/72] add shorthand for translating models #1407 Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 12 ++++++++++++ src/api/c++/z3++.h | 2 ++ src/api/python/z3/z3.py | 31 +++++++++++++++++++++++++------ src/api/z3_api.h | 7 +++++++ src/smt/theory_seq.cpp | 3 ++- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index bda33f186..d9936ff66 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -212,6 +212,18 @@ extern "C" { RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } + + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context target) { + Z3_TRY; + LOG_Z3_model_translate(c, m, target); + RESET_ERROR_CODE(); + Z3_model_ref* dst = alloc(Z3_model_ref, *mk_c(target)); + ast_translation tr(mk_c(c)->m(), mk_c(target)->m()); + dst->m_model = to_model_ref(m)->translate(tr); + mk_c(target)->save_object(dst); + RETURN_Z3(of_model(dst)); + Z3_CATCH_RETURN(0); + } Z3_bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a) { Z3_TRY; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8ff2be239..b1e667e9f 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1809,9 +1809,11 @@ namespace z3 { Z3_model_inc_ref(ctx(), m); } public: + struct translate {}; model(context & c):object(c) { init(Z3_mk_model(c)); } model(context & c, Z3_model m):object(c) { init(m); } model(model const & s):object(s) { init(s.m_model); } + model(model& src, context& dst, translate) : object(dst) { init(Z3_model_translate(src.ctx(), src, dst)); } ~model() { Z3_model_dec_ref(ctx(), m_model); } operator Z3_model() const { return m_model; } model & operator=(model const & s) { diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 20c521df6..465e9aab8 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5585,6 +5585,17 @@ class FuncInterp(Z3PPObject): raise IndexError return FuncEntry(Z3_func_interp_get_entry(self.ctx.ref(), self.f, idx), self.ctx) + def translate(self, other_ctx): + """Copy model 'self' to context 'other_ctx'. + """ + return ModelRef(Z3_model_translate(self.ctx.ref(), self.model, other_ctx.ref()), other_ctx) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def as_list(self): """Return the function interpretation as a Python list. >>> f = Function('f', IntSort(), IntSort()) @@ -5614,9 +5625,6 @@ class ModelRef(Z3PPObject): self.ctx = ctx Z3_model_inc_ref(self.ctx.ref(), self.model) - def __deepcopy__(self, memo={}): - return ModelRef(self.m, self.ctx) - def __del__(self): if self.ctx.ref() is not None: Z3_model_dec_ref(self.ctx.ref(), self.model) @@ -5870,6 +5878,20 @@ class ModelRef(Z3PPObject): r.append(FuncDeclRef(Z3_model_get_func_decl(self.ctx.ref(), self.model, i), self.ctx)) return r + def translate(self, target): + """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. + """ + if __debug__: + _z3_assert(isinstance(target, Context), "argument must be a Z3 context") + model = Z3_model_translate(self.ctx.ref(), self.model, target.ref()) + return Model(model, target) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def is_as_array(n): """Return true if n is a Z3 expression of the form (_ as-array f).""" return isinstance(n, ExprRef) and Z3_is_as_array(n.ctx.ref(), n.as_ast()) @@ -6072,9 +6094,6 @@ class Solver(Z3PPObject): self.solver = solver Z3_solver_inc_ref(self.ctx.ref(), self.solver) - def __deepcopy__(self, memo={}): - return Solver(self.solver, self.ctx) - def __del__(self): if self.solver is not None and self.ctx.ref() is not None: Z3_solver_dec_ref(self.ctx.ref(), self.solver) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 007bc3ab6..0ba49a5e5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4896,6 +4896,13 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_model_get_sort_universe(Z3_context c, Z3_model m, Z3_sort s); + /** + \brief translate model from context c to context \c dst. + + def_API('Z3_model_translate', MODEL, (_in(CONTEXT), _in(MODEL), _in(CONTEXT))) + */ + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context dst); + /** \brief The \ccode{(_ as-array f)} AST node is a construct for assigning interpretations for arrays in Z3. It is the array such that forall indices \c i we have that \ccode{(select (_ as-array f) i)} is equal to \ccode{(f i)}. diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 597348589..27ed95155 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3218,9 +3218,10 @@ void theory_seq::add_indexof_axiom(expr* i) { literal t_eq_empty = mk_eq_empty(t); // |t| = 0 => |s| = 0 or indexof(t,s,offset) = -1 - // ~contains(t,s) => indexof(t,s,offset) = -1 + // ~contains(t,s) <=> indexof(t,s,offset) = -1 add_axiom(cnt, i_eq_m1); + add_axiom(~cnt, ~i_eq_m1); add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { From c1c1b7378cffe3ac0781d4765fd1602c40531d33 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 19:44:16 -0800 Subject: [PATCH 59/72] removing axiom exposing unsoundness, replace by weaker axiom Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 27ed95155..f91685d43 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3221,7 +3221,7 @@ void theory_seq::add_indexof_axiom(expr* i) { // ~contains(t,s) <=> indexof(t,s,offset) = -1 add_axiom(cnt, i_eq_m1); - add_axiom(~cnt, ~i_eq_m1); +// add_axiom(~cnt, ~i_eq_m1); add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { @@ -3234,6 +3234,7 @@ void theory_seq::add_indexof_axiom(expr* i) { add_axiom(~s_eq_empty, i_eq_0); add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy)); add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx, false)); + add_axiom(~cnt, mk_literal(m_autil.mk_ge(i, zero))); tightest_prefix(s, x); } else { From e8a9e1a58b3dac9155e93bd2b61ee89ba1275771 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 20:04:55 -0800 Subject: [PATCH 60/72] set default rewriter behavior in incremental mode to distribute multiplication over addition #1373 Signed-off-by: Nikolaj Bjorner --- src/smt/asserted_formulas.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 56600266a..6ddce341d 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -131,6 +131,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { p.set_bool("gcd_rounding", true); p.set_bool("expand_select_store", true); p.set_bool("bv_sort_ac", true); + p.set_bool("som", true); m_rewriter.updt_params(p); flush_cache(); } From 73b3da37d898c261892807197f72df48711383ab Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 22:47:52 +0700 Subject: [PATCH 61/72] Typo fixes. --- README-CMake.md | 4 +- RELEASE_NOTES | 2 +- cmake/Z3Config.cmake.in | 2 +- contrib/suppressions/sanitizers/README.md | 2 +- examples/c/test_capi.c | 4 +- examples/dotnet/Program.cs | 2 +- examples/java/JavaExample.java | 2 +- examples/maxsat/README | 2 +- src/api/dotnet/Context.cs | 12 +++--- src/api/dotnet/Expr.cs | 14 +++---- src/api/dotnet/Model.cs | 2 +- src/api/java/Context.java | 6 +-- src/api/java/Expr.java | 10 ++--- src/api/java/Model.java | 2 +- src/api/ml/z3.mli | 26 ++++++------ src/api/python/z3/z3.py | 10 ++--- src/api/z3_api.h | 50 +++++++++++------------ src/ast/ast.h | 14 +++---- src/ast/proofs/proof_checker.cpp | 2 +- src/interp/iz3proof_itp.cpp | 8 ++-- src/interp/iz3translate_direct.cpp | 2 +- src/math/simplex/simplex_def.h | 2 +- src/muz/rel/dl_compiler.h | 2 +- src/muz/rel/dl_relation_manager.h | 2 +- src/nlsat/nlsat_solver.cpp | 8 ++-- src/qe/qe_lite.cpp | 2 +- src/smt/mam.cpp | 4 +- src/smt/smt_internalizer.cpp | 12 +++--- src/smt/smt_model_finder.cpp | 22 +++++----- src/smt/smt_quantifier.h | 2 +- src/smt/theory_arith.h | 2 +- src/tactic/arith/purify_arith_tactic.h | 2 +- src/tactic/ufbv/ufbv_rewriter.h | 2 +- 33 files changed, 120 insertions(+), 120 deletions(-) diff --git a/README-CMake.md b/README-CMake.md index 0d323e08f..1b1f72729 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -5,7 +5,7 @@ of the project written in the ``CMakeLists.txt`` files and emits a build system for that project of your choice using one of CMake's "generators". This allows CMake to support many different platforms and build tools. You can run ``cmake --help`` to see the list of supported "generators" -on your platform. Example generators include "UNIX Makfiles" and "Visual Studio +on your platform. Example generators include "UNIX Makefiles" and "Visual Studio 12 2013". ## Getting started @@ -44,7 +44,7 @@ cmake -G "Unix Makefiles" ../ make -j4 # Replace 4 with an appropriate number ``` -Note that on some platforms "Unix Makesfiles" is the default generator so on those +Note that on some platforms "Unix Makefiles" is the default generator so on those platforms you don't need to pass ``-G "Unix Makefiles"`` command line option to ``cmake``. diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 4f10cad26..5ce4d2682 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -712,7 +712,7 @@ The following bugs are fixed in this release: bvshl when using a shift amount that evaluates to the length of the bit-vector. Thanks to Trevor Hansen and Robert Brummayer. -- Incorrect NNF conversion in linear quantifier elimniation routines. +- Incorrect NNF conversion in linear quantifier elimination routines. Thanks to Josh Berdine. - Missing constant folding of extraction for large bit-vectors. diff --git a/cmake/Z3Config.cmake.in b/cmake/Z3Config.cmake.in index e7f604591..dbd63b103 100644 --- a/cmake/Z3Config.cmake.in +++ b/cmake/Z3Config.cmake.in @@ -2,7 +2,7 @@ # @AUTO_GEN_MSG@ # # This file is intended to be consumed by clients who wish to use Z3 from CMake. -# It can be use by doing `find_package(Z3 config)` from within a +# It can be used by doing `find_package(Z3 config)` from within a # `CMakeLists.txt` file. If CMake doesn't find this package automatically you # can give it a hint by passing `-DZ3_DIR=` to the CMake invocation where # `` is the path to the directory containing this file. diff --git a/contrib/suppressions/sanitizers/README.md b/contrib/suppressions/sanitizers/README.md index f76f920b2..1d7cd0ac8 100644 --- a/contrib/suppressions/sanitizers/README.md +++ b/contrib/suppressions/sanitizers/README.md @@ -1,4 +1,4 @@ -# Sanitizer supression files +# Sanitizer suppression files This directory contains files used to suppress ASan/LSan/UBSan warnings/errors. diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index d71771f98..b947928a7 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -1546,7 +1546,7 @@ void two_contexts_example1() } /** - \brief Demonstrates how error codes can be read insted of registering an error handler. + \brief Demonstrates how error codes can be read instead of registering an error handler. */ void error_code_example1() { @@ -2533,7 +2533,7 @@ void reference_counter_example() { cfg = Z3_mk_config(); Z3_set_param_value(cfg, "model", "true"); - // Create a Z3 context where the user is reponsible for managing + // Create a Z3 context where the user is responsible for managing // Z3_ast reference counters. ctx = Z3_mk_context_rc(cfg); Z3_del_config(cfg); diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 71364013b..aec3bdcc5 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -622,7 +622,7 @@ namespace test_mapi Console.WriteLine("{0}", q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.MkBound(1, ctx.IntSort); Expr y = ctx.MkBound(0, ctx.IntSort); diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 40fb25a92..7b8902768 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -660,7 +660,7 @@ class JavaExample System.out.println(q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.mkBound(1, ctx.getIntSort()); Expr y = ctx.mkBound(0, ctx.getIntSort()); diff --git a/examples/maxsat/README b/examples/maxsat/README index e5e4ba610..6c24da66b 100644 --- a/examples/maxsat/README +++ b/examples/maxsat/README @@ -9,4 +9,4 @@ On OSX and Linux, you must install z3 first using sudo make install OR update LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (OSX) with the build directory. You need that to be able to find the Z3 shared library. -This directory contains a test file (ex.smt) that can be use as input for the maxsat test application. +This directory contains a test file (ex.smt) that can be used as input for the maxsat test application. diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index ac23d1dbc..cbd6a1bac 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2262,7 +2262,7 @@ namespace Microsoft.Z3 /// Maps f on the argument arrays. /// /// - /// Eeach element of args must be of an array sort [domain_i -> range_i]. + /// Each element of args must be of an array sort [domain_i -> range_i]. /// The function declaration f must have type range_1 .. range_n -> range. /// v must have sort range. The sort of the result is [domain_i -> range]. /// @@ -2862,7 +2862,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2878,7 +2878,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2894,7 +2894,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2910,7 +2910,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -3211,7 +3211,7 @@ namespace Microsoft.Z3 /// Create an existential Quantifier. /// /// - /// Creates an existential quantifier using de-Brujin indexed variables. + /// Creates an existential quantifier using de-Bruijn 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) diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 4fd306052..0726f9d53 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -959,7 +959,7 @@ namespace Microsoft.Z3 /// Tn: (R t_n s_n) /// [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) /// Remark: if t_i == s_i, then the antecedent Ti is suppressed. - /// That is, reflexivity proofs are supressed to save space. + /// That is, reflexivity proofs are suppressed to save space. /// public bool IsProofMonotonicity { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_MONOTONICITY; } } @@ -1002,7 +1002,7 @@ namespace Microsoft.Z3 public bool IsProofAndElimination { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_AND_ELIM; } } /// - /// Indicates whether the term is a proof by eliminiation of not-or + /// Indicates whether the term is a proof by elimination of not-or /// /// /// Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). @@ -1112,7 +1112,7 @@ namespace Microsoft.Z3 public bool IsProofQuantInst { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_QUANT_INST; } } /// - /// Indicates whether the term is a hypthesis marker. + /// Indicates whether the term is a hypothesis marker. /// /// Mark a hypothesis in a natural deduction style proof. public bool IsProofHypothesis { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_HYPOTHESIS; } } @@ -1433,7 +1433,7 @@ namespace Microsoft.Z3 /// /// Filter (restrict) a relation with respect to a predicate. /// The first argument is a relation. - /// The second argument is a predicate with free de-Brujin indices + /// The second argument is a predicate with free de-Bruijn indices /// corresponding to the columns of the relation. /// So the first column in the relation has index 0. /// @@ -1649,7 +1649,7 @@ namespace Microsoft.Z3 public bool IsFPMul { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MUL; } } /// - /// Indicates whether the term is a floating-point divison term + /// Indicates whether the term is a floating-point division term /// public bool IsFPDiv { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_DIV; } } @@ -1709,7 +1709,7 @@ namespace Microsoft.Z3 public bool IsFPLe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_LE; } } /// - /// Indicates whether the term is a floating-point greater-than or erqual term + /// Indicates whether the term is a floating-point greater-than or equal term /// public bool IsFPGe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_GE; } } @@ -1789,7 +1789,7 @@ namespace Microsoft.Z3 #region Bound Variables /// - /// The de-Burijn index of a bound variable. + /// The de-Bruijn index of a bound variable. /// /// /// Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index 12992fa8a..d11a57052 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -253,7 +253,7 @@ namespace Microsoft.Z3 /// The uninterpreted sorts that the model has an interpretation for. /// /// - /// Z3 also provides an intepretation for uninterpreted sorts used in a formula. + /// Z3 also provides an interpretation for uninterpreted sorts used in a formula. /// The interpretation for a sort is a finite set of distinct values. We say this finite set is /// the "universe" of the sort. /// diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 3458f4d97..7e73fc15e 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2234,7 +2234,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2250,7 +2250,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2438,7 +2438,7 @@ public class Context implements AutoCloseable { } /** - * Creates an existential quantifier using de-Brujin indexed variables. + * Creates an existential quantifier using de-Bruijn indexed variables. * @see #mkForall(Sort[],Symbol[],Expr,int,Pattern[],Expr[],Symbol,Symbol) **/ public Quantifier mkExists(Sort[] sorts, Symbol[] names, Expr body, diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index d3793a24b..7b20b7993 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1421,7 +1421,7 @@ public class Expr extends AST * Remarks: T1: * (R t_1 s_1) ... Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... * t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is - * suppressed. That is, reflexivity proofs are supressed to save space. + * suppressed. That is, reflexivity proofs are suppressed to save space. * * @throws Z3Exception on error * @return a boolean @@ -1473,7 +1473,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a proof by eliminiation of not-or + * Indicates whether the term is a proof by elimination of not-or * Remarks: * Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). * T1: (not (or l_1 ... l_n)) [not-or-elim T1]: (not l_i) * @throws Z3Exception on error * @return a boolean @@ -1605,7 +1605,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a hypthesis marker. + * Indicates whether the term is a hypothesis marker. * Remarks: Mark a * hypothesis in a natural deduction style proof. * @throws Z3Exception on error @@ -1987,7 +1987,7 @@ public class Expr extends AST * Indicates whether the term is a relation filter * Remarks: Filter * (restrict) a relation with respect to a predicate. The first argument is - * a relation. The second argument is a predicate with free de-Brujin + * a relation. The second argument is a predicate with free de-Bruijn * indices corresponding to the columns of the relation. So the first column * in the relation has index 0. * @throws Z3Exception on error @@ -2094,7 +2094,7 @@ public class Expr extends AST } /** - * The de-Burijn index of a bound variable. + * The de-Bruijn index of a bound variable. * Remarks: Bound variables are * indexed by de-Bruijn indices. It is perhaps easiest to explain the * meaning of de-Bruijn indices by indicating the compilation process from diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 9c7013aca..d809b6790 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -239,7 +239,7 @@ public class Model extends Z3Object { /** * The uninterpreted sorts that the model has an interpretation for. - * Remarks: Z3 also provides an intepretation for uninterpreted sorts used + * Remarks: Z3 also provides an interpretation for uninterpreted sorts used * in a formula. The interpretation for a sort is a finite set of distinct * values. We say this finite set is the "universe" of the sort. * diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 80923a0c7..20a1e9c10 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -536,7 +536,7 @@ sig @return A Term with the given value and sort *) val mk_numeral_string : context -> string -> Sort.sort -> expr - (** Create a numeral of a given sort. This function can be use to create numerals that fit in a machine integer. + (** Create a numeral of a given sort. This function can be used to create numerals that fit in a machine integer. It is slightly faster than [MakeNumeral] since it is not necessary to parse a string. @return A Term with the given value and sort *) val mk_numeral_int : context -> int -> Sort.sort -> expr @@ -667,7 +667,7 @@ sig end - (** The de-Burijn index of a bound variable. + (** The de-Bruijn index of a bound variable. Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain the meaning of de-Bruijn indices by indicating the compilation process from @@ -830,7 +830,7 @@ sig (** Maps f on the argument arrays. - Eeach element of [args] must be of an array sort [[domain_i -> range_i]]. + Each element of [args] must be of an array sort [[domain_i -> range_i]]. The function declaration [f] must have type [ range_1 .. range_n -> range]. [v] must have sort range. The sort of the result is [[domain_i -> range]]. {!Z3Array.mk_sort} @@ -962,7 +962,7 @@ sig Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. *) val is_filter : Expr.expr -> bool @@ -2085,7 +2085,7 @@ sig (** Indicates whether an expression is a floating-point lt expression *) val is_lt : Expr.expr -> bool - (** Indicates whether an expression is a floating-point geqexpression *) + (** Indicates whether an expression is a floating-point geq expression *) val is_geq : Expr.expr -> bool (** Indicates whether an expression is a floating-point gt expression *) @@ -2233,7 +2233,7 @@ sig (** Conversion of a 2's complement unsigned bit-vector term into a term of FloatingPoint sort. *) val mk_to_fp_unsigned : context -> Expr.expr -> Expr.expr -> Sort.sort -> Expr.expr - (** C1onversion of a floating-point term into an unsigned bit-vector. *) + (** Conversion of a floating-point term into an unsigned bit-vector. *) val mk_to_ubv : context -> Expr.expr -> Expr.expr -> int -> Expr.expr (** Conversion of a floating-point term into a signed bit-vector. *) @@ -2385,7 +2385,7 @@ sig Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. *) + That is, reflexivity proofs are suppressed to save space. *) val is_monotonicity : Expr.expr -> bool (** Indicates whether the term is a quant-intro proof @@ -2417,7 +2417,7 @@ sig [and-elim T1]: l_i *) val is_and_elimination : Expr.expr -> bool - (** Indicates whether the term is a proof by eliminiation of not-or + (** Indicates whether the term is a proof by elimination of not-or Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). T1: (not (or l_1 ... l_n)) @@ -2500,7 +2500,7 @@ sig A proof of (or (not (forall (x) (P x))) (P a)) *) val is_quant_inst : Expr.expr -> bool - (** Indicates whether the term is a hypthesis marker. + (** Indicates whether the term is a hypothesis marker. Mark a hypothesis in a natural deduction style proof. *) val is_hypothesis : Expr.expr -> bool @@ -2882,7 +2882,7 @@ sig (** The uninterpreted sorts that the model has an interpretation for. - Z3 also provides an intepretation for uninterpreted sorts used in a formula. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort is a finite set of distinct values. We say this finite set is the "universe" of the sort. {!get_num_sorts} @@ -3056,7 +3056,7 @@ sig (** Create a tactic that fails if the probe evaluates to false. *) val fail_if : context -> Probe.probe -> tactic - (** Create a tactic that fails if the goal is not triviall satisfiable (i.e., empty) + (** Create a tactic that fails if the goal is not trivially satisfiable (i.e., empty) or trivially unsatisfiable (i.e., contains `false'). *) val fail_if_not_decided : context -> tactic @@ -3105,7 +3105,7 @@ sig (** True if the entry is float-valued. *) val is_float : statistics_entry -> bool - (** The string representation of the the entry's value. *) + (** The string representation of the entry's value. *) val to_string_value : statistics_entry -> string (** The string representation of the entry (key and value) *) @@ -3370,7 +3370,7 @@ sig (** Assert a constraints into the optimize solver. *) val add : optimize -> Expr.expr list -> unit - (** Asssert a soft constraint. + (** Assert a soft constraint. Supply integer weight and string that identifies a group of soft constraints. *) val add_soft : optimize -> Expr.expr -> string -> Symbol.symbol -> handle diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 465e9aab8..4896a475d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -182,7 +182,7 @@ class Context: """Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions. This method can be invoked from a thread different from the one executing the - interruptable procedure. + interruptible procedure. """ Z3_interrupt(self.ref()) @@ -602,7 +602,7 @@ def _sort(ctx, a): return _to_sort_ref(Z3_get_sort(ctx.ref(), a), ctx) def DeclareSort(name, ctx=None): - """Create a new uninterpred sort named `name`. + """Create a new uninterpreted sort named `name`. If `ctx=None`, then the new sort is declared in the global Z3Py context. @@ -724,7 +724,7 @@ class FuncDeclRef(AstRef): The arguments must be Z3 expressions. This method assumes that the sorts of the elements in `args` match the sorts of the - domain. Limited coersion is supported. For example, if + domain. Limited coercion is supported. For example, if args[0] is a Python integer, and the function expects a Z3 integer, then the argument is automatically converted into a Z3 integer. @@ -9243,7 +9243,7 @@ def fpMul(rm, a, b, ctx=None): return _mk_fp_bin(Z3_mk_fpa_mul, rm, a, b, ctx) def fpDiv(rm, a, b, ctx=None): - """Create a Z3 floating-point divison expression. + """Create a Z3 floating-point division expression. >>> s = FPSort(8, 24) >>> rm = RNE() @@ -9270,7 +9270,7 @@ def fpRem(a, b, ctx=None): return _mk_fp_bin_norm(Z3_mk_fpa_rem, a, b, ctx) def fpMin(a, b, ctx=None): - """Create a Z3 floating-point minimium expression. + """Create a Z3 floating-point minimum expression. >>> s = FPSort(8, 24) >>> rm = RNE() diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0ba49a5e5..5e5b84450 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -270,7 +270,7 @@ typedef enum - Z3_OP_ARRAY_MAP Array map operator. It satisfies map[f](a1,..,a_n)[i] = f(a1[i],...,a_n[i]) for every i. - - Z3_OP_SET_UNION Set union between two Booelan arrays (two arrays whose range type is Boolean). The function is binary. + - Z3_OP_SET_UNION Set union between two Boolean arrays (two arrays whose range type is Boolean). The function is binary. - Z3_OP_SET_INTERSECT Set intersection between two Boolean arrays. The function is binary. @@ -406,7 +406,7 @@ typedef enum - Z3_OP_BSMUL_NO_UDFL: check that bit-wise signed multiplication does not underflow. Signed multiplication underflows if the operands have opposite signs and the result of multiplication - does not fit within the avaialble bits. Z3_mk_bvmul_no_underflow. + does not fit within the available bits. Z3_mk_bvmul_no_underflow. - Z3_OP_BSDIV_I: Binary signed division. It has the same semantics as Z3_OP_BSDIV, but created in a context where the second operand can be assumed to be non-zero. @@ -485,7 +485,7 @@ typedef enum [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) } Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. + That is, reflexivity proofs are suppressed to save space. - Z3_OP_PR_QUANT_INTRO: Given a proof for (~ p q), produces a proof for (~ (forall (x) p) (forall (x) q)). @@ -832,7 +832,7 @@ typedef enum - Z3_OP_RA_FILTER: Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. @@ -969,7 +969,7 @@ typedef enum - Z3_OP_FPA_TO_FP: Floating-point conversion (various) - - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigend bit-vector + - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigned bit-vector - Z3_OP_FPA_TO_UBV: Floating-point conversion to unsigned bit-vector @@ -984,7 +984,7 @@ typedef enum of non-relevant terms in theory_fpa) - Z3_OP_FPA_BV2RM: Conversion of a 3-bit bit-vector term to a - floating-point rouding-mode term + floating-point rounding-mode term The conversion uses the following values: 0 = 000 = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, @@ -1922,7 +1922,7 @@ extern "C" { \param c logical context \param name name of the enumeration sort. - \param n number of elemenets in enumeration sort. + \param n number of elements in enumeration sort. \param enum_names names of the enumerated elements. \param enum_consts constants corresponding to the enumerated elements. \param enum_testers predicates testing if terms of the enumeration sort correspond to an enumeration. @@ -3186,7 +3186,7 @@ extern "C" { \param c logical context. \param num numerator of rational. - \param den denomerator of rational. + \param den denominator of rational. \pre den != 0 @@ -3201,7 +3201,7 @@ extern "C" { /** \brief Create a numeral of an int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine integer. + This function can be used to create numerals that fit in a machine integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3213,7 +3213,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine unsinged integer. + This function can be used to create numerals that fit in a machine unsigned integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3225,7 +3225,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __int64 integer. + This function can be used to create numerals that fit in a machine __int64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3237,7 +3237,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __uint64 integer. + This function can be used to create numerals that fit in a machine __uint64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3493,8 +3493,8 @@ extern "C" { Z3_ast Z3_API Z3_mk_re_range(Z3_context c, Z3_ast lo, Z3_ast hi); /** - \brief Create a regular expression loop. The supplied regular expression \c r is repated - between \c lo and \c hi times. The \c lo should be below \c hi with one exection: when + \brief Create a regular expression loop. The supplied regular expression \c r is repeated + between \c lo and \c hi times. The \c lo should be below \c hi with one exception: when supplying the value \c hi as 0, the meaning is to repeat the argument \c r at least \c lo number of times, and with an unbounded upper bound. @@ -4248,7 +4248,7 @@ extern "C" { Z3_sort Z3_API Z3_get_decl_sort_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_AST @@ -4257,7 +4257,7 @@ extern "C" { Z3_ast Z3_API Z3_get_decl_ast_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_FUNC_DECL @@ -4327,7 +4327,7 @@ extern "C" { /** \brief Return a hash code for the given AST. - The hash code is structural. You can use Z3_get_ast_id interchangably with + The hash code is structural. You can use Z3_get_ast_id interchangeably with this function. def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST))) @@ -4556,7 +4556,7 @@ extern "C" { Z3_ast Z3_API Z3_get_pattern(Z3_context c, Z3_pattern p, unsigned idx); /** - \brief Return index of de-Brujin bound variable. + \brief Return index of de-Bruijn bound variable. \pre Z3_get_ast_kind(a) == Z3_VAR_AST @@ -4659,7 +4659,7 @@ extern "C" { Provides an interface to the AST simplifier used by Z3. It returns an AST object which is equal to the argument. - The returned AST is simplified using algebraic simplificaiton rules, + The returned AST is simplified using algebraic simplification rules, such as constant propagation (propagating true/false over logical connectives). def_API('Z3_simplify', AST, (_in(CONTEXT), _in(AST))) @@ -4861,9 +4861,9 @@ extern "C" { Z3_func_decl Z3_API Z3_model_get_func_decl(Z3_context c, Z3_model m, unsigned i); /** - \brief Return the number of uninterpreted sorts that \c m assigs an interpretation to. + \brief Return the number of uninterpreted sorts that \c m assigns an interpretation to. - Z3 also provides an intepretation for uninterpreted sorts used in a formua. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort \c s is a finite set of distinct values. We say this finite set is the "universe" of \c s. @@ -4971,7 +4971,7 @@ extern "C" { unsigned Z3_API Z3_func_interp_get_num_entries(Z3_context c, Z3_func_interp f); /** - \brief Return a "point" of the given function intepretation. It represents the + \brief Return a "point" of the given function interpretation. It represents the value of \c f in a particular point. \pre i < Z3_func_interp_get_num_entries(c, f) @@ -5013,7 +5013,7 @@ extern "C" { \brief add a function entry to a function interpretation. \param c logical context - \param fi a function interpregation to be updated. + \param fi a function interpretation to be updated. \param args list of arguments. They should be constant values (such as integers) and be of the same types as the domain of the function. \param value value of the function when the parameters match args. @@ -5466,7 +5466,7 @@ extern "C" { Z3_bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g); /** - \brief Copy a goal \c g from the context \c source to a the context \c target. + \brief Copy a goal \c g from the context \c source to the context \c target. def_API('Z3_goal_translate', GOAL, (_in(CONTEXT), _in(GOAL), _in(CONTEXT))) */ @@ -5932,7 +5932,7 @@ extern "C" { 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. + \brief Copy a solver \c s from the context \c source to the context \c target. def_API('Z3_solver_translate', SOLVER, (_in(CONTEXT), _in(SOLVER), _in(CONTEXT))) */ diff --git a/src/ast/ast.h b/src/ast/ast.h index 2d06d03de..24e2b93b6 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -330,7 +330,7 @@ std::ostream& operator<<(std::ostream& out, sort_size const & ss); // ----------------------------------- /** - \brief Extra information that may be attached to intepreted sorts. + \brief Extra information that may be attached to interpreted sorts. */ class sort_info : public decl_info { sort_size m_num_elements; @@ -932,7 +932,7 @@ struct builtin_name { }; /** - \brief Each family of intepreted function declarations and sorts must provide a plugin + \brief Each family of interpreted function declarations and sorts must provide a plugin to build sorts and decls of the family. */ class decl_plugin { @@ -1059,7 +1059,7 @@ protected: ptr_vector m_eq_decls; // cached eqs ptr_vector m_ite_decls; // cached ites - ptr_vector m_oeq_decls; // cached obsevational eqs + ptr_vector m_oeq_decls; // cached observational eqs sort * m_proof_sort; func_decl * m_undef_decl; func_decl * m_true_pr_decl; @@ -1161,7 +1161,7 @@ public: virtual expr * get_some_value(sort * s); }; -typedef app proof; /* a proof is just an applicaton */ +typedef app proof; /* a proof is just an application */ // ----------------------------------- // @@ -1220,7 +1220,7 @@ enum pattern_op_kind { /** \brief Patterns are used to group expressions. These expressions are using during E-matching for - heurisitic quantifier instantiation. + heuristic quantifier instantiation. */ class pattern_decl_plugin : public decl_plugin { public: @@ -1245,13 +1245,13 @@ enum model_value_op_kind { /** \brief Values are used during model construction. All values are assumed to be different. Users should not use them, since they may - introduce unsoundess if the sort of a value is finite. + introduce unsoundness if the sort of a value is finite. Moreover, values should never be internalized in a logical context. However, values can be used during evaluation (i.e., simplification). - \remark Model values can be viewed as the partion ids in Z3 1.x. + \remark Model values can be viewed as the partition ids in Z3 1.x. */ class model_value_decl_plugin : public decl_plugin { public: diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 6fd876efc..5126198c6 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -502,7 +502,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return false; } case PR_HYPOTHESIS: { - // TBD all branches with hyptheses must be closed by a later lemma. + // TBD all branches with hypotheses must be closed by a later lemma. if (match_proof(p) && match_fact(p, fml)) { return true; diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index fc9d0fac6..32cb9cccb 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -55,7 +55,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* The summation rule. The term sum(p,c,i) takes a proof p of an inequality i', an integer coefficient c and an inequality i, and - yieds a proof of i' + ci. */ + yields a proof of i' + ci. */ symb sum; /* Proof rotation. The proof term rotate(q,p) takes a @@ -75,7 +75,7 @@ class iz3proof_itp_impl : public iz3proof_itp { symb leq2eq; /* Equality to inequality. eq2leq(p, q) takes a proof p of x=y, and - a proof q ~(x <= y) and and yields a proof of false. */ + a proof q ~(x <= y) and yields a proof of false. */ symb eq2leq; /* Proof term cong(p,q) takes a proof p of x=y and a proof @@ -97,7 +97,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* This oprerator represents a concatenation of rewrites. The term a=b;c=d represents an A rewrite from a to b, followed by a B - rewrite fron b to c, followed by an A rewrite from c to d. + rewrite from b to c, followed by an A rewrite from c to d. */ symb concat; @@ -1542,7 +1542,7 @@ class iz3proof_itp_impl : public iz3proof_itp { return my_implies(arg(rew,1),arg(rew,2)); } - // make rewrite rew conditon on rewrite cond + // make rewrite rew condition on rewrite cond ast rewrite_conditional(const ast &cond, const ast &rew){ ast cf = rewrite_to_formula(cond); return make(sym(rew),arg(rew,0),my_and(arg(rew,1),cf),arg(rew,2)); diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index b88e488b4..e71475e45 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -9,7 +9,7 @@ Translate a Z3 proof into the interpolating proof calculus. Translation is direct, without transformations on the target proof - representaiton. + representation. Author: diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 762e8ceb2..ceec60622 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -634,7 +634,7 @@ namespace simplex { // // max { c*x | A*x = 0 and l <= x <= u } // - // start with feasible assigment + // start with feasible assignment // A*x0 = 0 and l <= x0 <= u // // Identify pivot: i, j: such that x_i is base, diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 9aedf141a..6ac33ae91 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -60,7 +60,7 @@ namespace datalog { ACK_UNBOUND_VAR(var_index) - encodes that the column contains a variable that is unbound (by the corresponding rule body), - var_index is the de-Brujin index (var->get_idx()) + var_index is the de-Bruijn index (var->get_idx()) of the variable associated with the column. ACK_CONSTANT(constant) - encodes that the column contains the constant. diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index c77127eb7..610c523e1 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -609,7 +609,7 @@ namespace datalog { std::string to_nice_string(const relation_element & el) const; /** This one may give a nicer representation of \c el than the - \c to_nice_string(const relation_element & el) function, by unsing the information about the sort + \c to_nice_string(const relation_element & el) function, by using the information about the sort of the element. */ std::string to_nice_string(const relation_sort & s, const relation_element & el) const; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 448aa624d..12b063759 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -89,7 +89,7 @@ namespace nlsat { unsigned m_num_bool_vars; atom_vector m_atoms; // bool_var -> atom - svector m_bvalues; // boolean assigment + svector m_bvalues; // boolean assignment unsigned_vector m_levels; // bool_var -> level svector m_justifications; vector m_bwatches; // bool_var (that are not attached to atoms) -> clauses where it is maximal @@ -1051,7 +1051,7 @@ namespace nlsat { } /** - \brief Process a clause that contains nonlinar arithmetic literals + \brief Process a clause that contains nonlinear arithmetic literals If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0 */ @@ -1569,7 +1569,7 @@ namespace nlsat { max = lvl; } else { - // l must be a literal from a previous stage that is false in the current intepretation + // l must be a literal from a previous stage that is false in the current interpretation SASSERT(assigned_value(l) == l_undef); SASSERT(max_var(b) != null_var); SASSERT(m_xk != null_var); @@ -1890,7 +1890,7 @@ namespace nlsat { // ----------------------- // - // Variable reodering + // Variable reordering // // ----------------------- diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 01806bc24..3975945cb 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -974,7 +974,7 @@ namespace ar { // ------------------------------------------------------------ -// fm_tactic adapted to eliminate designated de-Brujin indices. +// fm_tactic adapted to eliminate designated de-Bruijn indices. namespace fm { typedef ptr_vector clauses; diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 96334e3ce..c979e476e 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -188,7 +188,7 @@ namespace smt { 1) Variables: (f ... X ...) 2) Ground terms: (f ... t ...) 3) depth 2 joint: (f ... (g ... X ...) ...) - Joint2 stores the declartion g, and the position of variable X, and its idx. + Joint2 stores the declaration g, and the position of variable X, and its idx. \remark Z3 has no support for depth 3 joints (f ... (g ... (h ... X ...) ...) ....) */ @@ -211,7 +211,7 @@ namespace smt { approx_set m_lbl_set; // singleton set containing m_label /* The following field is an array of tagged pointers. - Each positon contains: + Each position contains: 1- null (no joint), NULL_TAG 2- a boxed integer (i.e., register that contains the variable bind) VAR_TAG 3- an enode pointer (ground term) GROUND_TERM_TAG diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index ffaee434f..c38ef4e4a 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -369,7 +369,7 @@ namespace smt { else { TRACE("internalize_bug", tout << "creating enode for #" << n->get_id() << "\n";); mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true, /* bool enode must be merged with true/false, since it is not in the context of a gate */ false /* CC is not enabled */ ); set_enode_flag(v, false); @@ -453,7 +453,7 @@ namespace smt { // must be associated with an enode. if (!e_internalized(n)) { mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true /* bool enode must be merged with true/false, since it is not in the context of a gate */, false /* CC is not enabled */); } @@ -739,7 +739,7 @@ namespace smt { app_ref eq1(mk_eq_atom(n, t), m_manager); app_ref eq2(mk_eq_atom(n, e), m_manager); mk_enode(n, - true /* supress arguments, I don't want to apply CC on ite terms */, + true /* suppress arguments, I don't want to apply CC on ite terms */, false /* it is a term, so it should not be merged with true/false */, false /* CC is not enabled */); internalize(c, true); @@ -797,7 +797,7 @@ namespace smt { } enode * e = mk_enode(n, - false, /* do not supress args */ + false, /* do not suppress args */ false, /* it is a term, so it should not be merged with true/false */ true); apply_sort_cnstr(n, e); @@ -1506,7 +1506,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_and_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to false, the the and-parent must be notified + // if one child is assigned to false, the and-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(~l, eh); } @@ -1518,7 +1518,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_or_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to true, the the or-parent must be notified + // if one child is assigned to true, the or-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(l, eh); } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 28a65f898..f443d671b 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -537,7 +537,7 @@ namespace smt { } } - // For each instantiation_set, reemove entries that do not evaluate to values. + // For each instantiation_set, remove entries that do not evaluate to values. void cleanup_instantiation_sets() { ptr_vector to_delete; for (node * curr : m_nodes) { @@ -735,7 +735,7 @@ namespace smt { } } // TBD: add support for the else of bitvectors. - // Idea: get the term t with the minimal interpreation and use t - 1. + // Idea: get the term t with the minimal interpretation and use t - 1. } n->set_else((*(elems.begin())).m_key); } @@ -955,7 +955,7 @@ namespace smt { if (elems.empty()) { // The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts // (e.g., (Array S S) where S is uninterpreted). The problem is that these sorts do not have a fixed interpretation. - // Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value. + // Moreover, a model assigns an arbitrary interpretation to these sorts using "model_values" a model value. // If these module values "leak" inside the logical context, they may affect satisfiability. // sort * ns = n->get_sort(); @@ -1007,7 +1007,7 @@ namespace smt { This may happen because the evaluator uses model_completion. In the beginning of fix_model() we collected all f with partial interpretations. During the process of computing the - projections we used the evalutator with model_completion, + projections we used the evaluator with model_completion, and it may have fixed the "else" case of some partial interpretations. This is ok, because in the "limit" the "else" of the interpretation is irrelevant after the projections are applied. @@ -1570,7 +1570,7 @@ namespace smt { ast_manager & m = ctx->get_manager(); sort * s = q->get_decl_sort(num_vars - m_var_i - 1); if (m.is_uninterp(s)) { - // For uninterpreted sorst, we add all terms in the context. + // For uninterpreted sorts, we add all terms in the context. // See Section 4.1 in the paper "Complete Quantifier Instantiation" node * S_q_i = slv.get_uvar(q, m_var_i); ptr_vector::const_iterator it = ctx->begin_enodes(); @@ -1741,7 +1741,7 @@ namespace smt { if (has_quantifiers(q->get_expr())) { static bool displayed_flat_msg = false; if (!displayed_flat_msg) { - // [Leo]: This warning message is not usefult. + // [Leo]: This warning message is not useful. // warning_msg("For problems containing quantifiers, the model finding capabilities of Z3 work better when the formula does not contain nested quantifiers. You can use PULL_NESTED_QUANTIFIERS=true to eliminate nested quantifiers."); displayed_flat_msg = true; } @@ -2104,7 +2104,7 @@ namespace smt { } /** - \brief Process unintrepreted applications. + \brief Process uninterpreted applications. */ void process_u_app(app * t) { unsigned num_args = t->get_num_args(); @@ -2130,7 +2130,7 @@ namespace smt { /** \brief A term \c t is said to be a auf_select if - it is of ther form + it is of the form (select a i) Where: @@ -2151,7 +2151,7 @@ namespace smt { } /** - \brief Process intrepreted applications. + \brief Process interpreted applications. */ void process_i_app(app * t) { if (is_auf_select(t)) { @@ -2512,7 +2512,7 @@ namespace smt { SASSERT(f_else != 0); // Remark: I can ignore the conditions of m because // I know the (partial) interpretation of f satisfied the ground part. - // MBQI will force extra instantiations if the the (partial) interpretation of f + // MBQI will force extra instantiations if the (partial) interpretation of f // does not satisfy the quantifier. // In all other cases the "else" of f will satisfy the quantifier. set_else_interp(f, f_else); @@ -2937,7 +2937,7 @@ namespace smt { } /** - \brief Use m_fs to set the interpreation of the function symbols that were used to satisfy the + \brief Use m_fs to set the interpretation of the function symbols that were used to satisfy the quantifiers in m_satisfied. */ void set_interp() { diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index d89f3f6a4..ad5f58e49 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -152,7 +152,7 @@ namespace smt { virtual bool mbqi_enabled(quantifier *q) const {return true;} /** - \brief Give a change to the plugin to adjust the interpretation of unintepreted functions. + \brief Give a change to the plugin to adjust the interpretation of uninterpreted functions. It can basically change the "else" of each uninterpreted function. */ virtual void adjust_model(proto_model * m) = 0; diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 806b2a05b..6794ca3ac 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -660,7 +660,7 @@ namespace smt { satisfy their respective constraints. However, when they do that the may create inconsistencies in the other modules. I use m_liberal_final_check to avoid infinite - loops where the modules keep changing the assigment and no + loops where the modules keep changing the assignment and no progress is made. If m_liberal_final_check is set to false, these modules will avoid mutating the assignment to satisfy constraints. diff --git a/src/tactic/arith/purify_arith_tactic.h b/src/tactic/arith/purify_arith_tactic.h index bbb62710c..44b4f9b58 100644 --- a/src/tactic/arith/purify_arith_tactic.h +++ b/src/tactic/arith/purify_arith_tactic.h @@ -16,7 +16,7 @@ Abstract: Remarks: - The semantics of division by zero is not specified. Thus, uninterpreted functions are used. An ExRCF procedure may - treat the unintepreted function applications as fresh + treat the uninterpreted function applications as fresh constants. Then, in any model produced by this procedure, the interpretation for division by zero must be checked. diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/tactic/ufbv/ufbv_rewriter.h index 1e13f4fa4..af9888751 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/tactic/ufbv/ufbv_rewriter.h @@ -74,7 +74,7 @@ each offset is a different "variable bank". A pair (expr, offset) is essentially where every variable in expr is assumed to be from the "bank" offset. The class substitution (in substitution.h) manages offsets for us. -The class matcher (in matcher.h) can be use to test whether an expression is an instance of another one. +The class matcher (in matcher.h) can be used to test whether an expression is an instance of another one. Finally, there is the problem when we have N demodulators (where N is big), and a big formula, and we want to traverse the formula only once looking for opportunities for applying these N demodulators. From a3ad0aff8b6750c25e730c3e6493736545fd841c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 22:50:50 +0700 Subject: [PATCH 62/72] print_stat_f: Remove implicit conversion of float to double. --- src/util/stats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/stats.h b/src/util/stats.h index 0acc18f43..680f9c9df 100644 --- a/src/util/stats.h +++ b/src/util/stats.h @@ -29,7 +29,7 @@ inline void print_stat(std::ostream& out, char const* msg, unsigned num) { } inline void print_stat_f(std::ostream& out, char const* msg, float num) { - if (num > 0.0) { + if (num > 0.0f) { out << msg << num << "\n"; } } From a875d3e491052bccb62ac490cbb554a97be4c129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 07:54:31 -0800 Subject: [PATCH 63/72] fix #1429 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index ce305bb4e..120b0ddfd 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1994,7 +1994,7 @@ struct if csn <> cs || cdn <> cd then raise (Error "Argument size mismatch") else - Z3native.parse_smtlib2_string ctx file_name + Z3native.parse_smtlib2_file ctx file_name cs sort_names sorts cd decl_names decls end From a5a31fc23cd74463749da2911a71d60edcddcb19 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:11:36 +0700 Subject: [PATCH 64/72] Fix code formatting: Incorrect indentation. --- src/util/container_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/container_util.h b/src/util/container_util.h index e114c87b9..e68ab7199 100644 --- a/src/util/container_util.h +++ b/src/util/container_util.h @@ -29,7 +29,7 @@ Revision History: // ----------------------------------- template - void set_intersection(Set1 & tgt, const Set2 & src) { +void set_intersection(Set1 & tgt, const Set2 & src) { svector to_remove; for (auto const& itm : tgt) if (!src.contains(itm)) From 11db7784425516f77d1a378cea2a3c5bb5589a63 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:12:28 +0700 Subject: [PATCH 65/72] Remove ignored const qualifiers. The `const` qualifier on a scalar value is ignored in return types. --- src/util/lp/numeric_pair.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h index 4ebe63613..a8a743a71 100644 --- a/src/util/lp/numeric_pair.h +++ b/src/util/lp/numeric_pair.h @@ -38,10 +38,10 @@ template class numeric_traits {}; template <> class numeric_traits { public: static bool precise() { return true; } - static unsigned const zero() { return 0; } - static unsigned const one() { return 1; } + static unsigned zero() { return 0; } + static unsigned one() { return 1; } static bool is_zero(unsigned v) { return v == 0; } - static double const get_double(unsigned const & d) { return d; } + static double get_double(unsigned const & d) { return d; } }; template <> class numeric_traits { @@ -66,7 +66,7 @@ template <> class numeric_traits { static rational const & zero() { return rational::zero(); } static rational const & one() { return rational::one(); } static bool is_zero(const rational & v) { return v.is_zero(); } - static double const get_double(const rational & d) { return d.get_double();} + static double get_double(const rational & d) { return d.get_double();} static rational log(rational const& r) { UNREACHABLE(); return r; } static rational from_string(std::string const & str) { return rational(str.c_str()); } static bool is_pos(const rational & d) {return d.is_pos();} From 5a0f5a778fd6cdc383dd3594034b456b5911fb99 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:14:29 +0700 Subject: [PATCH 66/72] Remove unnecessary copy of coeff in iteration. --- src/smt/theory_lra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 292d2ab0d..21b66d3a0 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1916,7 +1916,7 @@ namespace smt { lp::var_index vi = m_theory_var2var_index[v]; SASSERT(m_solver->is_term(vi)); lp::lar_term const& term = m_solver->get_term(vi); - for (auto const coeff : term.m_coeffs) { + for (auto const& coeff : term.m_coeffs) { lp::var_index wi = coeff.first; lp::constraint_index ci; rational value; From b06f4135852cce8649fa1da92a9a53a8c7994782 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:20:00 +0700 Subject: [PATCH 67/72] raise_exception: Annotate that this doesn't return. --- src/ast/ast.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 24e2b93b6..ea97af004 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,6 +53,12 @@ Revision History: #pragma warning(disable : 4355) #endif +#ifdef __GNUC__ +# define Z3_NORETURN __attribute__((noreturn)) +#else +# define Z3_NORETURN +#endif + class ast; class ast_manager; @@ -1515,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg); + void raise_exception(char const * msg) Z3_NORETURN; bool is_format_manager() const { return m_format_manager == 0; } From 7457fa77cb44f9cfdfb4fc552581e10c41ee69b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 08:46:17 -0800 Subject: [PATCH 68/72] add noreturn attribute #1435 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 41 ++++++++++++++--------------------------- src/ast/ast.h | 8 +------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 3824325b3..0f18170df 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1492,11 +1492,8 @@ void ast_manager::compact_memory() { unsigned capacity = m_ast_table.capacity(); if (capacity > 4*m_ast_table.size()) { ast_table new_ast_table; - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - new_ast_table.insert(*it); - } + for (ast* curr : m_ast_table) + new_ast_table.insert(curr); m_ast_table.swap(new_ast_table); IF_VERBOSE(10, verbose_stream() << "(ast-table :prev-capacity " << capacity << " :capacity " << m_ast_table.capacity() << " :size " << m_ast_table.size() << ")\n";); @@ -1510,10 +1507,7 @@ void ast_manager::compress_ids() { ptr_vector asts; m_expr_id_gen.cleanup(); m_decl_id_gen.cleanup(c_first_decl_id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * n = *it; + for (ast * n : m_ast_table) { if (is_decl(n)) n->m_id = m_decl_id_gen.mk(); else @@ -1521,13 +1515,11 @@ void ast_manager::compress_ids() { asts.push_back(n); } m_ast_table.finalize(); - ptr_vector::iterator it2 = asts.begin(); - ptr_vector::iterator end2 = asts.end(); - for (; it2 != end2; ++it2) - m_ast_table.insert(*it2); + for (ast* a : asts) + m_ast_table.insert(a); } -void ast_manager::raise_exception(char const * msg) { +[[noreturn]] void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } @@ -1570,20 +1562,15 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { } void ast_manager::set_next_expr_id(unsigned id) { - while (true) { - id = m_expr_id_gen.set_next_id(id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * curr = *it; - if (curr->get_id() == id) - break; + try_again: + id = m_expr_id_gen.set_next_id(id); + for (ast * curr : m_ast_table) { + if (curr->get_id() == id) { + // id is in use, move to the next one. + ++id; + goto try_again; } - if (it == end) - return; - // id is in use, move to the next one. - id++; - } + } } unsigned ast_manager::get_node_size(ast const * n) { return ::get_node_size(n); } diff --git a/src/ast/ast.h b/src/ast/ast.h index ea97af004..482ec3a99 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,12 +53,6 @@ Revision History: #pragma warning(disable : 4355) #endif -#ifdef __GNUC__ -# define Z3_NORETURN __attribute__((noreturn)) -#else -# define Z3_NORETURN -#endif - class ast; class ast_manager; @@ -1521,7 +1515,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg) Z3_NORETURN; + [[noreturn]] void raise_exception(char const * msg); bool is_format_manager() const { return m_format_manager == 0; } From 16044c74bfcd64384065fa38b514882a52a013c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 09:29:14 -0800 Subject: [PATCH 69/72] revert use of [[noreturn]]. It's not fully supported on compilers #1435 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 2 +- src/ast/ast.h | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 0f18170df..cc4beb1b6 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1519,7 +1519,7 @@ void ast_manager::compress_ids() { m_ast_table.insert(a); } -[[noreturn]] void ast_manager::raise_exception(char const * msg) { +void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } diff --git a/src/ast/ast.h b/src/ast/ast.h index 482ec3a99..ea97af004 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,6 +53,12 @@ Revision History: #pragma warning(disable : 4355) #endif +#ifdef __GNUC__ +# define Z3_NORETURN __attribute__((noreturn)) +#else +# define Z3_NORETURN +#endif + class ast; class ast_manager; @@ -1515,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - [[noreturn]] void raise_exception(char const * msg); + void raise_exception(char const * msg) Z3_NORETURN; bool is_format_manager() const { return m_format_manager == 0; } From 11f5fdccdf1f3e7b72a052be73203760d75472b4 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 3 Jan 2018 01:02:07 +0700 Subject: [PATCH 70/72] Use noreturn attribute and __declspec version. --- src/ast/ast.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index ea97af004..7a662a193 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,10 +53,10 @@ Revision History: #pragma warning(disable : 4355) #endif -#ifdef __GNUC__ -# define Z3_NORETURN __attribute__((noreturn)) +#ifdef _MSC_VER +# define Z3_NORETURN __declspec(noreturn) #else -# define Z3_NORETURN +# define Z3_NORETURN [[noreturn]] #endif class ast; @@ -1521,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg) Z3_NORETURN; + Z3_NORETURN void raise_exception(char const * msg); bool is_format_manager() const { return m_format_manager == 0; } From e9be339d9df0d7d16d31e58aeb1ff81b9215a563 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Wed, 3 Jan 2018 12:42:43 +0000 Subject: [PATCH 71/72] [CMake] Fix #1437. The `clock_gettime()` function in glibc < 2.17 required linking against librt. Until #1437 nobody had tried using the CMake build system with a really old version of glibc (in this case 2.12). The python build system always linked against librt but the CMake build system never tried to link against it leading to link failures. This patch teaches the CMake build system to detect if librt is required when linking against `clock_gettime()` and adds `rt` as a link dependency if necessary. --- CMakeLists.txt | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0be2de537..69a0ca123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,6 +257,46 @@ list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/src" "${CMAKE_SOURCE_DIR}/src" ) + +################################################################################ +# Linux specific configuration +################################################################################ +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + # Try to detect if it is necessary to link against librt. + # Note that glibc < 2.17 required librt to be linked to use clock_gettime() + # and friends. + set(CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE + " + #include + int main() { + timespec res; + int result = clock_gettime(CLOCK_REALTIME, &res); + return result == 0; + } + " + ) + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_NO_REQUIRE_LIBRT + ) + if (NOT CLOCK_GETTIME_NO_REQUIRE_LIBRT) + # Try again with librt + message(STATUS "Failed to link against clock_gettime(), trying with librt") + set(CMAKE_REQUIRED_LIBRARIES_OLD "${CMAKE_REQUIRED_LIBRARIES}") + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} rt") + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_REQUIRES_LIBRT + ) + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_OLD}") + if (CLOCK_GETTIME_REQUIRES_LIBRT) + list(APPEND Z3_DEPENDENT_LIBS "rt") + else() + message(FATAL_ERROR "Failed to link against clock_gettime()") + endif() + endif() +endif() + ################################################################################ # GNU multiple precision library support ################################################################################ From a5180edc760a49ce05ddef98e69af510fc19f6b5 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 3 Jan 2018 16:05:34 -0500 Subject: [PATCH 72/72] make linear search the default for theory_str --- src/smt/params/smt_params_helper.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 937aa6a2b..d6ca8c9b2 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -74,7 +74,7 @@ def_module_params(module_name='smt', ('str.fast_length_tester_cache', BOOL, False, 'cache length tester constants instead of regenerating them'), ('str.fast_value_tester_cache', BOOL, True, 'cache value tester constants instead of regenerating them'), ('str.string_constant_cache', BOOL, True, 'cache all generated string constants generated from anywhere in theory_str'), - ('str.use_binary_search', BOOL, True, 'use a binary search heuristic for finding concrete length values for free variables in theory_str (set to False to use linear search)'), + ('str.use_binary_search', BOOL, False, 'use a binary search heuristic for finding concrete length values for free variables in theory_str (set to False to use linear search)'), ('str.binary_search_start', UINT, 64, 'initial upper bound for theory_str binary search'), ('theory_aware_branching', BOOL, False, 'Allow the context to use extra information from theory solvers regarding literal branching prioritization.'), ('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'),